Àudio3D

Pàgina actualitzada :
Data de creació de la pàgina :

Notes sobre aquests consells

Aquesta mostra es basa en els programes publicats en els següents llocs. Canvio una mica el codi per fer-lo més fàcil d'entendre i explicar-lo en japonès. Bàsicament, utilitzem el codi original tal com és, de manera que si realment l'adopteu al vostre programa de joc, corregiu-lo de manera oportuna i utilitzeu-lo.

Lloc de referència

A més, s'explica en el supòsit que vostè té alguns coneixements bàsics sobre MonoGame i XNA. Vegeu Consells de MonoGame i Consells XNA per al groller.

En particular, com les matemàtiques, vectors, funcions trigonomètriques, matrius, etc. són essencials, així que si us plau, sapigueu què són fins a cert punt.

entorn

plataforma
  • Windows 10
  • El codi es pot utilitzar en altres plataformes habilitades per a MonoGame
Estudi visual
  • Visual Studio 2019
Nucli .NET
  • 3.1
Monojoi
  • 3.8

Quant a les mostres

En funció de la posició de la càmera, es pot escoltar la trucada des de la posició del gos i la posició del gat. El gat envolta i envolta l'origen, i el jugador pot controlar la posició de la càmera amb la clau. Assegureu-vos que la forma en què escolteu el so canvia amb cada canvi en la posició de la càmera o la posició del gat. Crec que és fàcil d'entendre amb auriculars. No estic confirmat al canal 5.1.

Com operar

Què s'ha de fer amb el teclat gamepad (XInput) Tàctil del ratolí
Càmera cap endavant i cap enrere ↑↓ Pal esquerre (superior i inferior) - -
Canvia l'orientació de la càmera ←→ Pal esquerre (esquerra i dreta) - -
Final de la partida Esc Esquena - -

Què preparar

  • Fitxer d'àudio de grinyol del gos
  • Tres fitxers d'àudio de grinyol de gat
  • Fitxer d'imatge del gos
  • Fitxer d'imatge del cat
  • Fitxer d'imatge de terra

La mostra original del lloc oficial utilitza fitxers .xnb de contingut precompilat. Si voleu conservar les mostres al lloc oficial, no utilitzeu mgcbs, afegiu-les directament a la solució de Visual Studio i copieu-les en el moment de la construcció.

No sé per què la mostra original està prenent aquest mètode, però crec que és probablement perquè estem migrant versions més antigues del projecte tal com és. Per descomptat, podeu utilitzar mgcb per generar el mateix fitxer. Els projectes que es poden descarregar en aquest lloc han estat modificats a la versió MGCB.

programa

Descarrega't el programa per a tot el codi.

Aquesta mostra està dissenyada per fer que el codi es vegi una mica més general mentre fa que la reproducció de so es vegi bé en temps d'execució. L'ús d'Audio3D només seria molt menys codi, però es descriu al llarg de la mostra original. Em quedem amb les parts menys importants.

El projecte consta dels següents fitxers de codi:

  • Audio3DGame
  • AudioManager
  • Gat
  • Gos
  • IAudioEmitter
  • Programa
  • QuadDrawer
  • SpriteEntity

Classe QuadDrawer

Aquesta classe és una classe d'ajuda per dibuixar polígons rectangulars. Els polígons rectangulars s'utilitzen sovint principalment per mostrar personatges 3D (tanques publicitàries). Aquests consells s'utilitzen per a tanques publicitàries per a gats i gossos, així com per a exhibicions rectangulars del sòl.

Aquesta classe no té res a veure amb l'Audio3D.

camp

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

Informació mínima necessària per dibuixar polígons. Dibuixa polígons a partir de dades de vèrtexs sense preparar dades de model.

constructor

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

Com que aquesta classe és universalment utilitzable, rebeu GraphicsDevice una instància creada en el procés d'inicialització de la classe de joc.

Aquí, establim l'efecte necessari per dibuixar el personatge i la posició dels 4 vèrtexs necessaris per al polígon rectangular. La mida s'ha d'escalar quan es dibuixa, de manera que és de -1 a 1.

Mètode 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);
}

Estableix la textura passada en un rectangle i la dibuixa. Com que es tracta d'un procés bàsic, no hi ha res a tenir en compte.

Si hi ha un punt, es pot especificar una variable anomenada en textureRepeats l'argument, de manera que es puguin canviar les coordenades de la textura. Si vertexPositionTexture.TextureCoordinate s'estableix més enllà de l'interval 0 a 1, la textura es dibuixa repetidament per defecte. Utilitzant-lo, és possible expressar que les rajoles es poden organitzar repetidament. De fet, els patrons a quadres a terra semblen tenir diverses imatges simples en blanc i negre alineades.

Interfície IAudioEmitter

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

Definit com una entitat que emet so. Atès que les entitats que emeten so aquesta vegada són gossos i gats, s'hereten en les seves respectives classes. L'emissor necessita la següent informació:

