Audio3D

صفحه به روز شده :
تاریخ ایجاد صفحه :

یادداشت ها در این نکات

این نمونه بر اساس برنامه های منتشر شده در سایت های زیر است. من کد را کمی تغییر می دهم تا درک و توضیح آن به زبان ژاپنی آسان تر شود. اساسا، ما با استفاده از کد اصلی به عنوان است، بنابراین اگر شما در واقع آن را در برنامه بازی خود را اتخاذ، آن را به موقع اصلاح و استفاده از آن.

سایت مرجع

علاوه بر این ، آن را در فرض توضیح داده شده است که شما برخی از دانش اولیه در مورد MonoGame و XNA. مشاهده نکات MonoGame و نکات XNA برای رودی.

به طور خاص، به عنوان ریاضیات، بردارها، توابع مثلثاتی، ماتریس ها و غیره ضروری هستند، بنابراین لطفا بدانید که آنها تا حدودی چه هستند.

محیط

بستر
  • ویندوز 10
  • کد را می توان در سیستم عامل های دیگر MonoGame فعال استفاده می شود
ویژوال استودیو
  • ویژوال استودیو ۲۰۱۹
.NET Core
  • 3.1
تک بازی
  • 3.8

درباره نمونه ها

بر اساس موقعیت دوربین می توانید تماس را از موقعیت سگ و موقعیت گربه بشنوید. گربه مبدأ را دایره و دایره می کند و بازیکن می تواند موقعیت دوربین را با کلید کنترل کند. اطمینان حاصل کنید که نحوه شنیدن تغییرات صدا با هر تغییر در موقعیت دوربین یا موقعیت گربه. من فکر می کنم که آن را آسان به درک با استفاده از گوشی. من در کانال 5.1 تایید نشده است.

چگونه به کار

چه
برای انجام گیم پد صفحه کلید (XInput) ماوس لمسی
دوربین رو به جلو و عقب ↑↓ چوب چپ (بالا و پایین) - -
تغییر جهت گیری دوربین ←→ چوب چپ (چپ و راست) - -
پایان بازی Esc بازگشت - -

چه چیزی را آماده سازیم

  • سگ فایل صوتی squeal
  • سه گربه squeal فایل های صوتی
  • سگ فایل تصویر
  • پرونده عکس گربه
  • پرونده تصویر زمینی

نمونه اصلی در سایت رسمی از محتوای از پیش ساخته شده .xnb فایل ها استفاده می کند. اگر می خواهید نمونه ها را در سایت رسمی نگه دارید، از mgcbs استفاده نکنید، آنها را مستقیماً به راه حل ویژوال استودیویی خود اضافه کنید و در زمان ساخت کپی کنید.

من نمی دانم چرا نمونه اصلی در حال گرفتن این روش است، اما من فکر می کنم احتمالا به این دلیل است که ما در حال مهاجرت نسخه های قدیمی تر از پروژه به عنوان است. البته شما می توانید از mgcb برای تولید همان فایل استفاده کنید. پروژه هایی که در این سایت قابل دانلود هستند به نسخه MGCB اصلاح شده اند.

برنامه

دانلود برنامه برای همه کد.

این نمونه طراحی شده است تا کد نگاه کمی عمومی تر در حالی که ساخت پخش صدا نگاه خوب در زمان اجرا. با استفاده از Audio3D تنها کد بسیار کمتری خواهد بود، اما آن را در امتداد نمونه اصلی توصیف شده است. من قسمت هاي مهم تر رو نگه مي دارم

پروژه شامل فایل های کد زیر است:

  • Audio3DGame
  • AudioManager
  • گربه
  • سگ
  • ای اودیومیتر
  • برنامه
  • QuadDrawer
  • SpriteEntity

کلاس QuadDrawer

این کلاس یک کلاس یاب برای کشیدن چندضضح مستطیلی است. چند ضلعی های مستطیلی اغلب در درجه اول برای نمایش اسپریت های سه بعد (بیلبوردها) استفاده می شوند. این نکته برای بیلبوردها برای گربه ها و سگ ها و همچنین برای نمایش های مستطیل شکل زمین استفاده می شود.

این کلاس ربطی به Audio3D ندارد.

زمینه

readonly GraphicsDevice _graphicsDevice;
readonly AlphaTestEffect _effect;
readonly VertexPositionTexture[] _vertices;

