Audio3D

Oldal frissítve :
Oldal létrehozásának dátuma :

Megjegyzések ehhez a tippekhez

Ez a minta a következő webhelyeken közzétett programokon alapul. Egy kicsit megváltoztatom a kódot, hogy könnyebben érthető és megmagyarázható legyen japánul. Alapvetően az eredeti kódot úgy használjuk, ahogy van, tehát ha valóban elfogadja a játékprogramjában, javítsa ki időben, és használja.

Hivatkozási hely

Ezenkívül azzal a feltételezéssel magyarázható, hogy van néhány alapvető ismerete a MonoGame-ről és az XNA-ról. Lásd MonoGame tippek és XNA tippek a ruddly.

Különösen, mivel a matematika, a vektorok, a trigonometrikus függvények, a mátrixok stb. elengedhetetlenek, ezért kérjük, bizonyos mértékig tudják, mik azok.

környezet

peron
  • Windows 10
  • A kód más MonoGame-kompatibilis platformokon is használható
Visual Studio
  • Visual Studio 2019
.NET mag
  • 3.1
MonoGame
  • 3.8

Néhány szó a mintákról

A kamera helyzete alapján a kutya helyzetéből és a macska helyzetéből hallhatja a hívást. A macska körbejárja és körbejárja az eredetét, és a játékos a kulccsal vezérelheti a kamera helyzetét. Győződjön meg arról, hogy a hang hallásának módja megváltozik a kamera pozíciójának vagy a macska helyzetének minden egyes változásával. Úgy gondolom, hogy a fülhallgató használatával könnyű megérteni. Az 5.1-es csatornán még nem erősítettek meg.

Hogyan kell működtetni

Mi a teendő Billentyűzet Gamepad (XInput) Egér érintés
Kamera előre és hátra ↑↓ Bal bot (felső és alsó) - -
Kamera tájolásának módosítása ←→ Bal bot (bal és jobb) - -
A játék vége Esc Hát - -

Mit kell készíteni

  • Kutya sikoltozás hangfájlja
  • Három macska sikoltozó hangfájl
  • Kutya képfájl
  • Macska képfájl
  • Földi képfájl

A hivatalos webhelyen található eredeti minta előre elkészített .xnb fájlokat használ. Ha a mintákat a hivatalos webhelyen szeretné tartani, ne használjon mgcbs-t, adja hozzá őket közvetlenül a Visual Studio megoldásához, és másolja őket a létrehozáskor.

Nem tudom, miért az eredeti minta veszi ezt a módszert, de azt hiszem, ez valószínűleg azért van, mert migrrating régebbi változatai a projekt, ahogy van. Természetesen az mgcb segítségével ugyanazt a fájlt hozhatja létre. Az ezen az oldalon letölthető projektek az MGCB verzióra módosultak.

program

Töltse le a programot az összes kódhoz.

Ezt a mintát úgy tervezték, hogy a kód egy kicsit általánosabbnak tűnjön, miközben a hanglejátszás jól néz ki futásidőben. Az Audio3D használata csak sokkal kevesebb kód lenne, de az eredeti minta mentén van leírva. Megtartom a kevésbé fontos részeket.

A projekt a következő kódfájlokból áll:

  • Audio3DGame
  • AudioManager
  • Macska
  • Kutya
  • IAudioEmitter
  • Program
  • Négyhengeres
  • SpriteEntity

QuadDrawer osztály

Ez az osztály egy segítő osztály téglalap alakú sokszögek rajzolásához. A téglalap alakú sokszögeket gyakran elsősorban 3D-sprite (hirdetőtáblák) megjelenítésére használják. Ezt a tippet macskák és kutyák hirdetőtábláihoz, valamint a talaj téglalap alakú kijelzőihez használják.

Ennek az osztálynak semmi köze az Audio3D-hez.

mező

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

A sokszögek rajzolásához szükséges minimális információ. Rajzoljon sokszögeket a csúcspontadatokból modelladatok előkészítése nélkül.

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

Mivel ez az osztály általánosan használható, a GraphicsDevice játékosztály inicializálási folyamatában létrehozott példányt kap.

