Audio3D

Side opdateret :
Dato for oprettelse af side :

Bemærkninger til dette tip

Denne prøve er baseret på de programmer, der er offentliggjort på følgende websteder. Jeg ændrer koden lidt for at gøre det lettere at forstå og forklare det på japansk. Grundlæggende bruger vi den originale kode, som den er, så hvis du rent faktisk vedtager den i dit spilprogram, skal du rette den rettidigt og bruge den.

Reference websted

Derudover forklares det ud fra den antagelse, at du har en vis grundlæggende viden om MonoGame og XNA. Se MonoGame Tips og XNA Tips for ruddly.

Især da matematik, vektorer, trigonometriske funktioner, matricer osv. er afgørende, så vær venlig at vide, hvad de er til en vis grad.

miljø

perron
  • Vinduer 10
  • Kode kan bruges på andre MonoGame-aktiverede platforme
Visual Studio
  • Visual Studio 2019
.NET-kerne
  • 3.1
Monogame
  • 3.8

Om prøver

Baseret på kameraets position kan du høre opkaldet fra hundens position og kattens position. Katten cirkler og cirkler oprindelsen, og spilleren kan styre kameraets position med nøglen. Sørg for, at den måde, du hører lyden på, ændres med hver ændring i kameraets position eller kattens position. Jeg tror, at det er let at forstå ved hjælp af øretelefoner. Jeg er ikke bekræftet på kanal 5.1.

Sådan betjenes

Hvad skal man gøre Keyboard Gamepad (XInput) Mouse Touch
Kamera frem og tilbage ↑↓ Venstre pind (øverst og nederst) - -
Skift kameraretning ←→ Venstre pind (venstre og højre) - -
Slutningen af spillet Esc Ryg - -

Hvad skal man forberede sig på?

  • Hund hviner lydfil
  • Tre katte hviner lydfiler
  • Hund billedfil
  • Kat billedfil
  • Jordbillede fil

Den oprindelige prøve på det officielle websted bruger forudbyggede . xnb-filer . Hvis du vil beholde eksemplerne på det officielle websted, skal du ikke bruge mgcbs, føje dem direkte til din Visual Studio-løsning og kopiere dem på buildtidspunktet.

Jeg ved ikke, hvorfor den oprindelige prøve tager denne metode, men jeg tror, det sandsynligvis skyldes, at vi migrerer ældre versioner af projektet, som det er. Selvfølgelig kan du bruge mgcb til at generere den samme fil. De projekter, der kan downloades på dette websted, er blevet ændret til MGCB-versionen.

program

Download programmet til al koden.

Denne prøve er designet til at få koden til at se lidt mere generel ud, samtidig med at lydafspilningen ser godt ud ved kørsel. Brug af Audio3D kun ville være meget mindre kode, men det er beskrevet langs den originale prøve. Jeg beholder de mindre vigtige dele.

Projektet består af følgende kodefiler:

  • Audio3DGame
  • AudioManager
  • Kat
  • Hund
  • IAudioEmitter
  • Program
  • QuadDrawer
  • SpriteEntity

QuadDrawer klasse

Denne klasse er en hjælperklasse til tegning af rektangulære polygoner. Rektangulære polygoner bruges ofte primært til at vise 3D-sprites (billboards). Disse tips bruges til reklametavler til katte og hunde samt til rektangulære skærme af jorden.

Denne klasse har intet at gøre med Audio3D.

mark

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

Minimumsoplysninger, der kræves for at tegne polygoner. Tegn polygoner fra toppunktsdata uden at forberede modeldata.

konstruktør

/// <summary>
/// 新しい四辺形の描画ワーカーを作成します。
/// </summary>
public QuadDrawer(GraphicsDevice device)
{
  _graphicsDevice = device;

  _effect = new AlphaTestEffect(device);

  _effect.AlphaFunction = CompareFunction.Greater;
  _effect.ReferenceAlpha = 128;

  // 4つの頂点の配列を事前に割り当てます。
  _vertices = new VertexPositionTexture[4];

  _vertices[0].Position = new Vector3(1, 1, 0);
  _vertices[1].Position = new Vector3(-1, 1, 0);
  _vertices[2].Position = new Vector3(1, -1, 0);
  _vertices[3].Position = new Vector3(-1, -1, 0);
}

Da denne klasse er universelt anvendelig, modtager du GraphicsDevice en forekomst, der er oprettet i initialiseringsprocessen for spilklassen.

