Аудіо3D

Сторінка оновлюється :
Дата створення сторінки :

Примітки до цієї поради

Цей зразок базується на програмах, опублікованих на наступних сайтах. Я трохи змінюю код, щоб було легше зрозуміти і пояснити його японською мовою. В основному, ми використовуємо оригінальний код як є, тому, якщо ви дійсно приймаєте його у своїй ігровій програмі, вчасно виправте його та використовуйте.

Довідковий сайт

Крім того, це пояснюється припущенням, що у вас є деякі базові знання про MonoGame і XNA. Дивіться Поради Щодо MonoGame та поради XNA для грубо.

Зокрема, оскільки математика, вектори, тригонометричні функції, матриці тощо мають важливе значення, тому, будь ласка, знайте, що вони до певної міри.

середовище

платформа
  • Windows 10
  • Код можна використовувати на інших платформах з підтримкою MonoGame
Візуальна студія
  • Візуальна студія 2019
.NET Core
  • 3.1
Моногаграма
  • 3.8

Про зразки

Виходячи з положення камери, можна почути дзвінок з положення собаки і положення кішки. Кішка кружляє і обводить походження, а гравець може керувати положенням камери за допомогою ключа. Переконайтеся, що те, як ви чуєте звук, змінюється з кожною зміною положення камери або положення кішки. Я думаю, що це легко зрозуміти за допомогою навушників. Про це повідомляється на каналі 5.1.

Як працювати

Що робити клавіатурі геймпад (XInput) миші
Камера вперед і назад ↑↓ Ліва паличка (зверху і знизу) - -
Змінення орієнтації камери ←→ Ліва паличка (ліва і справа) - -
Кінець гри Esc Задній - -

До чого готуватися

  • Собака вереск аудіофайл
  • Три кішки верещать аудіофайли
  • Файл зображення собаки
  • Файл зображення кішки
  • Файл зображення заземлення

Оригінальний зразок на офіційному сайті використовує вбудований вміст .xnb файли. Якщо ви хочете зберегти зразки на офіційному сайті, не використовуйте mgcbs, додайте їх безпосередньо до рішення Visual Studio і скопіюйте їх під час збирання.

Я не знаю, чому оригінальний зразок приймає цей метод, але я думаю, що це, ймовірно, тому, що ми мігруємо старі версії проекту, як є. Звичайно, ви можете використовувати mgcb для створення того ж файлу. Проекти, які можна завантажити на цьому сайті, були змінені на версію MGCB.

програма

Завантажити програму для всього коду.

Цей зразок призначений для того, щоб код виглядав трохи більш загальним, роблячи відтворення звуку добре виглядати під час виконання. Використання Audio3D було б набагато менше коду, але це описано уздовж оригінального зразка. Я буду тримати менш важливі частини.

Проект складається з наступних файлів коду:

  • Аудіо3DGame
  • Аудіоменеджер
  • Кішка
  • Пес
  • IAudioemitter
  • Програма
  • Квадродравер
  • Спрайтентність

Клас QuadDrawer

Цей клас є допоміжним класом для малювання прямокутних багатокутників. Прямокутні багатокутники часто використовуються в основному для відображення 3D спрайтів (рекламних щитів). Ці поради використовуються для рекламних щитів для кішок і собак, а також для прямокутних дисплеїв землі.

Цей клас не має нічого спільного з 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 отримуєте екземпляр, створений у процесі ініціалізації ігрового класу.

Тут ми встановлюємо ефект, необхідний для малювання спрайту і положення 4 вершин, необхідних для прямокутного багатокутника. Розмір слід масштабувати при малюванні, щоб він був -1 до 1.

Метод 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 аргументі може бути вказана викликана змінна, так що координати текстури можуть бути змінені. Якщо вершинаPositionTexture.TextureCoordinate встановлена за межами діапазону від 0 до 1, текстура намальована кілька разів за замовчуванням. Використовуючи його, можна висловити, що плитки можна розташувати неодноразово. Насправді, картаті візерунки на землі, здається, мають кілька простих чорно-білих зображень.

Інтерфейс IAudioEmitter

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

Визначається як сутність, яка видає звук. Оскільки сутності, які випромінюють звук на цей раз, - це собаки і кішки, вони успадковуються у відповідних класах. Випромінювачу потрібна наступна інформація:

