Audio3D

Pagina aggiornata :
Data di creazione della pagina :

Note su questo Suggerimenti

Questo esempio si basa sui programmi pubblicati nei seguenti siti. Cambio un po 'il codice per renderlo più facile da capire e spiegarlo in giapponese. Fondamentalmente, usiamo il codice originale così com'è, quindi se lo adotti effettivamente nel tuo programma di gioco, correggilo in modo tempestivo e usalo.

Sito di riferimento

Inoltre, è spiegato sul presupposto che tu abbia alcune conoscenze di base su MonoGame e XNA. Vedi Suggerimenti monogioco e Suggerimenti XNA per il ruddly.

In particolare, poiché la matematica, i vettori, le funzioni trigonometriche, le matrici, ecc. sono essenziali, quindi per favore sappi cosa sono in una certa misura.

ambiente

piattaforma
  • Finestre 10
  • Il codice può essere utilizzato su altre piattaforme abilitate per MonoGame
Visual Studio
  • Visual Studio 2019
.NET Core
  • 3.1
Monogioco
  • 3.8

Informazioni sugli esempi

In base alla posizione della telecamera, puoi sentire il richiamo dalla posizione del cane e dalla posizione del gatto. Il gatto circonda e circonda l'origine e il giocatore può controllare la posizione della telecamera con la chiave. Assicurati che il modo in cui senti il suono cambi ad ogni cambiamento nella posizione della fotocamera o nella posizione del gatto. Penso che sia facile da capire usando gli auricolari. Non sono confermato sul canale 5.1.

Come operare

Cosa fare Tastiera Gamepad (XInput) Mouse Touch
Fotocamera avanti e indietro ↑↓ Levetta sinistra (superiore e inferiore) - -
Modificare l'orientamento della fotocamera ←→ Levetta sinistra (sinistra e destra) - -
Fine del gioco Esc Indietro - -

Cosa preparare

  • File audio strillatore del cane
  • Tre file audio strillatori di gatto
  • File immagine del cane
  • File immagine gatto
  • File immagine di terra

L'esempio originale sul sito ufficiale utilizza file .xnb di contenuto predefiniti. Se si desidera conservare gli esempi nel sito ufficiale, non utilizzare mgcbs, aggiungerli direttamente alla soluzione Visual Studio e copiarli in fase di compilazione.

Non so perché il campione originale stia prendendo questo metodo, ma penso che sia probabilmente perché stiamo migrando le versioni precedenti del progetto così com'è. Naturalmente, è possibile utilizzare mgcb per generare lo stesso file. I progetti scaricabili su questo sito sono stati modificati alla versione MGCB.

programma

Scarica il programma per tutto il codice.

Questo esempio è progettato per rendere il codice un po' più generale, rendendo al contempo la riproduzione audio un buon aspetto in fase di esecuzione. L'uso di Audio3D solo sarebbe molto meno codice, ma è descritto lungo l'esempio originale. Terrò le parti meno importanti.

Il progetto è costituito dai seguenti file di codice:

  • Audio3DGame
  • AudioManager
  • Gatto
  • Cane
  • IAudioEmitter
  • Programma
  • QuadDrawer
  • SpriteEntity

Classe QuadDrawer

Questa classe è una classe helper per il disegno di poligoni rettangolari. I poligoni rettangolari sono spesso utilizzati principalmente per visualizzare sprite 3D (cartelloni pubblicitari). Questo suggerimento viene utilizzato per cartelloni pubblicitari per cani e gatti, nonché per esposizioni rettangolari del terreno.

Questa classe non ha nulla a che fare con Audio3D.

campo

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

Informazioni minime richieste per disegnare poligoni. Disegnare poligoni dai dati dei vertici senza preparare i dati del modello.

costruttore

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

Poiché questa classe è universalmente utilizzabile, si GraphicsDevice riceve un'istanza creata nel processo di inizializzazione della classe di gioco.