Her indstiller vi den effekt, der er nødvendig for at tegne sprite og placeringen af de 4 hjørner, der kræves til den rektangulære polygon. Størrelsen skal skaleres, når du tegner, så den er -1 til 1.

DrawQuad metode

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

Indstiller den beståede tekstur til et rektangel og tegner den. Da dette er en grundlæggende proces, er der intet at bemærke.

Hvis der er et punkt, kan en variabel kaldet specificeres i textureRepeats argumentet, så koordinaterne for tekstur kan ændres. Hvis vertexPositionTexture.TextureCoordinate er indstillet ud over området 0 til 1, tegnes teksturen gentagne gange som standard. Ved hjælp af det er det muligt at udtrykke, at fliser kan arrangeres gentagne gange. Faktisk ser de ternede mønstre på jorden ud til at have flere enkle sort-hvide billeder opstillet.

IAudioEmitter interface

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

Defineret som en enhed, der udsender lyd. Da de enheder, der udsender lyd denne gang, er hunde og katte, arves de i deres respektive klasser. Emitter har brug for følgende oplysninger:

Ejendom brug
Position Enhedens position
Fremad Den retning, objektet vender mod (vektor)
Opad Op af enheden. Den retning, hvor hovedet eksisterer i en person
Hastighed Den hastighed, hvormed enheden bevæger sig. Bruges til at beregne Doppler-værdier.

SpriteEntity klasse

En klasse til repræsentation af 3D-sprites (billboards). Det er også en emitter, og arver IAudioEmitter . Hunde og katte arver denne klasse.

egenskab

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

Det har enhedens placeringsoplysninger osv. Dybest set har jeg oplysninger som udleder. Det er også en tegneenhed, så den har også et billede (tekstur) at vise.

Opdater metode

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

Beskriver virksomhedens position og processen med at afspille lyd, men implementerer den i den afledte klasse.

Tegn metode

/// <summary>
/// エンティティをビルボードスプライトとして描画します。
/// </summary>
public void Draw(QuadDrawer quadDrawer, Vector3 cameraPosition, Matrix view, Matrix projection)
{
  Matrix world = Matrix.CreateTranslation(0, 1, 0) *
                 Matrix.CreateScale(800) *
                 Matrix.CreateConstrainedBillboard(Position, cameraPosition, Up, null, null);

  quadDrawer.DrawQuad(Texture, 1, world, view, projection);
}

Hunde og katte har forskellige billeder og positioner, men den anden tegnemekanisme er nøjagtig den samme, så jeg beskriver dem her.

Hver transformation og tekstur overføres til QuadDrawer for at vise en rektangulær polygon. Da koordinattransformation er grundlæggende viden, er forklaringer ikke dækket.

Matrix.CreateConstrainedBillboard Brug metode- og kameraoplysninger til nemt at repræsentere reklametavler, så gør effektiv brug af dem.

Hundeklasse

Det er en klasse, der laver hundetegning og sangafspilning. SpriteEntity Arver klassen. Hunden forbliver i en fast position i 3D-rummet.

mark

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

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

_timeDelay bruges med mellemrum til at afspille råbet.

SoundEffectInstance _activeSound er et eksempel på afspilning af en lyd. SoundEffectInstance Som du ofte vil se i klassen af lydafspilning, kan du bruge dette som det er i 3D-lyd. _activeSound Forresten modtager jeg først en reference fra AudioManager-klassen senere, så jeg vil ikke kassere den på Dot-klassesiden.

Opdater metode

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

I denne prøve forbliver hunden i samme position i lang tid, så de første fire parametre er specificeret ved en afgørende strejke. Tegning sker i grundklassen.

_timeDelay bruges derefter som den resterende tid til at stoppe og afspille råbet.

AudioManager vil blive gengivet i 3D-rum ved at videregive navnet på råbetPlay3DSound , loop information og dine egne oplysninger som emitter til .

Hundeklassen er designet til at sløjfe gråden, så du ikke behøver at tænke for dybt, fordi det bare er en justering, såsom at lege eller stoppe forgreningen.

Kat klasse

Det er en klasse, der laver kattetegning og sangafspilning. SpriteEntity Arver klassen. Katten bevæger sig rundt om oprindelsen.

mark

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

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

_timeDelay bruges på samme måde som hundeklassen, med resten af tiden før næste hvin.

Der er tre typer katteopkald, der tilfældigt vælges og afspilles, men de har intet at gøre med Audio3D, fordi de er et bonuselement.

Opdater metode