حداقل اطلاعات مورد نیاز برای رسم چند ضلعی. رسم چند ضلعی از داده های راس بدون تهیه داده های مدل.

سازنده

/// <summary>
/// 新しい四辺形の描画ワーカーを作成します。
/// </summary>
public QuadDrawer(GraphicsDevice device)
{
  _graphicsDevice = device;

  _effect = new AlphaTestEffect(device);

  _effect.AlphaFunction = CompareFunction.Greater;
  _effect.ReferenceAlpha = 128;

  // 4つの頂点の配列を事前に割り当てます。
  _vertices = new VertexPositionTexture[4];

  _vertices[0].Position = new Vector3(1, 1, 0);
  _vertices[1].Position = new Vector3(-1, 1, 0);
  _vertices[2].Position = new Vector3(1, -1, 0);
  _vertices[3].Position = new Vector3(-1, -1, 0);
}

از آنجا که این کلاس در سطح جهانی قابل استفاده است، شما یک GraphicsDevice نمونه ایجاد شده در فرایند اولیه سازی کلاس بازی دریافت می کنید.

در اینجا اثر لازم برای رسم اسپریت و موقعیت ۴ یال مورد نیاز برای چند ضلعی مستطیلی را تعیین می کنیم. اندازه باید در هنگام نقاشی مقیاس بندی شود، بنابراین -۱ تا ۱ است.

روش DrawQuad

/// <summary>
/// 3Dワールドの一部として四角形を描画します。
/// </summary>
public void DrawQuad(Texture2D texture, float textureRepeats, Matrix world, Matrix view, Matrix projection)
{
  // 指定されたテクスチャとカメラマトリックスを使用するようにエフェクトを設定します。
  _effect.Texture = texture;

  _effect.World = world;
  _effect.View = view;
  _effect.Projection = projection;

  // 指定された数のテクスチャの繰り返しを使用するように頂点配列を更新します。
  _vertices[0].TextureCoordinate = new Vector2(0, 0);
  _vertices[1].TextureCoordinate = new Vector2(textureRepeats, 0);
  _vertices[2].TextureCoordinate = new Vector2(0, textureRepeats);
  _vertices[3].TextureCoordinate = new Vector2(textureRepeats, textureRepeats);

  // 矩形を描画します。
  _effect.CurrentTechnique.Passes[0].Apply();

  _graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
}

بافت عبوری را به مستطیل تنظیم می کند و آن را ترسیم می کند. از آنجا که این یک فرایند اساسی است، چیزی برای توجه وجود دارد.

اگر یک نقطه وجود داشته باشد textureRepeats ، متغیری به نام می تواند در آر استدلال مشخص شود، به طوری که مختصات بافت قابل تغییر باشد. اگر vertexPositionTexture.TextureCoordinate فراتر از محدوده ۰ تا ۱ تنظیم شود، بافت بارها به صورت پیش فرض کشیده می شود. با استفاده از آن می توان بیان کرد که کاشی ها را می توان بارها مرتب کرد. در واقع، الگوهای جستجوگر بر روی زمین به نظر می رسد چند تصویر ساده سیاه و سفید صف.

رابط IAudioEmitter

/// <summary>
/// 3D サウンドを再生するエンティティの位置と速度を検索するために AudioManager が使用するインターフェイス。
/// </summary>
public interface IAudioEmitter
{
  Vector3 Position { get; }
  Vector3 Forward { get; }
  Vector3 Up { get; }
  Vector3 Velocity { get; }
}

تعریف شده به عنوان یک نهاد است که ساطع صدا. از آنجا که نهادهایی که این بار صدا ساطع می کنند سگ و گربه هستند، در کلاس های مربوطه خود به ارث می برند. Emitter به اطلاعات زیر نیاز دارد:

استفاده
از ملک
موقعیت موقعیت نهاد
جلو جهتی که نهاد رو به رو است (بردار)
تا بالاي نهاد . جهتی که سر در یک فرد وجود دارد
سرعت سرعت حرکت نهاد. برای محاسبه مقادیر دوپلر استفاده می شود.

کلاس SpriteEntity

کلاسی برای نمایندگی اسپریت های سه بعد (بیلبوردها). آن را نیز یک emitter، و به ارث می برد IAudioEmitter . سگ ها و گربه ها این کلاس را به ارث می برند.

