Audio3D

Sidan uppdaterad :
Datum för skapande av sida :

Anteckningar om detta tips

Det här exemplet baseras på programmen som publiceras på följande webbplatser. Jag ändrar koden lite för att göra det lättare att förstå och förklara den på japanska. I grund och botten använder vi den ursprungliga koden som den är, så om du faktiskt antar den i ditt spelprogram, korrigera den i tid och använd den.

Referensplats

Dessutom förklaras det under antagandet att du har grundläggande kunskaper om MonoGame och XNA. Se MonoGame Tips och XNA Tips för ruddly.

I synnerhet, eftersom matematik, vektorer, trigonometriska funktioner, matriser etc. är viktiga, så vänligen veta vad de är i viss utsträckning.

miljö

plattform
  • Windows 10
  • Kod kan användas på andra MonoGame-aktiverade plattformar
Visuell studio
  • Visual Studio 2019
.NET-kärna
  • 3.1
MonoGame
  • 3.8

Om prover

Baserat på kamerans position kan du höra samtalet från hundens position och kattens position. Katten cirklar och cirklar ursprunget, och spelaren kan styra kamerans position med nyckeln. Se till att sättet du hör ljudet ändras med varje förändring i kamerans position eller kattens position. Jag tror att det är lätt att förstå med hörlurar. Jag är obekräftad på kanal 5.1.

Hur man arbetar

Vad ska du göra tangentbord gamepad (XInput) Mouse Touch
Kamera framåt och bakåt ↑↓ Vänster pinne (överst och nederkant) - -
Ändra kamerans orientering ←→ Vänster pinne (vänster och höger) - -
Spelets slut Esc Tillbaka - -

Vad man ska förbereda

  • Hund skrikande ljudfil
  • Tre katt skrikande ljudfiler
  • Hundbildfil
  • Cat-bildfil
  • Markbildsfil

Det ursprungliga exemplet på den officiella webbplatsen använder fördefinierat innehåll .xnb-filer . Om du vill behålla proverna på den officiella webbplatsen ska du inte använda mgcbs, lägg till dem direkt i din Visual Studio-lösning och kopiera dem vid byggtiden.

Jag vet inte varför det ursprungliga provet tar den här metoden, men jag tror att det förmodligen beror på att vi migrerar äldre versioner av projektet som det är. Naturligtvis kan du använda mgcb för att generera samma fil. De projekt som kan laddas ner på denna webbplats har ändrats till MGCB-versionen.

program

Ladda ner programmet för all kod.

Det här exemplet är utformat för att få koden att se lite mer allmän ut samtidigt som ljuduppspelningen ser bra ut vid körning. Att bara använda Audio3D skulle vara mycket mindre kod, men det beskrivs längs det ursprungliga exemplet. Jag behåller de mindre viktiga delarna.

Projektet består av följande kodfiler:

  • Ljud3DGame
  • AudioManager
  • Katt
  • Hund
  • IAudioEmitter
  • Program
  • QuadDrawer
  • SpriteEntity

QuadDrawer-klass

Denna klass är en hjälpklass för att rita rektangulära polygoner. Rektangulära polygoner används ofta främst för att visa 3D-sprites (skyltar). Dessa tips används för skyltar för katter och hundar, liksom för rektangulära skärmar av marken.

Den här klassen har inget att göra med Audio3D.

fält

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

Minsta information som krävs för att rita polygoner. Rita polygoner från hörndata utan att förbereda modelldata.

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

Eftersom den här klassen är allmänt användbar får du GraphicsDevice en instans som skapats i initieringsprocessen för spelklass.

Här ställer vi in den effekt som krävs för att rita spriten och positionen för de 4 hörnen som krävs för den rektangulära polygonen. Storleken ska skalas vid ritning, så det är -1 till 1.

DrawQuad-metod

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

Ställer in den skickade texturen på en rektangel och ritar den. Eftersom detta är en grundläggande process finns det inget att notera.

Om det finns en punkt kan en variabel som anropas anges i textureRepeats argumentet, så att texturens koordinater kan ändras. Om vertexPositionTexture.TextureCoordinate anges utanför intervallet 0 till 1 ritas texturen upprepade gånger som standard. Med hjälp av det är det möjligt att uttrycka att plattor kan ordnas upprepade gånger. Faktum är att de rutmönster på marken verkar ha flera enkla svartvita bilder uppradade.

IAudioEmitter-gränssnitt

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

Definieras som en entitet som avger ljud. Eftersom de enheter som avger ljud den här gången är hundar och katter ärvs de i sina respektive klasser. Emittern behöver följande information:

Användning av egenskaper
Position Enhetsposition
Framåt Den riktning som entiteten är vänd mot (vektor)
Upp Enhetens upp. Den riktning i vilken huvudet finns i en person
Hastighet Den hastighet med vilken entiteten rör sig. Används för att beräkna Dopplervärden.

SpriteEntity-klass

En klass för att representera 3D-sprites (skyltar). Det är också en emitter och ärver IAudioEmitter . Hundar och katter ärver denna klass.

egenskap

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

Den har enhetens platsinformation etc. I grund och botten har jag information som utsläppare. Det är också en ritningsentitet, så den har också en bild (textur) att visa.

Uppdateringsmetod

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

Beskriver entitetens position och processen för att spela upp ljud, men implementerar den i den härledda klassen.

Metoden Rita

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

Hundar och katter har olika bilder och positioner, men den andra ritmekanismen är exakt densamma, så jag beskriver dem här.

Varje omvandling och textur skickas till QuadDrawer för att visa en rektangulär polygon. Eftersom koordinattransformation är grundläggande kunskaper omfattas inte förklaringar.

Matrix.CreateConstrainedBillboard Använd metod- och kamerainformation för att enkelt representera skyltar, så utnyttja dem effektivt.

Hundklass

Det är en klass som gör hundteckning och sånguppspelning. SpriteEntity Ärver klassen. Hunden förblir i ett fast läge i 3D-rymden.

fält

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

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

_timeDelay används med jämna mellanrum för att spela gråten.

SoundEffectInstance _activeSound är en instans för att spela upp ett ljud. SoundEffectInstance Som du ofta ser i klassen för ljuduppspelning kan du använda detta som det är i 3D-ljud. Förresten _activeSound får jag bara en referens från AudioManager-klassen senare, så jag kommer inte att kasta den på Dot-klasssidan.

Uppdateringsmetod

/// <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 detta prov förblir hunden i samma position under lång tid, så de första fyra parametrarna anges av en avgörande strejk. Ritningen görs i grundklassen.

_timeDelay används sedan som återstående tid att sluta och spela gråten.

AudioManager kommer att reproducerasPlay3DSound i 3D-rymden genom att skicka namnet på skriket, loopinformationen och din egen information som en emitter till .

Hundklassen är utformad för att loopa skriket, så att du inte behöver tänka för djupt eftersom det bara är en justering, som att spela eller stoppa förgrening.

Kattklass

Det är en klass som gör kattteckning och sånguppspelning. SpriteEntity Ärver klassen. Katten rör sig runt ursprunget.

fält

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

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

_timeDelay används på samma sätt som hundklassen, med resten av tiden före nästa skrik.

Det finns tre typer av kattsamtal som väljs slumpmässigt och spelas, men de har inget att göra med Audio3D eftersom de är ett bonuselement.

Uppdateringsmetod

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

Eftersom katten vänder om ursprunget i en cirkulär rörelse bearbetar den den så att den flyttar cirkelns bana med hjälp av en trigonometrisk funktion. Som ett resultat har position, framåt och Velocity förändrats en efter en. Därför, när du kör programmet, kan du se att kattens rop cirklar runt även om du inte flyttar kameran.

_timeDelay Följande kod är en process där kattens rop slumpmässigt tilldelas och spelas med jämna mellanrum. audioManager.Play3DSound Jag överlämnar mig själv till metoden som är en emitter. Du kan se att ljudets uppspelningsposition ändras en efter en.

AudioManager-klass

Detta är äntligen kärnan i Audio3D. Ett 3D-ljud består av en lyssnare och en emitter. Emittern definierar redan hundar och katter, så klassen AudioManager definierar lyssnare. Det finns vanligtvis flera emittrar, medan det bara finns en lyssnare.

Den här klassen ärver ochGame registrerar GameComponent och använder komponenten i klassen.

Klassen ActiveSound

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

Den definieras längst ned i koden, men det är en klass för att bevara det tillstånd som spelas upp. Den har information om ljudinstansen som spelas upp och att sändaren spelas upp.

fält

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 definierar namnet på ljudfilen (tillgångsnamn) som ska läsas in. Eftersom det är ett exempelprogram definieras det för att ladda ljudfilen i bulk först. De importerade ljuddata lagras _soundEffects i .

AudioListener Listener är definitionen av lyssnaren. Lyssnarinformation definieras i eftersom den public är inställd från klassen Spel.

AudioEmitter _emitter är definitionen av sändaren när 3D tillämpas på ljuduppspelning. I det här exemplet, när du spelar upp ett ljud, anges värdet för varje emitterobjekt till _emitter , så det är ett formulär som delar ett som en instans. Naturligtvis kan du ha för varje AudioEmitter objekt.

_activeSounds har information om ljudet du spelar upp i klassen som du definierade ActiveSound tidigare. Eftersom emitterinformation ändras hela tiden används den för att uppdatera platsinformation osv.