/// <summary>
/// 猫の位置を更新し、音を鳴らします。
/// </summary>
public override void Update(GameTime gameTime, AudioManager audioManager)
{
  // 猫を大きな円で動かします。
  double time = gameTime.TotalGameTime.TotalSeconds;

  float dx = (float)-Math.Cos(time);
  float dz = (float)-Math.Sin(time);

  Vector3 newPosition = new Vector3(dx, 0, dz) * 6000;

  // エンティティの位置と速度を更新します。
  Velocity = newPosition - Position;
  Position = newPosition;
  if (Velocity == Vector3.Zero)
  {
    Forward = Vector3.Forward;
  }
  else
  {
    Forward = Vector3.Normalize(Velocity);
  }

  Up = Vector3.Up;

  // 時間遅延がなくなった場合は、別の単発音をトリガーします。
  _timeDelay -= gameTime.ElapsedGameTime;

  if (_timeDelay < TimeSpan.Zero)
  {
    // 異なる3つのサウンドバリエーション(CatSound0、CatSound1、CatSound2)からランダムに選択します。
    string soundName = "CatSound" + _random.Next(3);

    audioManager.Play3DSound(soundName, false, this);

    _timeDelay += TimeSpan.FromSeconds(1.25f);
  }
}

Da katten vender om oprindelsen i en cirkulær bevægelse, behandler den den, så den bevæger cirklens bane ved hjælp af en trigonometrisk funktion. Som følge heraf har position, fremad og hastighed ændret sig efter hinanden. Derfor, når du kører programmet, kan du se, at kattens råb cirkler rundt, selvom du ikke bevæger kameraet.

_timeDelay Følgende kode er en proces, hvor kattens råb tilfældigt tildeles og spilles med jævne mellemrum. audioManager.Play3DSound Jeg overgår mig selv til den metode, der er en emitter. Du kan se, at lydens afspilningsposition ændres en efter en.

AudioManager klasse

Dette er endelig essensen af Audio3D. En 3D-lyd består af en lytter og en emitter. Emitteren definerer allerede hunde og katte, så AudioManager-klassen definerer lyttere. Der er normalt flere emittere, mens der kun er en lytter.

Denne klasse arver ogGame registrerer GameComponent og bruger komponenten i klassen.

ActiveSound klasse

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

Det er defineret i bunden af koden, men det er en klasse til bevarelse af den tilstand, der spiller. Det har oplysninger om den lydforekomst, der afspilles, og emitteren, der afspilles.

mark

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 definerer navnet på den lydfil (aktivnavn), der skal indlæses. Da det er et eksempelprogram, er det defineret at indlæse lydfilen i bulk først. De importerede lyddata gemmes _soundEffects i .

AudioListener Listener er definitionen af lytteren. Lytteroplysninger er defineret i, fordi de public er indstillet fra spilklassen.

AudioEmitter _emitter er definitionen af emitteren, når du anvender 3D til lydafspilning. I denne prøve, når du afspiller en lyd, er værdien af hvert emitterobjekt indstillet til _emitter , så det er en formular, der deler en som en forekomst. Selvfølgelig kan du have for hvert AudioEmitter objekt.

_activeSounds har oplysninger om den lyd, du spiller i den klasse, du definerede ActiveSound tidligere. Da emitteroplysninger ændres hele tiden, bruges de til at opdatere placeringsoplysninger osv. og til at kassere lydforekomster, der er færdige med at afspille.

konstruktør

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

GameComponent Da den arver klassen, Game modtager den forekomsten og sender den til basisklassen.

Initialiser metode

/// <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 Fordi den arver klassen, kaldes den automatisk ved initialisering.

SoundEffect.DistanceScale og SoundEffect.DopplerScale er parametre dedikeret til static 3D-lyd.

SoundEffect.DistanceScale at høre lyd selv i det fjerne.

SoundEffect.DopplerScale er indflydelsen fra Doppler-effekten. Jo højere tallet er, desto større er Doppler-effekten.

_soundNames Gem det aktivnavn, der er defineret i, i en løkke for at indlæse _soundEffects .

Bortskaf metode

/// <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 Det kaldes automatisk i slutningen af spillet, fordi det arver klassen.

Ødelæggelse af alle importerede lydaktiver.

Opdater metode