اموال

/// <summary>エンティティの3D位置を取得または設定します。</summary>
public Vector3 Position { get; set; }

/// <summary>エンティティが向いている方向を取得または設定します。</summary>
public Vector3 Forward { get; set; }

/// <summary>このエンティティの上方向を取得または設定します。</summary>
public Vector3 Up { get; set; }

/// <summary>このエンティティの移動速度を取得または設定します。</summary>
public Vector3 Velocity { get; protected set; }

/// <summary>このエンティティの表示に使用されるテクスチャを取得または設定します。</summary>
public Texture2D Texture { get; set; }

اطلاعات مکان نهاد و غیره را دارد. اساسا ً من اطلاعاتي به عنوان يه منتشر کننده دارم. همچنین یک نهاد نقاشی است، بنابراین یک تصویر (بافت) برای نمایش نیز دارد.

روش به روز رسانی

/// <summary>
/// エンティティの位置を更新し、サウンドを再生できるようにします。
/// </summary>
public abstract void Update(GameTime gameTime, AudioManager audioManager);

موقعیت نهاد و فرایند نواختن صدا را توصیف می کند، اما آن را در کلاس مشتق شده پیاده سازی می کند.

روش رسم

/// <summary>
/// エンティティをビルボードスプライトとして描画します。
/// </summary>
public void Draw(QuadDrawer quadDrawer, Vector3 cameraPosition, Matrix view, Matrix projection)
{
  Matrix world = Matrix.CreateTranslation(0, 1, 0) *
                 Matrix.CreateScale(800) *
                 Matrix.CreateConstrainedBillboard(Position, cameraPosition, Up, null, null);

  quadDrawer.DrawQuad(Texture, 1, world, view, projection);
}

سگ ها و گربه ها تصاویر و موقعیت های متفاوتی دارند، اما مکانیسم نقاشی دیگر دقیقا ً یکسان است، بنابراین من آنها را در اینجا توصیف می کنم.

هر تبدیل و بافت به QuadDrawer منتقل می شود تا یک چند ضلعی مستطیل شکل را نمایش دهد. از آنجا که تحول مختصات دانش پایه است، توضیحات پوشش داده نمی شوند.

Matrix.CreateConstrainedBillboard استفاده از روش و اطلاعات دوربین به راحتی نشان دهنده بیلبورد، بنابراین استفاده موثر از آنها.

کلاس سگ

این کلاس است که نقاشی سگ و آواز پخش است. SpriteEntity به ارث بردن کلاس . سگ در فضای سه بعد در موقعیت ثابتی باقی می ماند.

زمینه

/// <summary>サウンドを開始または停止するまでの時間。</summary>
TimeSpan _timeDelay = TimeSpan.Zero;

/// <summary>現在再生中のサウンド(ある場合)。</summary>
SoundEffectInstance _activeSound = null;

_timeDelay در فواصل زمانی برای بازی گریه استفاده می شود.

SoundEffectInstance _activeSound یک نمونه برای پخش صدا است. SoundEffectInstance همانطور که شما اغلب در کلاس پخش صدا را ببینید، شما می توانید این را به عنوان در صدای سه بعد استفاده کنید. به هر حال ، _activeSound من فقط یک مرجع از کلاس AudioManager بعد دریافت خواهید کرد ، بنابراین من آن را در سمت کلاس نقطه دور انداختن نیست.

روش به روز رسانی

/// <summary>
/// 犬の位置を更新し、音を鳴らします。
/// </summary>
public override void Update(GameTime gameTime, AudioManager audioManager)
{
  // エンティティを固定位置に設定します。
  Position = new Vector3(0, 0, -4000);
  Forward = Vector3.Forward;
  Up = Vector3.Up;
  Velocity = Vector3.Zero;

  // 時間遅延がなくなった場合は、ループ音を開始または停止します。 これは通常は永久に続きますが、6秒の遅延後に停止し、さらに4秒後に再起動します。
  _timeDelay -= gameTime.ElapsedGameTime;

  if (_timeDelay < TimeSpan.Zero)
  {
    if (_activeSound == null)
    {
      // 現在再生中のサウンドがない場合は、トリガーします。
      _activeSound = audioManager.Play3DSound("DogSound", true, this);

      _timeDelay += TimeSpan.FromSeconds(6);
    }
    else
    {
      // それ以外の場合は、現在のサウンドを停止します。
      _activeSound.Stop(false);
      _activeSound = null;

      _timeDelay += TimeSpan.FromSeconds(4);
    }
  }
}