Itt beállítjuk a sprite rajzolásához szükséges hatást és a téglalap alakú sokszöghez szükséges 4 csúcs helyzetét. A méretet rajzoláskor kell méretezni, így -1 az 1-hez.

DrawQuad metódus

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

Az átadott textúrát téglalapra állítja, és rajzolja. Mivel ez egy alapvető folyamat, nincs mit megjegyezni.

Ha van egy pont, az argumentumban textureRepeats megadhat egy hívott változót, hogy a textúra koordinátái módosíthatók legyenek. Ha a csúcspontPositionTexture.TextureCoordinate értéke meghaladja a 0-tól 1-ig terjedő tartományt, a textúra alapértelmezés szerint többször is megrajzolódik. Használatával kifejezhető, hogy a csempe többször is elrendezhető. Valójában úgy tűnik, hogy a földön lévő kockás minták több egyszerű fekete-fehér képpel rendelkeznek.

IAudioEmitter felület

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

Olyan entitásként definiálva, amely hangot bocsát ki. Mivel azok az entitások, amelyek ezúttal hangot bocsátanak ki, kutyák és macskák, a saját osztályukban öröklődnek. Az emitternek a következő információkra van szüksége:

Tulajdonsághasználat
Pozíció Entitás pozíciója
Előre Az az irány, amellyel az entitás szembesül (vektor)
Fel Az entitás felemelkedése. Az az irány, amelyben a fej létezik egy személyben
Sebesség Az a sebesség, amellyel az entitás mozog. A Doppler-értékek kiszámításához használatos.

SpriteEntity osztály

A 3D-sprite (hirdetőtáblák) képviseletére szolgáló osztály. Ez is kibocsátó, és örökli IAudioEmitter . A kutyák és a macskák öröklik ezt az osztályt.

ingatlan

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

Rendelkezik az entitás helyadataival stb. Alapvetően van információm kibocsátóként. Ez is egy rajz entitás, így van egy kép (Textúra) is, amelyet meg kell jeleníteni.

Frissítési módszer

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

Leírja az entitás helyzetét és a hang lejátszásának folyamatát, de megvalósítja azt a származtatott osztályban.

Rajzolási módszer

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

A kutyáknak és macskáknak különböző képük és pozíciójuk van, de a másik rajzmechanizmus pontosan ugyanaz, ezért itt leírom őket.

Minden átalakítást és textúrát átadnak a QuadDrawernek egy téglalap alakú sokszög megjelenítéséhez. Mivel a koordináta-transzformáció alapvető tudás, a magyarázatok nem tartoznak ide.

Matrix.CreateConstrainedBillboard Használja a módszert és a kamera adatait a hirdetőtáblák egyszerű ábrázolásához, ezért hatékonyan használja ki őket.

Kutya osztály

Ez egy olyan osztály, amely kutyarajzolást és éneklejátszást végez. SpriteEntity Az osztály megörökölése. A kutya rögzített helyzetben marad 3D-s térben.

mező

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

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

_timeDelay a kiáltás lejátszására használják.

SoundEffectInstance _activeSound példa egy hang lejátszására. SoundEffectInstance Amint azt a hanglejátszás osztályában gyakran látni fogja, ezt ugyanúgy használhatja, mint a 3D-s hangban. By the way _activeSound , én csak kap egy referenciát az AudioManager osztály később, így nem fogom dobni, hogy a Dot osztály oldalán.

Frissítési módszer

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

Ebben a mintában a kutya hosszú ideig ugyanabban a helyzetben marad, így az első négy paramétert döntő csapás határozza meg. A rajzolás az alaposztályban történik.

_timeDelay ezután a fennmaradó időként használják a megállásra, a kiáltás lejátszására.

AudioManager 3D-s térben reprodukálódikPlay3DSound a cry, a hurokinformációk és a saját információk nevének kibocsátóként történő átadásával.

A Dog osztályt úgy tervezték, hogy hurkolja a sírást, így nem kell túl mélyen gondolkodnia, mert ez csak egy beállítás, például játék vagy elágazás leállítása.

Macska osztály

