Audio3D

Pagina actualizată :
Data creării paginii :

Note cu privire la acest Sfaturi

Acest eșantion se bazează pe programele publicate pe următoarele site-uri. Am schimba codul un pic pentru a face mai ușor să înțeleagă și să explice în japoneză. Practic, folosim codul original așa cum este, așa că, dacă îl adoptați efectiv în programul de joc, corectați-l în timp util și utilizați-l.

Site-ul de referință

În plus, se explică pe presupunerea că aveți câteva cunoștințe de bază despre MonoGame și XNA. A se vedea MonoGame Sfaturi și XNA Sfaturi pentru ruddly.

În special, deoarece matematica, vectorii, funcțiile trigonometrice, matricile etc. sunt esențiale, așa că vă rugăm să știți care sunt acestea într-o anumită măsură.

mediu

peron
  • Windows 10
  • Codul poate fi utilizat pe alte platforme compatibile cu MonoGame
Visual Studio
  • Visual Studio 2019
.NET Core
  • 3.1
MonoGame
  • 3.8

Despre probe

Pe baza poziției camerei, puteți auzi apelul din poziția câinelui și poziția pisicii. Pisica cercuri și cercuri de origine, iar player-ul poate controla poziția camerei cu cheia. Asigurați-vă că modul în care auziți sunetul se schimbă odată cu fiecare schimbare a poziției camerei sau a poziției pisicii. Cred că este ușor de înțeles folosind căști. Sunt neconfirmat pe canalul 5.1.

Cum să operezi

Ce este de a face Tastatura Gamepad (XInput) Mouse Touch
Cameră înainte și înapoi ↑↓ Stick stânga (sus și jos) - -
Modificarea orientării camerei ←→ Stick stânga (stânga și la dreapta) - -
Sfârșitul jocului Esc Spate - -

Ce să pregătești

  • Câine scârțâit fișier audio
  • Trei cat squeal fișiere audio
  • Fișier imagine câine
  • Fișier imagine pisică
  • Fișier imagine la sol

Eșantionul original de pe site-ul oficial utilizează fișiere .xnb de conținut predefinite. Dacă doriți să păstrați eșantioanele pe site-ul oficial, nu utilizați mgcbs, adăugați-le direct la soluția Visual Studio și copiați-le la momentul construirii.

Nu știu de ce eșantionul original ia această metodă, dar cred că este probabil pentru că migrăm versiuni mai vechi ale proiectului așa cum este. Desigur, puteți utiliza mgcb pentru a genera același fișier. Proiectele care pot fi descărcate de pe acest site au fost modificate la versiunea MGCB.

program

Descărcați programul pentru tot codul.

Acest eșantion este conceput pentru a face codul să arate puțin mai general, făcând în același timp redarea sunetului să arate bine la momentul rulării. Utilizarea Audio3D numai ar fi mult mai puțin cod, dar este descris de-a lungul eșantionului original. Voi păstra părțile mai puțin importante.

Proiectul este format din următoarele fișiere de cod:

  • Audio3DGame
  • AudioManager
  • Pisică
  • Câine
  • IAudioEmitter
  • Program
  • QuadDrawer
  • SpriteEntity

Clasa QuadDrawer

Această clasă este o clasă de ajutor pentru desenarea poligoanelor dreptunghiulare. Poligoanele dreptunghiulare sunt adesea folosite în principal pentru a afișa sprite 3D (panouri publicitare). Aceste sfaturi sunt utilizate pentru panouri publicitare pentru pisici și câini, precum și pentru afișajele dreptunghiulare ale solului.

Această clasă nu are nimic de-a face cu Audio3D.

câmp

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

Informații minime necesare pentru a desena poligoane. Desenați poligoane din datele nodurilor fără a pregăti datele modelului.

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

Deoarece această clasă este universal utilizabilă, primiți GraphicsDevice o instanță creată în procesul de inițializare a clasei de joc.