در این نمونه، سگ برای مدت طولانی در همان موقعیت باقی می ماند، بنابراین چهار پارامتر اول با یک اعتصاب قاطع مشخص می شوند. رسم در کلاس پایه انجام می شود.

_timeDelay آن به عنوان زمان باقی مانده برای متوقف کردن استفاده می شود، بازی گریه.

AudioManager خواهد شد در فضایPlay3DSound 3D با عبور از نام گریه ، اطلاعات حلقه ، و اطلاعات خود را به عنوان یک emitter به تکثیر.

کلاس سگ طراحی شده است برای حلقه فریاد، بنابراین شما لازم نیست که بیش از حد عمیق فکر می کنم چرا که آن را فقط یک تنظیم، مانند بازی و یا متوقف کردن شاخه.

کلاس گربه

کلاسی است که نقاشی گربه و پخش آواز را انجام می دهد. SpriteEntity به ارث بردن کلاس . گربه در حال حرکت در اطراف مبدا است.

زمینه

/// <summary>次の音を鳴らすまでの時間。</summary>
TimeSpan _timeDelay = TimeSpan.Zero;

/// <summary>サウンドバリエーションから選択するための乱数ジェネレータ。</summary>
static readonly Random _random = new Random();

_timeDelay است که در همان راه به عنوان کلاس سگ استفاده می شود, با بقیه زمان قبل از squeal بعدی.

سه نوع تماس گربه وجود دارد که به طور تصادفی انتخاب و پخش می شوند، اما هیچ ربطی به Audio3D ندارد زیرا یک عنصر جایزه هستند.

روش به روز رسانی

/// <summary>
/// 猫の位置を更新し、音を鳴らします。
/// </summary>
public override void Update(GameTime gameTime, AudioManager audioManager)
{
  // 猫を大きな円で動かします。
  double time = gameTime.TotalGameTime.TotalSeconds;

  float dx = (float)-Math.Cos(time);
  float dz = (float)-Math.Sin(time);

  Vector3 newPosition = new Vector3(dx, 0, dz) * 6000;

  // エンティティの位置と速度を更新します。
  Velocity = newPosition - Position;
  Position = newPosition;
  if (Velocity == Vector3.Zero)
  {
    Forward = Vector3.Forward;
  }
  else
  {
    Forward = Vector3.Normalize(Velocity);
  }

  Up = Vector3.Up;

  // 時間遅延がなくなった場合は、別の単発音をトリガーします。
  _timeDelay -= gameTime.ElapsedGameTime;

  if (_timeDelay < TimeSpan.Zero)
  {
    // 異なる3つのサウンドバリエーション(CatSound0、CatSound1、CatSound2)からランダムに選択します。
    string soundName = "CatSound" + _random.Next(3);

    audioManager.Play3DSound(soundName, false, this);

    _timeDelay += TimeSpan.FromSeconds(1.25f);
  }
}

از آنجا که گربه در یک حرکت دایره ای به دور مبدأ می چرخد، آن را طوری پردازش می کند که مسیر دایره را با استفاده از یک تابع مثلثاتی حرکت می دهد. در نتیجه موقعیت ، جلو و سرعت یکی پس از دیگری تغییر کرده است. بنابراین وقتی برنامه را اجرا می کنید، می بینید که گریه گربه حتی اگر دوربین را جابه جا نيکنيد، دور هم می چرخد.

_timeDelay کد زیر فرایندی است که در آن گریه گربه به طور تصادفی اختصاص داده می شود و در فواصل منظم پخش می شود. audioManager.Play3DSound من خودم را به روشی که یک امیتر است می گذرانم. می بینید که موقعیت پخش صدا یک به یک تغییر می کند.

کلاس AudioManager

این است که در نهایت ماه از Audio3D. یک صدای سه بعد شامل شنونده و یک اهمیتر است. منتشر کننده در حال حاضر سگ ها و گربه ها را تعریف می کند، بنابراین کلاس AudioManager شنوندگان را تعریف می کند. معمولاً ساطع کننده های متعدد وجود دارند، در حالی که تنها یک شنونده وجود دارد.