/// <summary>
/// 3Dオーディオシステムの状態を更新します。
/// </summary>
public override void Update(GameTime gameTime)
{
  // 現在再生中のすべての3Dサウンドをループします。
  int index = 0;

  while (index < _activeSounds.Count)
  {
    ActiveSound activeSound = _activeSounds[index];

    if (activeSound.Instance.State == SoundState.Stopped)
    {
      // 音の再生が終了した場合は廃棄してください。
      activeSound.Instance.Dispose();

      // アクティブリストから削除します。
      _activeSounds.RemoveAt(index);
    }
    else
    {
      // サウンドがまだ再生されている場合は、3D設定を更新します。
      Apply3D(activeSound);

      index++;
    }
  }

  base.Update(gameTime);
}

GameComponent Da den arver klassen, kaldes den automatisk i opdateringsprocessen.

Kontroller den lyd, der afspilles i øjeblikket, og hvis Apply3D den afspilles, skal du ringe til metoden for at opdatere lydens placering, så den matcher emitteren. Hvis en lyd er færdig med at afspilles, kasseres forekomsten.

Play3DSound-metode

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

Processen med at afspille 3D-lyd udefra. Det har navnet på den lyd, der skal afspilles, om den skal sløjfe og udsende information.

Hvis du vil afspille en lyd, skal du oprette en ny lydforekomst fra den lydressource, du opbevarer i _soundEffects. SoundEffectInstance kan også have en løkke eller ej, så indstil sløjfeoplysningerne.

Da jeg opretter som ActiveSound en afspilningstilstand, indstiller jeg emitteroplysninger, der er afspilningsobjektet for lyden der. Hvis du vil anvende 3D-placeringsoplysninger på en lyd, får Emitter du den værdi, du har brug for.

Apply3D Metoden er beskrevet nedenfor, men det er processen med at anvende 3D-information fra emitteren til lyden.

Den grundlæggende proces med 3D-lyd er at starte afspilning med SoundEffectInstance.Play 3D-informationssæt. Resten er at opdatere 3D-oplysningerne med jævne mellemrum, indtil lyden er færdig med at afspille.

Anvend 3D-metode

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

Processen med at anvende en 3D-effekt på en bestemt lydforekomst ved hjælp af lyttere og emittere.

Vi indstiller værdien til _emitter for den fælles forekomst hver gang. Hvis du allerede AudioEmitter har en, skal du SoundEffectInstance.Apply3D blot videregive lytteren og emitteren til metoden.

Audio3DGame klasse

Lad os endelig se på, hvad spilklassen handler om.

mark

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 Registrerer sig i , men har det som et felt, fordi det får adgang til det individuelt.

Andre definerer hunde-, katteenheder, teksturer til jordtegning, quaddrawer, kamerainformation og inputinformation.

konstruktør

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 Generer og GameComponents registrer dig hos .

Du har også genereret klasserne Kat og Hund.

LoadContent-metode

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

Indlæs de teksturer, der er nødvendige for hver tegning.

QuadDrawer genereres GraphicsDevice her, fordi kræver .

Opdater metode

/// <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 Metoderne og UpdateCamera metoderne er processen med at hente enhedsindgang og håndtere kameraet, som vil blive diskuteret senere.

Da kamerapositionen og lytterpositionen næsten altid er den samme, indstilles lytteren til den samme værdi efter kameraopdateringsprocessen.

_cat Ring til og _dog Opdater metoder til henholdsvis at flytte og hvine.

Tegn metode

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

Genererer visnings- og projektionstransformationer fra kameraoplysninger.

Til jorden vises rektanglet tegnet i QuadDrawer lodret, så det drejes for at være vandret og forstørret moderat. _quadDrawer.DrawQuad Det andet argument for metoden angiver antallet af gentagelser af tekstur, hvilket angiver, at 32x32 ark vises side om side.

_cat og _dog er billboardet internt, så kameraets placeringsoplysninger videregives og tegnes.

HandleInput metode

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

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

Oplysninger på tastaturet og gamepad erhverves, og slutningen af spillet bestemmes.

UpdateCamera metode

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

Kameraet styres til at bevæge sig.

Det inkluderer også beregninger som acceleration og friktion, men jeg tror, det sandsynligvis tager højde for Doppler-effekten på 3D-lyd. Da jeg ikke gør noget særligt ved selve beregningen, vil jeg ikke diskutere det.

Resumé

Jeg har dækket det i længden, men det er normalt nok at henvise til klassen for AudioManager , hvordan man spiller 3D-lyd. Faktisk er de fleste af vanskelighederne gjort af rammen, fordi det SoundEffectInstance , vi laver, er at sætte 3D-information i . Hvis du kun har samplet delene af 3D-lyden, ender du med at skrive lidt arbejde i game-klassen. Jeg skriver dog Tips baseret på den originale historie, så det har været meget længere.