Audio3D

Diese Seite wurde aktualisiert :
Erstellungsdatum der Seite :

Hinweise zu diesen Tipps

Dieses Beispiel basiert auf den Programmen, die auf den folgenden Websites veröffentlicht wurden. Ich ändere den Code ein wenig, um es einfacher zu machen, ihn auf Japanisch zu verstehen und zu erklären. Grundsätzlich verwenden wir den ursprünglichen Code so, wie er ist, wenn Sie ihn also tatsächlich in Ihr Spielprogramm übernehmen, korrigieren Sie ihn rechtzeitig und verwenden Sie ihn.

Referenzseite

Darüber hinaus wird es unter der Annahme erklärt, dass Sie einige Grundkenntnisse über MonoGame und XNA haben. Siehe MonoGame Tipps und XNA Tipps für das Ruder.

Insbesondere, da Mathematik, Vektoren, trigonometrische Funktionen, Matrizen usw. unerlässlich sind, wissen Sie bitte, was sie bis zu einem gewissen Grad sind.

Umwelt

Bahnsteig
  • Windows 10
  • Code kann auf anderen MonoGame-fähigen Plattformen verwendet werden
Visual Studio
  • Visual Studio 2019
.NET Core
  • 3.1
MonoGame
  • 3.8

Über Beispiele

Basierend auf der Position der Kamera können Sie den Ruf von der Position des Hundes und der Position der Katze hören. Die Katze umkreist und umkreist den Ursprung, und der Spieler kann die Position der Kamera mit dem Schlüssel steuern. Stellen Sie sicher, dass sich die Art und Weise, wie Sie den Ton hören, mit jeder Änderung der Position der Kamera oder der Position der Katze ändert. Ich denke, dass es mit Kopfhörern leicht zu verstehen ist. Ich bin auf Kanal 5.1 unbestätigt.

Bedienung

Was ist zu tun Keyboard Gamepad (XInput) Mouse Touch
Kamera vorwärts und rückwärts ↑↓ Linker Stick (oben und unten) - -
Kameraausrichtung ändern ←→ Linker Stick (links und rechts) - -
Ende des Spiels Esc Zurück - -

Was ist vorzubereiten?

  • Hunde quietschen Audiodatei
  • Drei Katzen quietschen Audiodateien
  • Hundebilddatei
  • Katzenbilddatei
  • Bodenbilddatei

Das Originalbeispiel auf der offiziellen Website verwendet vorgefertigte XNB-Inhaltsdateien . Wenn Sie die Beispiele auf der offiziellen Website beibehalten möchten, verwenden Sie mgcbs nicht, fügen Sie sie direkt der Visual Studio-Projektmappe hinzu, und kopieren Sie sie zur Buildzeit.

Ich weiß nicht, warum das ursprüngliche Beispiel diese Methode verwendet, aber ich denke, es liegt wahrscheinlich daran, dass wir ältere Versionen des Projekts so migrieren, wie es ist. Natürlich können Sie mgcb verwenden, um die gleiche Datei zu generieren. Die Projekte, die auf dieser Website heruntergeladen werden können, wurden auf die MGCB-Version geändert.

Programm

Laden Sie das Programm für den gesamten Code herunter.

Dieses Beispiel wurde entwickelt, um den Code etwas allgemeiner aussehen zu lassen, während die Soundwiedergabe zur Laufzeit gut aussieht. Die Verwendung von Audio3D nur wäre viel weniger Code, aber es wird entlang des ursprünglichen Beispiels beschrieben. Ich behalte die weniger wichtigen Teile.

Das Projekt besteht aus den folgenden Codedateien:

  • Audio3DGame
  • AudioManager
  • Katze
  • Hund
  • IAudioEmitter
  • Programm
  • QuadDrawer
  • SpriteEntity

QuadDrawer-Klasse

Diese Klasse ist eine Hilfsklasse zum Zeichnen rechteckiger Polygone. Rechteckige Polygone werden oft hauptsächlich zur Darstellung von 3D-Sprites (Billboards) verwendet. Diese Tipps werden für Werbetafeln für Katzen und Hunde sowie für rechteckige Darstellungen des Bodens verwendet.

Diese Klasse hat nichts mit Audio3D zu tun.

Feld

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

Mindestinformationen, die zum Zeichnen von Polygonen erforderlich sind. Zeichnen Sie Polygone aus Vertexdaten, ohne Modelldaten vorzubereiten.

Konstruktor

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

Da diese Klasse universell verwendbar ist, erhalten Sie GraphicsDevice eine Instanz, die im Initialisierungsprozess der Spielklasse erstellt wurde.