Qui, impostiamo l'effetto necessario per disegnare lo sprite e la posizione dei 4 vertici richiesti per il poligono rettangolare. La dimensione deve essere ridimensionata durante il disegno, quindi è da -1 a 1.

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

Imposta la texture passata su un rettangolo e la disegna. Poiché questo è un processo di base, non c'è nulla da notare.

Se c'è un punto, una variabile chiamata può essere specificata nell'argomento, in textureRepeats modo che le coordinate della trama possano essere modificate. Se vertexPositionTexture.TextureCoordinate è impostato oltre l'intervallo da 0 a 1, la texture viene disegnata ripetutamente per impostazione predefinita. Usandolo, è possibile esprimere che le tessere possono essere disposte ripetutamente. In effetti, i motivi a scacchi sul terreno sembrano avere più semplici immagini in bianco e nero allineate.

Interfaccia IAudioEmitter

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

Definito come un'entità che emette suoni. Poiché le entità che emettono suoni questa volta sono cani e gatti, sono ereditate nelle rispettive classi. Emettitore ha bisogno delle seguenti informazioni:

Uso della proprietà
Posizione Posizione dell'entità
Inoltrare Direzione in cui l'entità è rivolta (vettore)
Su L'up dell'entità. La direzione in cui la testa esiste in una persona
Velocità Velocità di spostamento dell'entità. Utilizzato per calcolare i valori Doppler.

SpriteEntity classe

Una classe per rappresentare sprite 3D (cartelloni pubblicitari). È anche un emettitore IAudioEmitter ed eredita . Cani e gatti ereditano questa classe.

proprietà

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

Ha le informazioni sulla posizione dell'entità, ecc. Fondamentalmente ho informazioni come emettitore. È anche un'entità di disegno, quindi ha anche un'immagine (Texture) da visualizzare.

Metodo di aggiornamento

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

Descrive la posizione dell'entità e il processo di riproduzione del suono, ma lo implementa nella classe derivata.

Metodo Draw

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

Cani e gatti hanno immagini e posizioni diverse, ma l'altro meccanismo di disegno è esattamente lo stesso, quindi li descrivo qui.

Ogni trasformazione e texture viene passata a QuadDrawer per visualizzare un poligono rettangolare. Poiché la trasformazione delle coordinate è una conoscenza di base, le spiegazioni non sono coperte.

Matrix.CreateConstrainedBillboard Usa il metodo e le informazioni sulla fotocamera per rappresentare facilmente i cartelloni pubblicitari, quindi fai un uso efficace di loro.

Classe per cani

È una classe che fa il disegno del cane e la riproduzione del canto. SpriteEntity Ereditare la classe. Il cane rimane in una posizione fissa nello spazio 3D.

campo

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

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

_timeDelay è usato a intervalli per suonare il grido.

SoundEffectInstance _activeSound è un'istanza per la riproduzione di un suono. SoundEffectInstance Come vedrai spesso nella classe di riproduzione del suono, puoi usarlo così com'è nel suono 3D. A proposito _activeSound , ricevo un riferimento dalla classe AudioManager solo in un secondo momento, quindi non lo scarterò sul lato della classe Dot.

Metodo di aggiornamento

/// <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 questo campione, il cane rimane nella stessa posizione per lungo tempo, quindi i primi quattro parametri sono specificati da un colpo decisivo. Il disegno è fatto nella classe base.

_timeDelay viene quindi utilizzato come il tempo rimanente per fermarsi, suonando il grido.

AudioManager verrà riprodottoPlay3DSound nello spazio 3D passando il nome del grido, le informazioni del ciclo e le proprie informazioni come emettitore a .

La classe Cane è progettata per far girare il grido, quindi non devi pensare troppo profondamente perché è solo una regolazione, come giocare o smettere di ramificarsi.

Classe Cat

È una classe che fa il disegno del gatto e la riproduzione del canto. SpriteEntity Ereditare la classe. Il gatto si muove intorno all'origine.