این کلاس به ارث می برد وGame ثبت نام می کند GameComponent و از جزء در کلاس استفاده می کند.

کلاس ActiveSound

/// <summary>
/// アクティブな3Dサウンドを追跡し、アタッチされているエミッターオブジェクトを記憶するための内部ヘルパークラス。
/// </summary>
private class ActiveSound
{
  public SoundEffectInstance Instance;
  public IAudioEmitter Emitter;
}

در پایین کد تعریف می شود، اما کلاسی برای حفظ حالتی است که در حال نواختن است. این اطلاعات در مورد نمونه صدا در حال پخش و منتشر کننده در حال پخش است.

زمینه

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
static string[] _soundNames =
  {
    "CatSound0",
    "CatSound1",
    "CatSound2",
    "DogSound",
  };

/// <summary>音を聞くリスナーの情報です。これは通常カメラに一致するように設定されます。</summary>
public AudioListener Listener { get; } = new AudioListener();

/// <summary>AudioEmitter は、3Dサウンドを生成しているエンティティを表します。</summary>
readonly AudioEmitter _emitter = new AudioEmitter();

/// <summary>再生可能なすべての効果音を保存します。</summary>
readonly Dictionary<string, SoundEffect> _soundEffects = new Dictionary<string, SoundEffect>();

/// <summary>現在再生中のすべての3Dサウンドを追跡します。また、再生が終わったインスタンスの破棄にも使用します。</summary>
readonly List<ActiveSound> _activeSounds = new List<ActiveSound>();

_soundNames تعریف نام فایل صوتی (نام دارایی) به بار. از آنجا که یک برنامه نمونه است، برای بارگذاری فایل صوتی به صورت فله ای ابتدا تعریف می شود. داده های صوتی وارداتی در ذخیره _soundEffects شده است.

AudioListener Listener تعریف شنونده است. اطلاعات شنونده به این دلیل تعریف می شود که از public کلاس Game تنظیم شده است.

AudioEmitter _emitter تعریف از emitter در هنگام استفاده از 3D به پخش صدا است. در این نمونه، _emitter هنگام پخش یک صدا، مقدار هر شیء پخش کننده تنظیم می شود، بنابراین فرمی است که یکی را به عنوان نمونه به اشتراک می گذارید. البته شما می توانید برای هر شی AudioEmitter داشته باشد.

_activeSounds اطلاعاتی در مورد صدایی که در کلاسی که قبلا تعریف کرده بودی داشته ActiveSound باشد. از آنجا که اطلاعات منتشر کننده تغییر تمام وقت، آن استفاده می شود برای به روز رسانی اطلاعات محل، و غیره، و به دور انداختن نمونه های صوتی است که بازی به پایان رسید.

سازنده

public AudioManager(Game game) : base(game) { }

GameComponent از آنجا که کلاس را به ارث می برد، Game نمونه را دریافت می کند و آن را به کلاس پایه می رساند.

روش اولیه سازی

/// <summary>
/// オーディオマネージャを初期化します。
/// </summary>
public override void Initialize()
{
  // ゲームの世界のスケールと一致するように、3Dオーディオのスケールを設定します。
  // DistanceScale は、離れるにつれて音量が変化する音の量を制御します。
  // DopplerScale は、サウンドを通過するときにピッチが変化するサウンドの量を制御します。
  SoundEffect.DistanceScale = 2000;
  SoundEffect.DopplerScale = 0.1f;

  // すべての効果音をロードします。
  foreach (string soundName in _soundNames)
  {
    _soundEffects.Add(soundName, Game.Content.Load<SoundEffect>(soundName));
  }

  base.Initialize();
}

GameComponent چون کلاس را به ارث می برد، به طور خودکار در ابتداسازی نامیده می شود.

SoundEffect.DistanceScale و پارامترهای SoundEffect.DopplerScale اختصاص داده شده به static صدای سه بعد.

SoundEffect.DistanceScale تا صدا را حتی در فاصله بشنوند.

SoundEffect.DopplerScale تاثیر اثر دوپلر است. هر چه تعداد بیشتر باشد، اثر دوپلر بیشتر می شود.