Aici, am stabilit efectul necesar pentru a desena spritul și poziția celor 4 noduri necesare pentru poligonul dreptunghiular. Dimensiunea ar trebui să fie scalate atunci când desenați, deci este -1 la 1.

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

Setează textura trecută la un dreptunghi și o desenează. Deoarece acesta este un proces de bază, nu este nimic de remarcat.

Dacă există un punct, o variabilă apelată poate fi specificată în textureRepeats argument, astfel încât coordonatele texturii să poată fi modificate. Dacă vertexPositionTexture.TextureCoordinate este setat dincolo de intervalul de la 0 la 1, textura este desenată în mod repetat în mod implicit. Folosind-o, este posibil să se exprime faptul că plăcile pot fi aranjate în mod repetat. De fapt, modelele în carouri de pe teren par să aibă mai multe imagini simple alb-negru aliniate.

Interfața IAudioEmitter

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

Definită ca o entitate care emite sunet. Deoarece entitățile care emit sunet de data aceasta sunt câini și pisici, ele sunt moștenite în clasele lor respective. Emițătorul are nevoie de următoarele informații:

Utilizarea proprietății
Poziție Poziția entității
Înainte Direcția cu care se confruntă entitatea (vector)
Sus Partea de sus a entității. Direcția în care capul există într-o persoană
Velocitate Viteza cu care se mișcă entitatea. Se utilizează pentru a calcula valorile Doppler.

Clasa SpriteEntity

O clasă pentru reprezentarea spritelor 3D (panouri publicitare). Este, de asemenea, un emițător și moștenește IAudioEmitter . Câinii și pisicile moștenesc această clasă.

proprietate

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

Are informațiile despre locația entității etc. Practic am informații ca emițător. Este, de asemenea, o entitate de desen, deci are și o imagine (Textură) de afișat.

Metoda de actualizare

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

Descrie poziția entității și procesul de redare a sunetului, dar îl implementează în clasa derivată.

Metoda desenării

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

Câinii și pisicile au imagini și poziții diferite, dar celălalt mecanism de desen este exact același, așa că le descriu aici.

Fiecare transformare și textură este transmisă la QuadDrawer pentru a afișa un poligon dreptunghiular. Deoarece transformarea coordonatelor este o cunoaștere de bază, explicațiile nu sunt acoperite.

Matrix.CreateConstrainedBillboard Utilizați metoda și informațiile camerei pentru a reprezenta cu ușurință panourile publicitare, astfel încât să le utilizați în mod eficient.

Clasa câinilor

Este o clasă care face desen de câine și cântând redare. SpriteEntity Moștenirea clasei. Câinele rămâne într-o poziție fixă în spațiu 3D.

câmp

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

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

_timeDelay este folosit la intervale de timp pentru a juca strigătul.

SoundEffectInstance _activeSound este un exemplu pentru redarea unui sunet. SoundEffectInstance După cum veți vedea adesea în clasa de redare a sunetului, puteți utiliza acest lucru așa cum este în sunetul 3D. Apropo _activeSound , primesc doar o referință de la clasa AudioManager mai târziu, așa că nu o voi arunca pe partea de clasă Dot.

Metoda de actualizare

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

În acest eșantion, câinele rămâne în aceeași poziție pentru o lungă perioadă de timp, astfel încât primii patru parametri sunt specificați printr-o lovitură decisivă. Desenul se face în clasa de bază.

_timeDelay este apoi folosit ca timpul rămas pentru a opri, joc strigăt.

AudioManager va fi reprodus înPlay3DSound spațiu 3D prin trecerea numelui strigătului, a informațiilor de buclă și a propriilor informații ca emițător la .

Clasa Dog este conceput pentru a bucla strigăt, astfel încât să nu trebuie să se gândească prea profund, deoarece este doar o ajustare, cum ar fi joc sau oprirea ramificare.

Clasa de pisici