campo

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

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

_timeDelay viene utilizzato allo stesso modo della classe Dog, con il resto del tempo prima dello stridio successivo.

Esistono tre tipi di richiami di gatti che vengono selezionati e riprodotti in modo casuale, ma non hanno nulla a che fare con Audio3D perché sono un elemento bonus.

Metodo di aggiornamento

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

Poiché il gatto gira intorno all'origine con un movimento circolare, la elabora in modo da spostare la traiettoria del cerchio usando una funzione trigonometrica. Di conseguenza, posizione, avanti e Velocità sono cambiati uno dopo l'altro. Pertanto, quando esegui il programma, puoi vedere che il pianto del gatto gira intorno anche se non muovi la fotocamera.

_timeDelay Il seguente codice è un processo in cui il pianto del gatto viene assegnato in modo casuale e riprodotto a intervalli regolari. audioManager.Play3DSound Mi sto passando al metodo che è un emettitore. Puoi vedere che la posizione di riproduzione del suono cambia uno per uno.

Classe AudioManager

Questa è finalmente l'essenza di Audio3D. Un suono 3D è costituito da un ascoltatore e un emettitore. L'emettitore definisce già cani e gatti, quindi la classe AudioManager definisce gli ascoltatori. Di solito ci sono più emettitori, mentre c'è un solo ascoltatore.

Questa classe eredita,Game registra GameComponent e utilizza il componente nella classe.

Classe ActiveSound

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

È definito nella parte inferiore del codice, ma è una classe per preservare lo stato in riproduzione. Contiene informazioni sull'istanza audio riprodotta e sull'emettitore riprodotto.

campo

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 definisce il nome del file audio (nome risorsa) da caricare. Poiché si tratta di un programma di esempio, è definito per caricare prima il file audio in blocco. I dati _soundEffects audio importati vengono memorizzati in .

AudioListener Listener è la definizione dell'ascoltatore. Le informazioni sul listener sono definite in perché public sono impostate dalla classe Game.

AudioEmitter _emitter è la definizione dell'emettitore quando si applica il 3D alla riproduzione del suono. In questo esempio, quando si riproduce un suono, il valore di ogni oggetto emettitore è impostato _emitter su , quindi è un modulo che ne condivide uno come istanza. Certo, puoi avere per ogni AudioEmitter oggetto.

_activeSounds contiene informazioni sul suono che si sta riproducendo nella classe definita ActiveSound in precedenza. Poiché le informazioni sull'emettitore cambiano continuamente, vengono utilizzate per aggiornare le informazioni sulla posizione, ecc. e per eliminare le istanze audio che hanno terminato la riproduzione.

costruttore

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

GameComponent Poiché eredita la classe, Game riceve l'istanza e la passa alla classe base.

Metodo Initialize

/// <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 Poiché eredita la classe, viene chiamata automaticamente all'inizializzazione.

SoundEffect.DistanceScale e SoundEffect.DopplerScale sono parametri dedicati al static suono 3D.

SoundEffect.DistanceScale per sentire il suono anche in lontananza.

SoundEffect.DopplerScale è l'influenza dell'effetto Doppler. Maggiore è il numero, maggiore è l'effetto Doppler.

_soundNames Salvare il nome della risorsa definito in un ciclo da caricare _soundEffects .

Metodo Dispose

/// <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 Viene chiamato automaticamente alla fine del gioco perché eredita la classe.

Distruggere tutte le risorse audio importate.

Metodo di aggiornamento

/// <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 Poiché eredita la classe, viene chiamata automaticamente nel processo di aggiornamento.

Controllare il suono attualmente in riproduzione e, se Apply3D è in riproduzione, chiamare il metodo per aggiornare la posizione del suono in modo che corrisponda all'emettitore. Se la riproduzione di un suono è terminata, l'istanza viene eliminata.

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