_soundNames ذخیره نام دارایی تعریف شده در یک حلقه به بار _soundEffects .

روش دفع

/// <summary>
/// 効果音データをアンロードします。
/// GameComponent として登録すればゲーム終了時に自動的に呼ばれます。
/// </summary>
protected override void Dispose(bool disposing)
{
  try
  {
    if (disposing)
    {
      foreach (SoundEffect soundEffect in _soundEffects.Values)
      {
        soundEffect.Dispose();
      }

      _soundEffects.Clear();
    }
  }
  finally
  {
    base.Dispose(disposing);
  }
}

GameComponent به طور خودکار در پایان بازی نامیده می شود زیرا کلاس را به ارث می برد.

از بین بردن تمام دارایی های صوتی وارداتی.

روش به روز رسانی

/// <summary>
/// 3Dオーディオシステムの状態を更新します。
/// </summary>
public override void Update(GameTime gameTime)
{
  // 現在再生中のすべての3Dサウンドをループします。
  int index = 0;

  while (index < _activeSounds.Count)
  {
    ActiveSound activeSound = _activeSounds[index];

    if (activeSound.Instance.State == SoundState.Stopped)
    {
      // 音の再生が終了した場合は廃棄してください。
      activeSound.Instance.Dispose();

      // アクティブリストから削除します。
      _activeSounds.RemoveAt(index);
    }
    else
    {
      // サウンドがまだ再生されている場合は、3D設定を更新します。
      Apply3D(activeSound);

      index++;
    }
  }

  base.Update(gameTime);
}

GameComponent از آنجا که کلاس را به ارث می برد، به طور خودکار در فرایند به روز رسانی نامیده می شود.

صدای در حال حاضر پخش را Apply3D بررسی کنید و اگر در حال پخش است، با روش به روز رسانی محل صدا تماس بگیرید تا با پخش کننده مطابقت داشته باشد. اگر هر صدایی پخش را به پایان رسانده باشد، نمونه دور انداخته می شود.

روش Play3DSound

/// <summary>
/// 新しい3Dサウンドを設定し再生します。
/// </summary>
public SoundEffectInstance Play3DSound(string soundName, bool isLooped, IAudioEmitter emitter)
{
  ActiveSound activeSound = new ActiveSound();

  // インスタンスを生成し、インスタンス、エミッターを設定します。
  activeSound.Instance = _soundEffects[soundName].CreateInstance();
  activeSound.Instance.IsLooped = isLooped;

  activeSound.Emitter = emitter;

  // 3D 位置を設定します。
  Apply3D(activeSound);

  activeSound.Instance.Play();

  // このサウンドがアクティブであることを保存します。
  _activeSounds.Add(activeSound);

  return activeSound.Instance;
}

روند پخش صدای سه بعد از بیرون. این نام صدا را به بازی، چه به حلقه، و اطلاعات منتشر کننده است.

اگر می خواهید یک صدا پخش کنید، یک نمونه صوتی جدید از منبع صوتی ایجاد کنید که در _soundEffects. SoundEffectInstance همچنین می تواند یک حلقه داشته باشد یا نه، بنابراین اطلاعات حلقه را تنظیم کنید.

از آنجا که من ایجاد به عنوان ActiveSound یک حالت بازی، من تنظیم اطلاعات امیتر است که شی پخش صدا وجود دارد. اگر می خواهید اطلاعات مکان سه بعد را روی یک صدا اعمال کنید، ارزش مورد Emitter نیاز خود را دریافت خواهید کرد.

Apply3D روش در زیر شرح داده شده است، اما این فرایند به کار گرفتن اطلاعات سه بعد از انتشار به صدا است.

فرایند اساسی صدای سه بعد شروع پخش با مجموعه اطلاعات SoundEffectInstance.Play سه بعد است. بقیه این است که اطلاعات سه بعدی را به طور دوره ای به روز کنید تا زمانی که صدا پخش به پایان برسد.

روش Apply3D

/// <summary>
/// 3Dサウンドの位置と速度の設定を更新します。
/// </summary>
private void Apply3D(ActiveSound activeSound)
{
  _emitter.Position = activeSound.Emitter.Position;
  _emitter.Forward = activeSound.Emitter.Forward;
  _emitter.Up = activeSound.Emitter.Up;
  _emitter.Velocity = activeSound.Emitter.Velocity;

  activeSound.Instance.Apply3D(Listener, _emitter);
}