Використання властивостей
Позиція Позиція сутності
Вперед Напрямок, до якого звернено сутність (вектор)
Вгору Вгору від сутності. Напрямок, в якому голова існує у людини
Швидкість Швидкість, з якою сутність рухається. Використовується для обчислення значень доплера.

Клас спрайтентності

Клас для представлення 3D спрайтів (рекламних щитів). Він також є випромінювачем і успадковує 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 Успадкування класу. Собака залишається в нерухомому положенні в 3D-просторі.

поле

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

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

_timeDelay Використовується з інтервалами, щоб грати крик.

SoundEffectInstance _activeSound є прикладом для відтворення звуку. SoundEffectInstance Як ви часто бачите в класі відтворення звуку, ви можете використовувати це, як це відбувається в 3D-звучанні. До речі _activeSound , я отримую посилання тільки від класу AudioManager пізніше, тому я не буду відкидати його на стороні класу Dot.

Метод оновлення

/// <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-просторі, передаючи ім'я крику, циклічної інформації та вашої власної інформації як випромінювача .

Клас Dog розроблений для петлі крику, так що вам не доведеться думати занадто глибоко, тому що це просто коригування, наприклад, грати або зупинити розгалуження.

Клас кішки

Це клас, який робить кішку малювання і спів відтворення. SpriteEntity Успадкування класу. Кішка рухається навколо походження.

поле

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

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

_timeDelay використовується так само, як і клас Собаки, з рештою часу до наступного вереску.

Є три типи котячих дзвінків, які випадковим чином вибираються і граються, але вони не мають нічого спільного з 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 Я переходжу до методу, який є випромінювачем. Ви можете бачити, що положення відтворення звуку змінюється один за одним.

Клас аудіоменеджера

У цьому, нарешті, суть Audio3D. 3D-звук складається зі слухача і випромінювача. Випромінювач вже визначає собак і кішок, тому клас 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 — це визначення випромінювача при застосуванні 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 3D-звуку.

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;
}

Процес відтворення 3D-звуку ззовні. Він має назву звуку для відтворення, будь то петля, і випромінювач інформації.

Якщо потрібно відтворити звук, створіть новий звуковий екземпляр зі звукового ресурсу, який ви зберігаєте в _soundEffects. SoundEffectInstance також може мати цикл чи ні, тому встановіть інформацію про цикл.

Оскільки я створюю як ActiveSound стан відтворення, я установляю інформацію про випромінювач, яка є об'єктом відтворення звуку там. Якщо ви хочете застосувати інформацію про 3D-місцезнаходження до звуку, ви отримаєте Emitter потрібне значення.

Apply3D Метод описаний нижче, але це процес нанесення 3D-інформації від випромінювача до звуку.

Основний процес 3D-звуку полягає в тому, щоб почати відтворення з набором SoundEffectInstance.Play 3D-інформації. Решта - періодично оновлювати 3D-інформацію до завершення відтворення звуку.

Застосувати метод3D

/// <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);
}

Процес застосування 3D-ефекту до заданого звукового екземпляра за допомогою слухачів і випромінювачів.

Кожного разу ми встановлюємо значення _emitter загального екземпляра. Якщо він у вас SoundEffectInstance.Apply3D вже AudioEmitter є, просто передайте слухача і випромінювач методу.

Клас аудіо3DGame

Нарешті, давайте подивимося, про що клас гри.

поле

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 Другий аргумент методу визначає кількість повторів текстури, яка вказує на те, що аркуші 32х32 з'являються поруч.

_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();
  }
}

Інформація на клавіатурі і геймпаді купується, а кінець гри визначається.

Метод 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;
}

Камера контролюється для переміщення.

Він також включає в себе такі розрахунки, як прискорення і тертя, але я думаю, що це, ймовірно, з урахуванням ефекту Доплера на 3D-звук. Оскільки нічого особливого в самому розрахунку я не роблю, я не буду його обговорювати.

Зведення

Я висвітлив його в довжину, але, як правило, достатньо звернутися до класу для AudioManager того, як відтворювати 3D-звук. Насправді, більшість труднощів робиться рамками, тому що те, що SoundEffectInstance ми робимо, - це установка 3D-інформації в . Якщо ви відібрали лише частини 3D-звуку, ви в кінцевому підсумку напишете невелику роботу в класі Game. Тим не менш, я пишу поради, засновані на оригінальній історії, так що це було набагато довше.