Il processo di riproduzione del suono 3D dall'esterno. Ha il nome del suono da riprodurre, se eseguire il loop e le informazioni dell'emettitore.

Se si desidera riprodurre un suono, creare una nuova istanza audio dalla risorsa audio che si conserva nel _soundEffects. SoundEffectInstance può anche avere un ciclo o meno, quindi imposta le informazioni sul ciclo.

Poiché sto creando come ActiveSound stato di riproduzione, ho impostato le informazioni sull'emettitore che sono l'oggetto di riproduzione del suono lì. Se vuoi applicare le informazioni sulla posizione 3D a un suono, otterrai Emitter il valore di cui hai bisogno.

Apply3D Il metodo è descritto di seguito, ma è il processo di applicazione delle informazioni 3D dall'emettitore al suono.

Il processo di base del suono 3D consiste nell'avviare la riproduzione con SoundEffectInstance.Play il set di informazioni 3D. Il resto è aggiornare periodicamente le informazioni 3D fino al termine della riproduzione del suono.

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

Processo di applicazione di un effetto 3D a un'istanza audio specificata utilizzando listener ed emettitori.

Ogni volta impostiamo il valore sul _emitter dell'istanza comune. Se ne hai SoundEffectInstance.Apply3D già AudioEmitter uno, passa semplicemente l'ascoltatore e l'emettitore al metodo.

Audio3DGame Classe

Infine, diamo un'occhiata a cosa tratta la classe Game.

campo

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 Si registra GameComponents in , ma lo ha come campo perché vi accede individualmente.

Altri definiscono cani, entità di gatto, trame per il disegno a terra, quaddrawer, informazioni sulla fotocamera e informazioni di input.

costruttore

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 Generare e GameComponents registrarsi con .

Hai anche generato le classi Cane e Gatto.

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

Caricate le texture necessarie per ogni disegno.

QuadDrawer viene GraphicsDevice generato qui perché richiede .

Metodo di aggiornamento

/// <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 I metodi e UpdateCamera i metodi sono il processo di recupero dell'input del dispositivo e la gestione della fotocamera, che verrà discusso in seguito.

Poiché la posizione della telecamera e la posizione dell'ascoltatore sono quasi sempre le stesse, l'ascoltatore viene impostato sullo stesso valore dopo il processo di aggiornamento della telecamera.

_cat Chiamare i metodi e _dog Update per spostare e strillare, rispettivamente.

Metodo Draw

/// <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 trasformazioni di visualizzazione e proiezione dalle informazioni sulla telecamera.

Per il terreno, il rettangolo disegnato in QuadDrawer viene visualizzato verticalmente, quindi viene ruotato per essere orizzontale e ingrandito moderatamente. _quadDrawer.DrawQuad Il secondo argomento del metodo specifica il numero di ripetizioni della trama, che specifica che i fogli 32x32 appaiono fianco a fianco.

_cat e _dog sono cartelloni pubblicitari internamente, quindi le informazioni sulla posizione della telecamera vengono passate e disegnate.

Metodo HandleInput

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

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

Le informazioni sulla tastiera e sul gamepad vengono acquisite e viene determinata la fine del gioco.

Metodo 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 telecamera è controllata per muoversi.

Include anche calcoli come l'accelerazione e l'attrito, ma penso che probabilmente stia tenendo conto dell'effetto Doppler sul suono 3D. Dal momento che non faccio nulla di speciale sul calcolo stesso, non ne discuterò.

Sommario

L'ho trattato a lungo, ma di solito è sufficiente fare riferimento alla classe per AudioManager come riprodurre il suono 3D. In effetti, la maggior parte delle difficoltà sono fatte dal framework, perché quello che SoundEffectInstance stiamo facendo è impostare le informazioni 3D in . Se hai campionato solo le parti del suono 3D, finirai per scrivere un po 'di lavoro nella classe Game. Tuttavia, sto scrivendo Suggerimenti basati sulla storia originale, quindi è stato molto più lungo.