فرایند اعمال یک اثر سه بعد به یک نمونه صوتی مشخص شده با استفاده از شنوندگان و ساطع کننده ها.

ما هر بار ارزش را به _emitter نمونه مشترک تعیین می کنیم. اگر شما در SoundEffectInstance.Apply3D حال AudioEmitter حاضر یکی، به سادگی شنونده و emitter به روش منتقل می شود.

کلاس Audio3DGame

در نهایت بیایید به این نگاه کنیم که کلاس بازی در مورد چه چیزی است.

زمینه

readonly GraphicsDeviceManager _graphics;
readonly AudioManager _audioManager;
readonly SpriteEntity _cat;
readonly SpriteEntity _dog;

/// <summary>地面の描画に使用するテクスチャーです。</summary>
Texture2D _checkerTexture;

QuadDrawer _quadDrawer;

Vector3 _cameraPosition = new Vector3(0, 512, 0);
Vector3 _cameraForward = Vector3.Forward;
Vector3 _cameraUp = Vector3.Up;
Vector3 _cameraVelocity = Vector3.Zero;

KeyboardState _currentKeyboardState;
GamePadState _currentGamePadState;

AudioManager ثبت نام در GameComponents ، اما آن را به عنوان یک زمینه به دلیل آن دسترسی به آن به صورت جداگانه.

برخی دیگر سگ، نهادهای گربه، بافت هایی برای نقاشی زمین، چهارگوش، اطلاعات دوربین، و اطلاعات ورودی را تعریف می کنند.

سازنده

public Audio3DGame()
{
  Content.RootDirectory = "Content";

  _graphics = new GraphicsDeviceManager(this);

  _audioManager = new AudioManager(this);

  // AudioManager を Components に追加して自動的に Update メソッドが呼ばれるようにします。
  Components.Add(_audioManager);

  _cat = new Cat();
  _dog = new Dog();
}

AudioManager تولید و ثبت GameComponents نام با .

شما همچنین تولید کلاس گربه و سگ.

روش LoadContent

/// <summary>
/// グラフィックコンテンツをロードします。
/// </summary>
protected override void LoadContent()
{
  _cat.Texture = Content.Load<Texture2D>("CatTexture");
  _dog.Texture = Content.Load<Texture2D>("DogTexture");

  _checkerTexture = Content.Load<Texture2D>("checker");

  // 四角形ポリゴンを描画するためのクラス
  _quadDrawer = new QuadDrawer(_graphics.GraphicsDevice);
}

بار بافت های مورد نیاز برای هر نقاشی.

QuadDrawer در اینجا تولید GraphicsDevice می شود زیرا نیاز دارد.

روش به روز رسانی

/// <summary>
/// ゲームがロジックを実行できるようにします。
/// </summary>
protected override void Update(GameTime gameTime)
{
  HandleInput();

  UpdateCamera();

  // 新しいカメラの位置について AudioManager に伝えます。
  _audioManager.Listener.Position = _cameraPosition;
  _audioManager.Listener.Forward = _cameraForward;
  _audioManager.Listener.Up = _cameraUp;
  _audioManager.Listener.Velocity = _cameraVelocity;

  // ゲームエンティティに動き回って音を鳴らすように伝えます。
  _cat.Update(gameTime, _audioManager);
  _dog.Update(gameTime, _audioManager);

  base.Update(gameTime);
}

HandleInput روش ها و روش ها UpdateCamera فرایند بازیابی ورودی دستگاه و دست زدن به دوربین است که بعداً مورد بحث قرار خواهد گرفت.

از آنجا که موقعیت دوربین و موقعیت شنونده تقریبا همیشه یکسان است، شنونده پس از فرایند به روز رسانی دوربین به همان ارزش تنظیم شده است.

_cat به ترتیب با روش های _dog حرکت و به روز رسانی تماس بگیرید.

روش رسم