Ús de la propietat
Posició Posició de l'entitat
Endavant La direcció a la qual s'enfronta l'entitat (vector)
Amunt El dalt de l'entitat. La direcció en què el cap existeix en una persona
Velocitat La velocitat a la qual es mou l'entitat. S'utilitza per calcular els valors doppler.

Classe de SpriteEntity

Una classe per a la representació de personatges 3D (cartells publicitaris). També és emissor, i hereta IAudioEmitter . Els gossos i els gats hereten aquesta classe.

propietat

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

Disposa de la informació de localització de l'entitat, etc. Bàsicament tinc informació com a emissor. També és una entitat de dibuix, de manera que també té una imatge (Textura) per mostrar.

Mètode d'actualització

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

Descriu la posició de l'entitat i el procés de reproducció del so, però l'implementa a la classe derivada.

Mètode de dibuix

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

Els gossos i els gats tenen imatges i posicions diferents, però l'altre mecanisme de dibuix és exactament el mateix, així que els descric aquí.

Cada transformació i textura es passa a QuadDrawer per mostrar un polígon rectangular. Atès que la transformació coordinada és coneixement bàsic, les explicacions no estan cobertes.

Matrix.CreateConstrainedBillboard Utilitzeu el mètode i la informació de la càmera per representar fàcilment les tanques publicitàries, de manera que feu-ne un ús eficaç.

Classe de gossos

És una classe que fa el dibuix de gossos i el joc de cant. SpriteEntity Heretar la classe. El gos es troba en una posició fixa en un espai 3D.

camp

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

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

_timeDelay S'utilitza a intervals per tocar el crit.

SoundEffectInstance _activeSound és un exemple per tocar un so. SoundEffectInstance Com veureu sovint a la classe de reproducció de so, podeu utilitzar-lo com ho és en el so 3D. Per cert _activeSound , només rebo una referència de la classe AudioManager més tard, de manera que no la descartaré al costat de la classe Dot.

Mètode d'actualització

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

En aquesta mostra, el gos roman en la mateixa posició durant molt de temps, de manera que els quatre primers paràmetres s'especifiquen mitjançant un cop decisiu. El dibuix es fa a la classe bàsica.

_timeDelay s'utilitza com el temps restant per aturar-se, jugant al plor.

AudioManager es reproduiràPlay3DSound en l'espai 3D passant el nom del crit, la informació del bucle i la vostra pròpia informació com a emissor a .

La classe de gossos està dissenyada per fer un bucle del crit, de manera que no cal pensar massa profundament perquè és només un ajustament, com jugar o deixar de ramificar.

Classe de gat

És una classe que fa cat dibuixant i cantant playback. SpriteEntity Heretar la classe. El gat es mou al voltant de l'origen.

camp

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

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

_timeDelay s'utilitza de la mateixa manera que la classe de gossos, amb la resta del temps abans del següent grinyol.

Hi ha tres tipus de trucades de gats que es seleccionen i es reprodueixen aleatòriament, però no tenen res a veure amb Audio3D perquè són un element de bonificació.

Mètode d'actualització

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

Com que el gat gira al voltant de l'origen en un moviment circular, el processa de manera que mou la trajectòria de la circumferència utilitzant una funció trigonomètrica. Com a resultat, la posició, l'avanç i la velocitat han canviat un darrere l'altre. Per tant, quan executeu el programa, podeu veure que el crit del gat gira al voltant, fins i tot si no moveu la càmera.

_timeDelay El següent codi és un procés en el qual el crit del gat s'assigna aleatòriament i es reprodueix a intervals regulars. audioManager.Play3DSound M'estic passant al mètode que és un emissor. Pots veure que la posició de reproducció del so canvia una a una.

Classe AudioManager

Aquesta és, finalment, l'essència d'Audio3D. Un so 3D consisteix en un oient i un emissor. L'emissor ja defineix gossos i gats, de manera que la classe AudioManager defineix els oients. Normalment hi ha diversos emissors, mentre que només hi ha un oient.

Aquesta classe hereta iGame registra GameComponent i utilitza el component de la classe.

Classe ActiveSound

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

Es defineix a la part inferior del codi, però és una classe per preservar l'estat que està jugant. Té informació sobre la instància de so que s'està reont i l'emissor que s'està reant.

camp

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 defineix el nom del fitxer d'àudio (nom del recurs) a carregar. Com que és un programa d'exemple, es defineix per carregar primer el fitxer d'àudio a granel. Les dades de so importades s'emmagatzemen _soundEffects al .

AudioListener Listener És la definició de l'oient. La informació de l'oient es defineix al perquè s'estableix public a partir de la classe Joc.

AudioEmitter _emitter és la definició de l'emissor quan s'aplica el 3D a la reproducció de so. En aquesta mostra, quan es reprodueix un so, el valor de cada objecte emissor s'estableix com a _emitter , de manera que és una forma que en comparteix una com a instància. Per descomptat, podeu tenir per a cada AudioEmitter objecte.