konstruktor

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

GameComponent Eftersom den ärver klassen Game tar den emot instansen och skickar den till basklassen.

Initiera metod

/// <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 Eftersom den ärver klassen anropas den automatiskt vid initieringen.

SoundEffect.DistanceScale och SoundEffect.DopplerScale är parametrar dedikerade till static 3D-ljud.

SoundEffect.DistanceScale för att höra ljud även i fjärran.

SoundEffect.DopplerScale är dopplereffektens påverkan. Ju högre tal, desto större Dopplereffekt.

_soundNames Spara tillgångsnamnet som definierats i en slinga för att läsa in _soundEffects .

Metoden Kassera

/// <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 anropas automatiskt i slutet av spelet eftersom det ärver klassen.

Förstör alla importerade ljudtillgångar.

Uppdateringsmetod

/// <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 Eftersom den ärver klassen anropas den automatiskt i uppdateringsprocessen.

Kontrollera det ljud som spelas upp och anropa metoden för att uppdatera ljudets plats för att matcha sändaren om det Apply3D spelas upp. Om något ljud har spelats upp har det ignorerats instansen.

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

Processen att spela 3D-ljud från utsidan. Det har namnet på ljudet att spela upp, om det ska loopas och sändarinformation.

Om du vill spela upp ett ljud skapar du en ny ljudinstans från ljudresursen som du behåller i _soundEffects. SoundEffectInstance kan också ha en slinga eller inte, så ställ in loopinformationen.

Eftersom jag skapar som ActiveSound ett speltillstånd ställer jag in emitterinformation som är uppspelningsobjektet för ljudet där. Om du vill använda 3D-platsinformation på ett ljud får du Emitter det värde du behöver.

Apply3D Metoden beskrivs nedan, men det är processen att tillämpa 3D-information från sändaren på ljudet.

Den grundläggande processen för 3D-ljud är att starta uppspelning med SoundEffectInstance.Play 3D-informationsuppsättning. Resten är att uppdatera 3D-informationen regelbundet tills ljudet är klart.

Apply3D-metod

/// <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 att tillämpa en 3D-effekt på en angiven ljudinstans med hjälp av lyssnare och emittrar.

Vi anger värdet till _emitter för den gemensamma instansen varje gång. Om du SoundEffectInstance.Apply3D redan AudioEmitter har en, skicka helt enkelt lyssnaren och sändaren till metoden.

Audio3DGame-klass

Låt oss slutligen titta på vad spelklassen handlar om.

fält

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 Registrerar sig i , men har det som ett fält eftersom det kommer åt det individuellt.

Andra definierar hund-, kattenheter, texturer för markritning, fyrhjuling, kamerainformation och inmatningsinformation.

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 Generera och GameComponents registrera dig med .

Du har också genererat katt- och hundklasserna.

LoadContent-metod

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

Läs in de texturer som behövs för varje ritning.

QuadDrawerGraphicsDevice genereras här eftersom kräver .

Uppdateringsmetod

/// <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 Metoderna och UpdateCamera metoderna är processen att hämta enhetens inmatning och hantera kameran, som kommer att diskuteras senare.

Eftersom kamerans position och lyssnarposition nästan alltid är desamma är lyssnaren inställd på samma värde efter kamerauppdateringsprocessen.

_cat Anropa metoderna och _dog Uppdatera för att flytta respektive skrika.

Metoden Rita

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

Genererar vy- och projektionstransformeringar från kamerainformation.

För marken visas rektangeln som ritas i QuadDrawer vertikalt, så den roteras för att vara horisontell och förstorad måttligt. _quadDrawer.DrawQuad Metodens andra argument anger antalet upprepningar av texturen, som anger att 32x32-ark visas sida vid sida.

_cat och _dog visas internt, så kamerans platsinformation skickas och ritas.

HandleInput-metod

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

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

Information på tangentbordet och gamepaden förvärvas, och slutet av spelet bestäms.

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

Kameran styrs för att röra sig.

Det innehåller också beräkningar som acceleration och friktion, men jag tror att det förmodligen tar hänsyn till Doppler-effekten på 3D-ljud. Eftersom jag inte gör något speciellt åt själva beräkningen kommer jag inte att diskutera det.

Sammanfattning

Jag har täckt det länge, men det är vanligtvis tillräckligt att hänvisa till klassen för AudioManager hur man spelar 3D-ljud. Faktum är att de flesta svårigheterna görs av ramverket, eftersom det SoundEffectInstance vi gör är att ställa in 3D-information i . Om du bara har provat delarna av 3D-ljudet kommer du att skriva lite arbete i klassen Spel. Men jag skriver tips baserat på den ursprungliga historien, så det har varit mycket längre.