Hier legen wir den Effekt fest, der zum Zeichnen des Sprites und der Position der 4 Eckpunkte erforderlich ist, die für das rechteckige Polygon erforderlich sind. Die Größe sollte beim Zeichnen skaliert werden, also ist sie -1 zu 1.

DrawQuad-Methode

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

Legt die übergebene Textur auf ein Rechteck fest und zeichnet sie. Da dies ein grundlegender Prozess ist, gibt es nichts zu beachten.

Wenn es einen Punkt gibt, kann eine aufgerufene Variable im textureRepeats Argument angegeben werden, so dass die Koordinaten der Textur geändert werden können. Wenn vertexPositionTexture.TextureCoordinate über den Bereich von 0 bis 1 hinaus festgelegt ist, wird die Textur standardmäßig wiederholt gezeichnet. Damit kann ausgedrückt werden, dass Kacheln wiederholt angeordnet werden können. Tatsächlich scheinen die karierten Muster auf dem Boden mehrere einfache Schwarz-Weiß-Bilder zu haben.

IAudioEmitter-Schnittstelle

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

Definiert als eine Entität, die Sound ausgibt. Da die Entitäten, die diesmal Geräusche aussenden, Hunde und Katzen sind, werden sie in ihren jeweiligen Klassen vererbt. Der Emitter benötigt die folgenden Informationen:

Nutzung der Immobilie
Position Position der Entität
Vorwärts Die Richtung, in die das Objekt zeigt (Vektor)
Oben Das Up der Entität. Die Richtung, in der der Kopf in einer Person existiert
Geschwindigkeit Die Geschwindigkeit, mit der sich die Entität bewegt. Wird verwendet, um Dopplerwerte zu berechnen.

SpriteEntity-Klasse

Eine Klasse zur Darstellung von 3D-Sprites (Billboards). Es ist auch ein Emitter und erbt IAudioEmitter . Hunde und Katzen erben diese Klasse.

Eigentum

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

Es hat die Standortinformationen der Entität usw. Grundsätzlich habe ich Informationen als Emitter. Es ist auch eine Zeichnungsentität, so dass es auch ein Bild (Textur) anzuzeigen hat.

Update-Methode

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

Beschreibt die Position der Entität und den Prozess der Soundwiedergabe, implementiert sie jedoch in der abgeleiteten Klasse.

Draw-Methode

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

Hunde und Katzen haben unterschiedliche Bilder und Positionen, aber der andere Zeichenmechanismus ist genau derselbe, also beschreibe ich sie hier.

Jede Transformation und Textur wird an QuadDrawer übergeben, um ein rechteckiges Polygon anzuzeigen. Da koordinatentransformation Grundwissen ist, werden Erklärungen nicht behandelt.

Matrix.CreateConstrainedBillboard Verwenden Sie Methoden- und Kamerainformationen, um Werbetafeln einfach darzustellen, also nutzen Sie sie effektiv.

Hundeklasse

Es ist eine Klasse, die Hunde zeichnen und Singen Playback macht. SpriteEntity Erben der Klasse. Der Hund bleibt in einer festen Position im 3D-Raum.

Feld

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

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

_timeDelay wird in Intervallen verwendet, um den Schrei zu spielen.

SoundEffectInstance _activeSound ist eine Instanz zum Abspielen eines Sounds. SoundEffectInstance Wie Sie oft in der Klasse der Soundwiedergabe sehen werden, können Sie dies so verwenden, wie es im 3D-Sound der Fall ist. Übrigens _activeSound erhalte ich erst später eine Referenz von der AudioManager-Klasse, daher werde ich sie nicht auf der Seite der Dot-Klasse verwerfen.

Update-Methode

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

In dieser Probe bleibt der Hund lange Zeit in der gleichen Position, so dass die ersten vier Parameter durch einen entscheidenden Schlag spezifiziert werden. Das Zeichnen erfolgt in der Basisklasse.

_timeDelay wird dann als verbleibende Zeit verwendet, um aufzuhören und den Schrei zu spielen.

AudioManager wird im 3D-Raum reproduziertPlay3DSound , indem der Name des Schreis, schleifeninformationen und Ihre eigenen Informationen als Emitter an übergeben werden.

Die Hundeklasse ist so konzipiert, dass sie den Schrei wiederholt, so dass Sie nicht zu tief nachdenken müssen, da es sich nur um eine Anpassung handelt, z. B. Spielen oder Stoppen der Verzweigung.

Katzenklasse