Ez egy olyan osztály, amely macskarajzolást és éneklést végez. SpriteEntity Az osztály megörökölése. A macska az eredet körül mozog.

mező

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

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

_timeDelay ugyanúgy használják, mint a Kutya osztályt, a többi időt a következő sikítás előtt.

Háromféle macskahívás létezik, amelyeket véletlenszerűen választanak ki és játszanak le, de semmi közük az Audio3D-hez, mert bónusz elem.

Frissítési módszer

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

Mivel a macska körkörös mozgásban fordul meg az origó körül, úgy dolgozza fel, hogy trigonometrikus függvény segítségével mozgassa a kör pályáját. Ennek eredményeként a pozíció, az előre és a sebesség egymás után változott. Ezért a program futtatásakor láthatja, hogy a macska sírása körbejár, még akkor is, ha nem mozgatja a kamerát.

_timeDelay A következő kód egy olyan folyamat, amelyben a macska sírását véletlenszerűen rendelik hozzá és rendszeres időközönként játsszák le. audioManager.Play3DSound Átadom magam annak a módszernek, ami egy emitter. Láthatja, hogy a hang lejátszási pozíciója egyenként változik.

AudioManager osztály

Ez végre az Audio3D lényege. A 3D-s hang egy hallgatóból és egy kibocsátóból áll. Az emitter már meghatározza a kutyákat és macskákat, így az AudioManager osztály határozza meg a hallgatókat. Általában több kibocsátó van, míg csak egy hallgató van.

Ez az osztály örökli ésGame regisztrálja GameComponent és használja az osztály összetevőjét.

ActiveSound osztály

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

A kód alján van definiálva, de ez egy osztály a lejátszott állapot megőrzésére. Információval rendelkezik a lejátszott hangpéldányról és a lejátszott kibocsátóról.

mező

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 meghatározza a betöltendő hangfájl nevét (eszköz nevét). Mivel ez egy mintaprogram, úgy van definiálva, hogy először tömegesen töltse be az audiofájlt. Az importált hangadatokat a _soundEffects rendszer tárolja a rendszerben.

AudioListener Listener A hallgató definíciója. A figyelő adatai azért vannak definiálva, public mert a Játék osztályból vannak beállítva.

AudioEmitter _emitter az emitter definíciója, amikor 3D-t alkalmaz a hanglejátszásra. Ebben a mintában hang lejátszásakor az egyes emitterobjektumok értéke a következőre _emitter van állítva: így ez egy olyan űrlap, amely példányként osztozik. Természetesen minden AudioEmitter objektumhoz lehet.

_activeSounds információt tartalmaz arról a hangról, amelyet a korábban definiált osztályban játszik le ActiveSound . Mivel az emitter-információ folyamatosan változik, a helyadatok frissítésére stb. szolgál, és a lejátszott hangpéldányok elvetésére szolgál.

Konstruktor

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

GameComponent Mivel örökli az osztályt, megkapja a példányt, Game és átadja az alaposztálynak.

Metódus inicializálása

/// <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 Mivel örökli az osztályt, az inicializáláskor automatikusan meghívják.

SoundEffect.DistanceScale és SoundEffect.DopplerScale a 3D-s hangnak static szentelt paraméterek.

SoundEffect.DistanceScale hogy a hang még a távolban is halljon.

SoundEffect.DopplerScale A Doppler-effektus hatása. Minél nagyobb a szám, annál nagyobb a Doppler-hatás.

_soundNames A betöltendő hurokban definiált eszköznév mentése _soundEffects .

Megsemmisítési módszer

/// <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 A játék végén automatikusan meghangzik, mert örökli az osztályt.

Megsemmisíti az összes importált hangeszközt.

Frissítési módszer

/// <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 Mivel örökli az osztályt, a rendszer automatikusan meghívja a frissítési folyamatban.

Ellenőrizze az aktuálisan lejátszott hangot, és ha Apply3D játszik, hívja meg a hang helyének frissítésére szolgáló módszert, hogy megfeleljen az emitternek. Ha bármelyik hang lejátszása befejeződött, a példány elvetésre kerül.

Play3DSound módszer

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