_activeSounds té informació sobre el so que esteu reproduint a la classe que heu definit ActiveSound anteriorment. Com que la informació de l'emissor canvia tot el temps, s'utilitza per actualitzar la informació d'ubicació, etc., i per descartar instàncies de so que s'han acabat de reproduir.

constructor

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

GameComponent Com que hereta la classe, Game rep la instància i la passa a la classe base.

Inicialitza el mètode

/// <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 Com que hereta la classe, s'anomena automàticament a la inicialització.

SoundEffect.DistanceScale i SoundEffect.DopplerScale són paràmetres dedicats al static so 3D.

SoundEffect.DistanceScale Sentir el soroll fins i tot en la distància.

SoundEffect.DopplerScale És la influència de l'efecte Doppler. Com més gran sigui el nombre, més gran serà l'efecte Doppler.

_soundNames Desa el nom del recurs definit en un bucle per carregar _soundEffects .

Disposeu del mètode

/// <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 crida automàticament al final del joc perquè hereta la classe.

S'estan destruint tots els actius de so importats.

Mètode d'actualització

/// <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 Com que hereta la classe, s'anomena automàticament en el procés d'actualització.

Comproveu el so que s'està reproduint i, si s'està Apply3D reproduint, truqueu al mètode per actualitzar la ubicació del so perquè coincideixi amb l'emissor. Si algun so ha acabat de reproduir-se, la instància es descarta.

Mètode 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;
}

El procés de reproducció del so 3D des de l'exterior. Té el nom del so a reproduir, ja sigui en bucle i informació emissora.

Si vols reproduir un so, crea una instància de so nova a partir del recurs de so que guardes a la _soundEffects. SoundEffectInstance també pot tenir un bucle o no, de manera que establiu la informació del bucle.

Com que estic creant com a ActiveSound estat de reproducció, estableixo la informació de l'emissor que és l'objecte de reproducció del so allà. Si voleu aplicar la informació d'ubicació Emitter 3D a un so, obtindreu el valor que necessiteu.

Apply3D El mètode es descriu a continuació, però és el procés d'aplicar informació 3D de l'emissor al so.

El procés bàsic del so 3D és començar la reproducció amb SoundEffectInstance.Play informació 3D. La resta és actualitzar la informació 3D periòdicament fins que s'acabi de reproduir el so.

Mètode 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);
}

El procés d'aplicar un efecte 3D a una instància de so especificada utilitzant oients i emissors.

Establim el valor a la _emitter de la instància comuna cada vegada. Si ja AudioEmitter en teniu SoundEffectInstance.Apply3D un, simplement passeu l'oient i l'emissor al mètode.

Classe de joc d'àudio3D

Vegem de què va la classe de joc.

camp

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 Es registra GameComponents a , però el té com a camp perquè hi accedeix individualment.

Altres defineixen entitats de gossos, gats, textures per al dibuix a terra, quaddrawer, informació de la càmera i informació d'entrada.

constructor

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 Generar i GameComponents registrar-se amb .

També s'han fet classes de gossos i gats.

Mètode 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);
}

Carrega les textures necessàries per a cada dibuix.

QuadDrawer es GraphicsDevice genera aquí perquè requereix .

Mètode d'actualització

/// <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 Els mètodes i UpdateCamera mètodes són el procés de recuperació de l'entrada del dispositiu i el maneig de la càmera, que es discutirà més endavant.

Atès que la posició de la càmera i la posició de l'oient són gairebé sempre els mateixos, l'oient s'estableix al mateix valor després del procés d'actualització de la càmera.

_cat Truqueu als mètodes i _dog Actualitza per moure i grinyolar, respectivament.

Mètode de dibuix

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

Genera transformacions de visió i projecció a partir de la informació de la càmera.

Per al terra, el rectangle dibuixat a QuadDrawer es mostra verticalment, de manera que es gira per ser horitzontal i s'amplia moderadament. _quadDrawer.DrawQuad El segon argument del mètode especifica el nombre de repeticions de la textura, que especifica que els fulls 32x32 apareixen un al costat de l'altre.

_cat i _dog estan cartellejats internament, de manera que la informació d'ubicació de la càmera es passa i es dibuixa.

Mètode HandleInput

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

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

S'adquireix informació sobre el teclat i el gamepad, i es determina el final del joc.

Mètode 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;
}

La càmera està controlada per moure's.

També inclou càlculs com l'acceleració i la fricció, però crec que probablement està tenint en compte l'efecte Doppler sobre el so 3D. Com que no faig res especial sobre el càlcul en si, no en discutiré.

Resum

L'he cobert llargament, però normalment n'hi ha prou amb referir-se a la classe per AudioManager com reproduir so 3D. De fet, la majoria de les dificultats les fa el marc, perquè el que SoundEffectInstance estem fent és establir informació 3D a . Si només has mostrejat les parts del so 3D, acabaràs escrivint una mica de treball a la classe Joc. No obstant això, estic escrivint Consells basats en la història original, de manera que ha estat molt més llarg.