Es ist eine Klasse, die Katzen zeichnen und singen Wiedergabe macht. SpriteEntity Erben der Klasse. Die Katze bewegt sich um den Ursprung herum.

Feld

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

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

_timeDelay wird auf die gleiche Weise wie die Hundeklasse verwendet, mit dem Rest der Zeit vor dem nächsten Quietschen.

Es gibt drei Arten von Katzenrufen, die zufällig ausgewählt und abgespielt werden, aber sie haben nichts mit Audio3D zu tun, da sie ein Bonuselement sind.

Update-Methode

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

Da sich die Katze in einer kreisförmigen Bewegung um den Ursprung dreht, verarbeitet sie ihn so, dass sie die Flugbahn des Kreises mit einer trigonometrischen Funktion bewegt. Infolgedessen haben sich Position, Vorwärts und Geschwindigkeit nacheinander geändert. Wenn Sie das Programm ausführen, können Sie daher sehen, dass der Schrei der Katze kreist, auch wenn Sie die Kamera nicht bewegen.

_timeDelay Der folgende Code ist ein Prozess, bei dem der Katzenschrei zufällig zugewiesen und in regelmäßigen Abständen abgespielt wird. audioManager.Play3DSound Ich übergebe mich an die Methode, die ein Emitter ist. Sie können sehen, dass sich die Wiedergabeposition des Sounds nacheinander ändert.

AudioManager-Klasse

Das ist schließlich die Essenz von Audio3D. Ein 3D-Sound besteht aus einem Zuhörer und einem Emitter. Der Emitter definiert bereits Hunde und Katzen, daher definiert die AudioManager-Klasse Listener. Es gibt normalerweise mehrere Emitter, während es nur einen Listener gibt.

Diese Klasse erbt undGame registriert GameComponent und verwendet die Komponente in der Klasse.

ActiveSound-Klasse

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

Es ist am Ende des Codes definiert, aber es ist eine Klasse zum Beibehalten des Zustands, der wiedergegeben wird. Es enthält Informationen über die abgespielte Soundinstanz und den abgespielten Emitter.

Feld

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 definiert den Namen der zu ladenden Audiodatei (Asset-Name). Da es sich um ein Beispielprogramm handelt, ist es so definiert, dass die Audiodatei zuerst in großen Mengen geladen wird. Die importierten Sounddaten _soundEffects werden in gespeichert.

AudioListener Listener ist die Definition des Listeners. Listenerinformationen werden in definiert, da sie public aus der Game-Klasse festgelegt werden.

AudioEmitter _emitter ist die Definition des Emitters bei der Anwendung von 3D auf die Klangwiedergabe. In diesem Beispiel wird beim Abspielen eines Sounds der Wert jedes Emitterobjekts auf festgelegt, sodass es sich um _emitter ein Formular handelt, das eines als Instanz gemeinsam verwendet. Natürlich können Sie für jedes AudioEmitter Objekt haben.

_activeSounds enthält Informationen über den Sound, den Sie in der zuvor definierten ActiveSound Klasse wiedergeben. Da sich die Emitterinformationen ständig ändern, werden sie zum Aktualisieren von Standortinformationen usw. und zum Verwerfen von Soundinstanzen verwendet, deren Wiedergabe beendet ist.

Konstruktor

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

GameComponent Da es die Klasse erbt, Game empfängt es die Instanz und übergibt sie an die Basisklasse.

Initialize-Methode

/// <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 Da sie die Klasse erbt, wird sie bei der Initialisierung automatisch aufgerufen.

SoundEffect.DistanceScale und SoundEffect.DopplerScale sind Parameter, die dem 3D-Sound gewidmet static sind.

SoundEffect.DistanceScale um Auch in der Ferne Geräusche zu hören.

SoundEffect.DopplerScale ist der Einfluss des Doppler-Effekts. Je höher die Zahl, desto größer der Dopplereffekt.

_soundNames Speichern Sie den asset-Namen, der in einer Schleife definiert ist, um zu laden _soundEffects .

Dispose-Methode

/// <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 Es wird automatisch am Ende des Spiels aufgerufen, da es die Klasse erbt.

Löschen aller importierten Sound-Assets.

Update-Methode

/// <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 Da sie die Klasse erbt, wird sie im Aktualisierungsprozess automatisch aufgerufen.

Überprüfen Sie den aktuell wiedergegebenen Ton, und rufen Sie, wenn er Apply3D wiedergegeben wird, die Methode auf, um die Position des Sounds so zu aktualisieren, dass sie mit dem Emitter übereinstimmt. Wenn die Wiedergabe eines Sounds beendet wurde, wird die Instanz verworfen.