Este o clasă care face desen de pisică și redare cântând. SpriteEntity Moștenirea clasei. Pisica se mișcă în jurul originii.

câmp

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

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

_timeDelay este folosit în același mod ca și clasa Dog, cu restul timpului înainte de următorul scârțâit.

Există trei tipuri de apeluri pisică care sunt selectate aleatoriu și redate, dar nu au nimic de-a face cu Audio3D, deoarece acestea sunt un element bonus.

Metoda de actualizare

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

Deoarece pisica întoarce originea într-o mișcare circulară, o procesează astfel încât să miște traiectoria cercului folosind o funcție trigonometrică. Ca urmare, poziția, înainte și viteza s-au schimbat una după alta. Prin urmare, atunci când rulați programul, puteți vedea că strigătul pisicii se învârte în jurul chiar dacă nu mutați camera.

_timeDelay Următorul cod este un proces în care strigătul pisicii este atribuit aleatoriu și jucat la intervale regulate. audioManager.Play3DSound Mă transmit metodei care este un emițător. Puteți vedea că poziția de redare a sunetului se schimbă unul câte unul.

Clasa AudioManager

Aceasta este în cele din urmă esența Audio3D. Un sunet 3D este format dintr-un ascultător și un emițător. Emițătorul definește deja câinii și pisicile, astfel încât clasa AudioManager definește ascultătorii. Există, de obicei, mai mulți emițători, în timp ce există un singur ascultător.

Această clasă moștenește șiGame înregistrează GameComponent și utilizează componenta din clasă.

Clasa ActiveSound

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

Este definit în partea de jos a codului, dar este o clasă pentru păstrarea stării care se joacă. Are informații despre instanța de sunet redată și emițătorul redat.

câmp

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 definește numele fișierului audio (numele activului) de încărcat. Deoarece este un program eșantion, este definit pentru a încărca fișierul audio în vrac mai întâi. Datele _soundEffects sonore importate sunt stocate în .

AudioListener Listener este definiția ascultătorului. Informațiile ascultătorului sunt definite deoarece sunt public setate din clasa Joc.

AudioEmitter _emitter este definiția emițătorului atunci când se aplică 3D la redarea sunetului. În acest eșantion, atunci când redați un sunet, valoarea fiecărui obiect emițător este setată la _emitter , deci este o formă care partajează unul ca instanță. Desigur, puteți avea pentru fiecare AudioEmitter obiect.

_activeSounds are informații despre sunetul pe care îl redați în clasa pe care ați definit-o ActiveSound mai devreme. Deoarece informațiile despre emițător se schimbă tot timpul, acestea sunt utilizate pentru a actualiza informațiile despre locație etc., și pentru a renunța la instanțele de sunet care au terminat de redat.

constructor

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

GameComponent Din moment ce moștenește clasa, Game primește instanța și o transmite clasei de bază.

Metoda de inițializare

/// <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 Deoarece moștenește clasa, este numită automat la inițializare.

SoundEffect.DistanceScale și SoundEffect.DopplerScale sunt parametri dedicați static sunetului 3D.

SoundEffect.DistanceScale pentru a auzi sunetul chiar și în depărtare.

SoundEffect.DopplerScale este influența efectului Doppler. Cu cât numărul este mai mare, cu atât efectul Doppler este mai mare.

_soundNames Salvați numele activului definit într-o buclă pentru a încărca _soundEffects .

Metoda de eliminare

/// <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 Acesta este numit automat la sfârșitul jocului, deoarece moștenește clasa.

Distrugerea tuturor activelor sonore importate.

Metoda de actualizare

/// <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 Deoarece moștenește clasa, este apelată automat în procesul de actualizare.

Verificați sunetul redat în prezent și, dacă este Apply3D redat, apelați metoda pentru a actualiza locația sunetului pentru a se potrivi cu emițătorul. Dacă un sunet a terminat de redat, instanța este eliminată.

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