/// <summary>
/// ゲームが描画する必要があるときに呼び出されます。
/// </summary>
protected override void Draw(GameTime gameTime)
{
  var device = _graphics.GraphicsDevice;

  device.Clear(Color.CornflowerBlue);

  device.BlendState = BlendState.AlphaBlend;

  // カメラ行列を計算します。
  var view = Matrix.CreateLookAt(_cameraPosition, _cameraPosition + _cameraForward, _cameraUp);
  var projection = Matrix.CreatePerspectiveFieldOfView(1, device.Viewport.AspectRatio, 1, 100000);

  // チェッカーグラウンドポリゴンを描画します。
  var groundTransform = Matrix.CreateScale(20000) * Matrix.CreateRotationX(MathHelper.PiOver2);

  _quadDrawer.DrawQuad(_checkerTexture, 32, groundTransform, view, projection);

  // ゲームエンティティを描画します。
  _cat.Draw(_quadDrawer, _cameraPosition, view, projection);
  _dog.Draw(_quadDrawer, _cameraPosition, view, projection);

  base.Draw(gameTime);
}

تولید نمایش و تحول طرح از اطلاعات دوربین.

برای زمین مستطیل کشیده شده در QuadDrawer به صورت عمودی نمایش داده می شود، بنابراین می چرخد تا افقی باشد و به صورت متوسط بزرگ شود. _quadDrawer.DrawQuad آر استدلال دوم روش تعداد تکرارهای بافت را مشخص می کند که مشخص می کند ورق های ۳۲x۳۲ در کنار هم ظاهر می شوند.

_cat و _dog به صورت داخلی بیلبورد شده اند، بنابراین اطلاعات محل دوربین منتقل و کشیده می شود.

روش HandleInput

/// <summary>
/// ゲームを終了するための入力を処理します。
/// </summary>
void HandleInput()
{
  _currentKeyboardState = Keyboard.GetState();
  _currentGamePadState = GamePad.GetState(PlayerIndex.One);

  // 終了を確認します。
  if (_currentKeyboardState.IsKeyDown(Keys.Escape) ||
      _currentGamePadState.Buttons.Back == ButtonState.Pressed)
  {
    Exit();
  }
}

اطلاعات مربوط به صفحه کلید و gamepad اکتسابی است، و پایان بازی مشخص می شود.

روش UpdateCamera

/// <summary>
/// カメラを動かすための入力を処理します。
/// </summary>
void UpdateCamera()
{
  const float turnSpeed = 0.05f;
  const float accelerationSpeed = 4;
  const float frictionAmount = 0.98f;

  // 左または右に曲がります。
  float turn = -_currentGamePadState.ThumbSticks.Left.X * turnSpeed;

  if (_currentKeyboardState.IsKeyDown(Keys.Left)) turn += turnSpeed;
  if (_currentKeyboardState.IsKeyDown(Keys.Right)) turn -= turnSpeed;

  _cameraForward = Vector3.TransformNormal(_cameraForward, Matrix.CreateRotationY(turn));

  // 前方または後方に加速します。
  float accel = _currentGamePadState.ThumbSticks.Left.Y * accelerationSpeed;

  if (_currentKeyboardState.IsKeyDown(Keys.Up)) accel += accelerationSpeed;
  if (_currentKeyboardState.IsKeyDown(Keys.Down)) accel -= accelerationSpeed;

  _cameraVelocity += _cameraForward * accel;

  // 現在の位置に速度を追加します。
  _cameraPosition += _cameraVelocity;

  // 摩擦力を加えます。
  _cameraVelocity *= frictionAmount;
}

دوربین برای حرکت کنترل می شود.

همچنین شامل محاسباتی مانند شتاب و اصطکاک است، اما فکر می کنم احتمالاً اثر دوپلر را بر روی صدای سه بعد در نظر می گیرد. از آنجا که من هیچ کار خاصی در مورد محاسبه خود را انجام نمی دهد، من آن را مورد بحث نیست.

خلاصه

من آن را در طول AudioManager پوشش داده ام، اما معمولا کافی است برای اشاره به کلاس برای چگونگی پخش صدای سه بعد. در واقع بیشتر مشکلات توسط چارچوب انجام SoundEffectInstance می شود، زیرا کاری که ما انجام می دهیم تنظیم اطلاعات سه بعدی در آن است. اگر شما فقط بخش هایی از صدای سه بعد را نمونه برداری کرده ام، در نهایت کمی کار در کلاس بازی می نویسید. با این حال ، من نوشتن نکات بر اساس داستان اصلی ، بنابراین آن را بسیار طولانی تر شده است.