Play3DSound-Methode

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

Der Prozess des Abspielens von 3D-Sound von außen. Es hat den Namen des zu spielenden Sounds, ob eine Schleife erfolgen soll, und Emitterinformationen.

Wenn Sie einen Sound wiedergeben möchten, erstellen Sie eine neue Soundinstanz aus der Soundressource, die Sie im _soundEffects. SoundEffectInstance kann auch eine Schleife haben oder nicht, also stellen Sie die Schleifeninformationen ein.

Da ich als ActiveSound Wiedergabezustand erstelle, setze ich Emitterinformationen, die das Wiedergabeobjekt des Sounds dort sind. Wenn Sie 3D-Positionsinformationen auf einen Sound anwenden möchten, erhalten Emitter Sie den Wert, den Sie benötigen.

Apply3D Die Methode wird unten beschrieben, aber es ist der Prozess der Anwendung von 3D-Informationen vom Emitter auf den Klang.

Der grundlegende Prozess von 3D-Sound besteht darin, die Wiedergabe mit SoundEffectInstance.Play 3D-Informationen zu starten. Der Rest besteht darin, die 3D-Informationen regelmäßig zu aktualisieren, bis die Wiedergabe des Sounds beendet ist.

Apply3D-Methode

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

Der Prozess des Anwendens eines 3D-Effekts auf eine angegebene Soundinstanz mithilfe von Listenern und Emittern.

Wir legen den Wert jedes Mal auf den _emitter der gemeinsamen Instanz fest. Wenn Sie bereits AudioEmitter einen haben, übergeben Sie SoundEffectInstance.Apply3D einfach den Listener und den Emitter an die Methode.

Audio3DGame Klasse

Schauen wir uns zum Schluss an, worum es in der Game-Klasse geht.

Feld

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;

AudioManagerGameComponents Registriert sich in , hat es aber als Feld, da es einzeln darauf zugreift.

Andere definieren Hunde-, Katzenentitäten, Texturen für die Bodenzeichnung, Quaddrawer, Kamerainformationen und Eingabeinformationen.

Konstruktor

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 Generieren und GameComponents registrieren sie mit .

Sie haben auch die Klassen Katze und Hund generiert.

LoadContent-Methode

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

Laden Sie die für jede Zeichnung benötigten Texturen.

QuadDrawer wird GraphicsDevice hier generiert, weil erforderlich ist.

Update-Methode

/// <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 Die Methoden und UpdateCamera Methoden sind der Prozess des Abrufens von Geräteeingaben und der Handhabung der Kamera, auf den später eingegangen wird.

Da Kameraposition und Zuhörerposition fast immer gleich sind, wird der Listener nach dem Kamera-Update-Vorgang auf den gleichen Wert gesetzt.

_cat Rufen Sie die Und _dog Update-Methoden auf, um sich zu bewegen bzw. zu quietschen.

Draw-Methode

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

Generiert Ansichts- und Projektionstransformationen aus Kamerainformationen.

Für den Boden wird das in QuadDrawer gezeichnete Rechteck vertikal angezeigt, sodass es horizontal gedreht und moderat vergrößert wird. _quadDrawer.DrawQuad Das zweite Argument der Methode gibt die Anzahl der Wiederholungen der Textur an, die angibt, dass 32x32 Blätter nebeneinander angezeigt werden.

_cat und _dog werden intern ausgehängt, sodass die Standortinformationen der Kamera weitergegeben und gezeichnet werden.

HandleInput-Methode

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

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

Informationen auf der Tastatur und dem Gamepad werden erfasst und das Ende des Spiels wird festgelegt.

UpdateCamera-Methode

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

Die Kamera wird gesteuert, um sich zu bewegen.

Es enthält auch Berechnungen wie Beschleunigung und Reibung, aber ich denke, es berücksichtigt wahrscheinlich den Doppler-Effekt auf 3D-Sound. Da ich nichts Besonderes an der Berechnung selbst mache, werde ich nicht darauf eingehen.

Zusammenfassung

Ich habe es ausführlich behandelt, aber es reicht normalerweise aus, sich auf die Klasse AudioManager zu beziehen, um 3D-Sound abzuspielen. Tatsächlich werden die meisten Schwierigkeiten durch das Framework verursacht, da SoundEffectInstance wir 3D-Informationen in festlegen. Wenn Sie nur die Teile des 3D-Sounds gesampelt haben, werden Sie am Ende eine kleine Arbeit in der Game-Klasse schreiben. Ich schreibe jedoch Tipps, die auf der ursprünglichen Geschichte basieren, also ist es schon viel länger her.