Procesul de redare a sunetului 3D din exterior. Are numele sunetului de redat, dacă să buclă și informații emițător.

Dacă doriți să redați un sunet, creați o nouă instanță de sunet din resursa de sunet pe care o păstrați în _soundEffects. SoundEffectInstance poate avea, de asemenea, o buclă sau nu, deci setați informațiile despre buclă.

Din moment ce eu sunt crearea ca ActiveSound o stare de joc, am stabilit emitter de informații, care este obiectul de redare a sunetului acolo. Dacă doriți să aplicați informațiile despre locația 3D la un sunet, veți Emitter obține valoarea de care aveți nevoie.

Apply3D Metoda este descrisă mai jos, dar este procesul de aplicare a informațiilor 3D de la emițător la sunet.

Procesul de bază al sunetului 3D este de a începe redarea cu SoundEffectInstance.Play setul de informații 3D. Restul este de a actualiza informațiile 3D periodic până când sunetul este terminat de redat.

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

Procesul de aplicare a unui efect 3D la o instanță de sunet specificată folosind ascultători și emițători.

De fiecare dată, punem valoarea la _emitter instanței comune. Dacă aveți SoundEffectInstance.Apply3D deja AudioEmitter unul, pur și simplu treceți ascultătorul și emițătorul la metodă.

Clasa Audio3DGame

În cele din urmă, să ne uităm la ceea ce clasa de joc este de aproximativ.

câmp

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 Se înregistrează în , dar îl are ca câmp, deoarece îl accesează individual.

Altele definesc câine, entități pisică, texturi pentru desen la sol, quaddrawer, informații aparat de fotografiat, și informații de intrare.

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 Generați și GameComponents înregistrați-vă cu .

Ați generat, de asemenea, clasele de pisici și câini.

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

Încărcați texturile necesare pentru fiecare desen.

QuadDrawer este GraphicsDevice generat aici pentru că necesită .

Metoda de actualizare

/// <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 Metodele și UpdateCamera metodele sunt procesul de recuperare a intrării dispozitivului și de manipulare a camerei, care va fi discutat mai târziu.

Deoarece poziția camerei și poziția ascultătorului sunt aproape întotdeauna aceleași, ascultătorul este setat la aceeași valoare după procesul de actualizare a camerei.

_cat Apelați și _dog actualizați metodele pentru a vă deplasa și, respectiv, a scârțâi.

Metoda desenării

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

Generează transformări de vizualizare și proiecție din informațiile camerei.

Pentru sol, dreptunghiul desenat în QuadDrawer este afișat vertical, astfel încât acesta este rotit pentru a fi orizontal și mărit moderat. _quadDrawer.DrawQuad Al doilea argument al metodei specifică numărul de repetări ale texturii, care specifică faptul că foile 32x32 apar una lângă alta.

_cat și _dog sunt panouri publicitare intern, astfel încât informațiile despre locația camerei sunt transmise și extrase.

Metoda HandleInput

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

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

Informațiile de pe tastatură și gamepad sunt achiziționate, iar sfârșitul jocului este determinat.

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

Camera este controlată pentru a se deplasa.

De asemenea, include calcule precum accelerația și frecarea, dar cred că probabil ține cont de efectul Doppler asupra sunetului 3D. Din moment ce nu fac nimic special despre calculul în sine, nu voi discuta.

Rezumat

L-am acoperit pe larg, dar de obicei este suficient să se refere la clasă pentru AudioManager modul de a reda sunet 3D. De fapt, majoritatea dificultăților sunt făcute de cadru, deoarece ceea ce SoundEffectInstance facem este să punem informații 3D în . Dacă ați eșantionat doar părțile sunetului 3D, veți ajunge să scrieți puțină lucrare în clasa Joc. Cu toate acestea, scriu Sfaturi bazate pe povestea originală, așa că a fost mult mai mult timp.