A 3D-s hang kívülről történő lejátszásának folyamata. A lejátszandó hang neve, hurok és kibocsátó információk.

Ha hangot szeretne lejátszani, hozzon létre egy új hangpéldányt a _soundEffects tárolt hangerőforrásból. SoundEffectInstance lehet hurok is, vagy sem, ezért állítsa be a hurokinformációt.

Mivel lejátszási állapotként ActiveSound hozok létre, beállítom az emitter információt, amely a hang lejátszási objektuma. Ha 3D-s helyadatokat szeretne alkalmazni egy hangra, megkapja Emitter a szükséges értéket.

Apply3D A módszert az alábbiakban ismertetjük, de ez az a folyamat, amelynek során a kibocsátótól származó 3D-s információkat a hangra alkalmazzák.

A 3D hang alapvető folyamata a lejátszás megkezdése 3D-s információkészlettel SoundEffectInstance.Play . A többi az, hogy rendszeresen frissítse a 3D-s információkat, amíg a hang lejátszása be nem fejeződik.

Apply3D metódus

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

A 3D-s effektus meghatározott hangpéldányra történő alkalmazásának folyamata hallgatók és kibocsátók segítségével.

Az értéket minden alkalommal a közös példány _emitter állítjuk be. Ha SoundEffectInstance.Apply3D már AudioEmitter van ilyen, egyszerűen adja át a hallgatót és az emittert a módszernek.

Audio3DGame osztály

Végül nézzük meg, miről szól a játékosztály.

mező

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 Regisztrál a GameComponents rendszerben, de mezőként van, mert egyénileg fér hozzá.

Mások meghatározzák a kutya- és macska entitásokat, a talajrajz textúráit, a négykvadránsokat, a kamerainformációkat és a bemeneti információkat.

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 Generáljon és GameComponents regisztráljon a következővel: .

Létrehoztad a macska- és kutyaórákat is.

LoadContent metódus

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

Töltse be az egyes rajzokhoz szükséges textúrákat.

QuadDrawer itt jön létre, GraphicsDevice mert megköveteli.

Frissítési módszer

/// <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 A módszerek és UpdateCamera módszerek az eszköz bemenetének lekérésének és a kamera kezelésének folyamata, amelyet később tárgyalunk.

Mivel a kamera helyzete és a figyelő pozíciója szinte mindig azonos, a figyelő a kamerafrissítési folyamat után ugyanarra az értékre van állítva.

_cat Hívja meg a és _dog a Frissítési módszereket az áthelyezéshez és a sikításhoz.

Rajzolási módszer

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

Nézet- és vetítési átalakításokat hoz létre a kamera adataiból.

A talaj esetében a QuadDrawerben rajzolt téglalap függőlegesen jelenik meg, így vízszintesen forog, és mérsékelten nagyítva van. _quadDrawer.DrawQuad A metódus második argumentuma a textúra ismétléseinek számát határozza meg, amely azt határozza meg, hogy a 32x32 lap egymás mellett jelenjen meg.

_cat és _dog belsőleg hirdetőtáblával vannak ellátva, így a kamera helyadatait továbbítják és rajzolják.

HandleInput metódus

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

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

A billentyűzeten és a gamepaden található információk beszerzése megtörténik, és a játék vége meghatározásra kerül.

UpdateCamera metódus

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

A kamera mozgásra van vezérelve.

Olyan számításokat is tartalmaz, mint a gyorsulás és a súrlódás, de azt hiszem, valószínűleg figyelembe veszi a Doppler-hatást a 3D-s hangra. Mivel nem teszek semmi különöset magával a számítással kapcsolatban, nem fogom megvitatni.

Összefoglalás

Hosszasan lefedtem, de általában elég ahhoz, hogy az osztályra utaljak a 3D-s hang lejátszásához AudioManager . Valójában a legtöbb nehézséget a keretrendszer végzi, mert amit SoundEffectInstance csinálunk, az a 3D-s információk beállítása a rendszerbe. Ha csak a 3D-s hang részeit kóstolta meg, akkor végül egy kis munkát fog írni a Játék osztályban. Azonban az eredeti történet alapján írok tippeket, így sokkal hosszabb volt.