Audio3D

Puslapis atnaujintas :
Puslapio sukūrimo data :

Pastabos apie šiuos patarimus

Šis pavyzdys pagrįstas programomis, paskelbtomis šiose svetainėse. Aš šiek tiek keičiu kodą, kad būtų lengviau jį suprasti ir paaiškinti japonų kalba. Iš esmės mes naudojame originalų kodą tokį, koks yra, taigi, jei jūs iš tikrųjų jį priimate savo žaidimo programoje, ištaisykite jį laiku ir naudokite.

Nuorodų svetainė

Be to, tai paaiškinama darant prielaidą, kad turite tam tikrų pagrindinių žinių apie MonoGame ir XNA. Žiūrėkite "MonoGame Tips" ir "XNA" patarimus , kad galėtumėte rudi.

Visų pirma, kadangi matematika, vektoriai, trigonometrinės funkcijos, matricos ir kt. yra būtini, todėl prašome žinoti, kas jie yra tam tikru mastu.

Aplinkos

platforma
  • "Windows 10"
  • Kodą galima naudoti kitose "MonoGame" palaikančiose platformose
Visual Studio
  • "Visual Studio 2019"
.NET Core
  • 3.1
MonoGame
  • 3.8

Apie mėginius

Remiantis fotoaparato padėtimi, galite išgirsti skambutį iš šuns padėties ir katės padėties. Katė apjuosia ir apjuosia kilmę, o žaidėjas gali valdyti fotoaparato padėtį raktu. Įsitikinkite, kad tai, kaip girdite garsą, keičiasi su kiekvienu fotoaparato padėties ar katės padėties pasikeitimu. Manau, kad tai lengva suprasti naudojant ausines. Aš nepatvirtintas kanale 5.1.

Kaip valdyti

Ką daryti klaviatūros žaidimų pulto (XInput) pelės prisilietimas
Fotoaparatas į priekį ir atgal ↑↓ Kairysis pagaliukas (viršuje ir apačioje) - -
Keisti fotoaparato padėtį ←→ Kairė lazda (kairė ir dešinė) - -
Žaidimo pabaiga Esc Nugara - -

Ką paruošti

  • Šunų girgždėjimo garso failas
  • Trys kačių girgždėjimo garso failai
  • Šuns vaizdo failas
  • Katės paveikslėlio failas
  • Žemės vaizdo failas

Pradinis pavyzdys oficialioje svetainėje naudoja iš anksto sukurtą turinį .xnb failus. Jei norite laikyti pavyzdžius oficialioje svetainėje, nenaudokite mgCB, pridėkite juos tiesiai prie "Visual Studio" sprendimo ir nukopijuokite juos kūrimo metu.

Aš nežinau, kodėl originalus pavyzdys imasi šio metodo, bet manau, kad tai tikriausiai todėl, kad mes migruojame senesnes projekto versijas, kaip yra. Žinoma, galite naudoti mgCB, kad sugeneruotumėte tą patį failą. Projektai, kuriuos galima atsisiųsti šioje svetainėje, buvo modifikuoti į MGCB versiją.

programa

Atsisiųskite programą visam kodui.

Šis pavyzdys sukurtas taip, kad kodas atrodytų šiek tiek bendresnis, o garso atkūrimas atrodytų gerai vykdymo metu. Naudojant tik "Audio3D" būtų daug mažiau kodo, tačiau jis aprašytas palei pradinį pavyzdį. Aš pasiliksiu mažiau svarbias dalis.

Projektą sudaro šie kodų failai:

  • Audio3DGame
  • AudioManager
  • Katė
  • Šuo
  • IAudioEmitter
  • Programa
  • QuadDrawer
  • SpriteEntity

QuadDrawer klasė

Ši klasė yra pagalbinė klasė stačiakampiams daugiakampiams piešti. Stačiakampiai daugiakampiai dažnai pirmiausia naudojami 3D sprites (skelbimų lentoms) rodyti. Šie patarimai naudojami kačių ir šunų skelbimų lentoms, taip pat stačiakampiams žemės ekranams.

Ši klasė neturi nieko bendro su "Audio3D".

laukas

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

Minimali informacija, reikalinga daugiakampiams piešti. Pieškite daugiakampius iš viršūnės duomenų neruošdami modelio duomenų.

Konstruktorius

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

Kadangi ši klasė yra visuotinai naudojama, jūs gaunate GraphicsDevice egzempliorių, sukurtą žaidimo klasės inicijavimo procese.

Čia mes nustatėme efektą, reikalingą spritei piešti ir 4 viršūnių, reikalingų stačiakampio poligonui, padėtį. Dydis turėtų būti sumažintas piešiant, todėl jis yra nuo -1 iki 1.

DrawQuad metodas

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

Nustato perduotą tekstūrą į stačiakampį ir jį traukia. Kadangi tai yra pagrindinis procesas, nėra nieko, į kurį reikia atkreipti dėmesį.

Jei yra vienas taškas, argumente textureRepeats galima nurodyti iškviestą kintamąjį, kad būtų galima keisti tekstūros koordinates. Jei vertexPositionTexture.TextureCoordinate nustatomas už diapazono nuo 0 iki 1 ribų, pagal numatytuosius nustatymus tekstūra piešiama pakartotinai. Naudojant jį, galima išreikšti, kad plytelės gali būti išdėstytos pakartotinai. Tiesą sakant, languoti modeliai ant žemės, atrodo, turi kelis paprastus juodos ir baltos spalvos vaizdus.

IAudioEmitter sąsaja

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

Apibrėžiamas kaip objektas, skleidžiantis garsą. Kadangi šį kartą garsą skleidžiantys subjektai yra šunys ir katės, jie paveldimi atitinkamose klasėse. Emitentui reikia šios informacijos:

Ypatybių naudojimas
Poziciją Objekto pareigos
Į priekį Kryptis, į kurią nukreiptas subjektas (vektorius)
Į viršų Subjekto pakilimas. Kryptis, kuria galva egzistuoja žmoguje
Greitis Greitis, kuriuo objektas juda. Naudojamas Doplerio reikšmėms apskaičiuoti.

SpriteEntity klasė

Klasė, skirta atstovauti 3D sprites (skelbimų lentos). Jis taip pat yra teršėjas ir paveldi IAudioEmitter . Šunys ir katės paveldi šią klasę.

nuosavybė

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

Jame yra objekto vietos informacija ir kt. Iš esmės aš turiu informaciją kaip emitentas. Tai taip pat yra piešimo subjektas, todėl jis taip pat turi rodyti vaizdą (tekstūrą).

Atnaujinimo metodas

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

Aprašoma objekto padėtis ir garso grojimo procesas, tačiau jis įgyvendinamas išvestinėje klasėje.

Piešimo metodas

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

Šunys ir katės turi skirtingus vaizdus ir pozicijas, tačiau kitas piešimo mechanizmas yra lygiai tas pats, todėl juos aprašau čia.

Kiekviena transformacija ir tekstūra perduodama "QuadDrawer", kad būtų rodomas stačiakampis daugiakampis. Kadangi koordinačių transformacija yra pagrindinės žinios, paaiškinimai neįtraukiami.

Matrix.CreateConstrainedBillboard Naudokite metodą ir fotoaparato informaciją, kad lengvai atvaizduotumėte skelbimų lentas, todėl efektyviai jas naudokite.

Šunų klasė

Tai klasė, kuri daro šunų piešimo ir dainavimo atkūrimą. SpriteEntity Paveldėti klasę. Šuo lieka fiksuotoje padėtyje 3D erdvėje.

laukas

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

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

_timeDelay jis naudojamas intervalais, kad būtų galima žaisti šauksmą.

SoundEffectInstance _activeSound Tai pavyzdys, kaip groti garsą. SoundEffectInstance Kaip dažnai matysite garso atkūrimo klasėje, galite naudoti tai, kaip yra 3D garsu. Beje _activeSound , aš tik gauti nuorodą iš AudioManager klasės vėliau, todėl aš ne išmesti jį į Dot klasės pusėje.

Atnaujinimo metodas

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

Šiame mėginyje šuo ilgą laiką lieka toje pačioje padėtyje, todėl pirmieji keturi parametrai nurodomi lemiamu smūgiu. Piešimas atliekamas pagrindinėje klasėje.

_timeDelay tada naudojamas kaip likęs laikas sustoti, žaisti šauksmą.

AudioManager bus atkuriamasPlay3DSound 3D erdvėje, perduodant šauksmo pavadinimą, kilpos informaciją ir savo informaciją kaip emitentą.

Šunų klasė yra skirta kilpa verkti, todėl jums nereikia galvoti per giliai, nes tai tik koregavimas, pavyzdžiui, žaisti ar sustabdyti šakotis.

Kačių klasė

Tai klasė, kuri daro kačių piešimo ir dainavimo atkūrimą. SpriteEntity Paveldėti klasę. Katė juda aplink kilmę.

laukas

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

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

_timeDelay naudojamas taip pat, kaip ir šunų klasė, o likusį laiką iki kito girgždėjimo.

Yra trijų tipų kačių skambučiai, kurie yra atsitiktinai atrinkti ir grojami, tačiau jie neturi nieko bendro su "Audio3D", nes jie yra premijos elementas.

Atnaujinimo metodas

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

Kadangi katė sukasi aplink kilmę sukamaisiais judesiais, ji ją apdoroja taip, kad judintų apskritimo trajektoriją, naudodama trigonometrinę funkciją. Dėl to padėtis, į priekį ir greitis pasikeitė vienas po kito. Todėl, kai paleidžiate programą, galite pamatyti, kad katės šauksmas sukasi aplink, net jei nejudinate fotoaparato.

_timeDelay Šis kodas yra procesas, kurio metu katės šauksmas atsitiktinai priskiriamas ir žaidžiamas reguliariais intervalais. audioManager.Play3DSound Aš perduodu save metodui, kuris yra teršėjas. Galite matyti, kad garso atkūrimo padėtis keičiasi po vieną.

AudioManager klasė

Tai yra "Audio3D" esmė. 3D garsą sudaro klausytojas ir emitentas. Teršėjas jau apibrėžia šunis ir kates, todėl "AudioManager" klasė apibrėžia klausytojus. Paprastai yra keli teršėjai, o klausytojas yra tik vienas.

Ši klasė paveldi,Game registruoja GameComponent ir naudoja komponentą klasėje.

ActiveSound klasė

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

Jis apibrėžiamas kodo apačioje, tačiau tai yra klasė, skirta išsaugoti valstybę, kuri žaidžia. Jame yra informacijos apie grojamą garso egzempliorių ir grojamą emitentą.

laukas

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 apibrėžia įkelto garso failo (turto pavadinimo) pavadinimą. Kadangi tai yra pavyzdinė programa, ji apibrėžiama pirmiausia įkelti garso failą dideliais kiekiais. Importuoti garso duomenys _soundEffects saugomi .

AudioListener Listener Tai yra klausytojo apibrėžimas. Klausytojo informacija apibrėžiama, nes ji public nustatyta iš Žaidimo klasės.

AudioEmitter _emitter yra emitento apibrėžimas, kai garso atkūrimui taikomas 3D. Šiame pavyzdyje, grojant garsą, nustatoma kiekvieno emitento objekto _emitter vertė , todėl tai yra forma, kuri dalijasi vienu kaip egzemplioriumi. Žinoma, galite turėti kiekvienam AudioEmitter objektui.

_activeSounds turi informacijos apie garsą, kurį grojate klasėje, kurią anksčiau apibrėžėte ActiveSound . Kadangi emitento informacija nuolat keičiasi, ji naudojama vietos informacijai atnaujinti ir kt. ir garso egzemplioriams, kurie baigė leisti, atmesti.

Konstruktorius

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

GameComponent Kadangi jis paveldi klasę, Game jis gauna egzempliorių ir perduoda jį pagrindinei klasei.

Inicijavimo metodas

/// <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 Kadangi jis paveldi klasę, jis automatiškai iškviečiamas inicijavimo metu.

SoundEffect.DistanceScale ir SoundEffect.DopplerScale yra parametrai, skirti 3D garsui static .

SoundEffect.DistanceScale Girdėti garsą net per atstumą.

SoundEffect.DopplerScale Tai doplerio efekto įtaka. Kuo didesnis skaičius, tuo didesnis Doplerio efektas.

_soundNames Įrašyti įkeltame _soundEffects cikle apibrėžtą turto pavadinimą .

Disponavimo metodas

/// <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 Jis automatiškai iškviečiamas žaidimo pabaigoje, nes jis paveldi klasę.

Sunaikinti visus importuotus garso išteklius.

Atnaujinimo metodas

/// <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 Kadangi jis paveldi klasę, jis automatiškai iškviečiamas atnaujinimo procese.

Patikrinkite šiuo metu leidžiamą garsą ir, jei jis grojamas, paskambinkite į garso vietos atnaujinimo metodą, kad jis Apply3D atitiktų emitentą. Jei bet kuris garsas baigtas leisti, egzempliorius atmetamas.

Play3DSound metodas

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

3D garso grojimo procesas iš išorės. Jis turi garso pavadinimą, kurį reikia groti, nesvarbu, ar kilpa, ir skleidžiančią informaciją.

Jei norite leisti garsą, sukurkite naują garso egzempliorių iš garso šaltinio, kurį laikote _soundEffects. SoundEffectInstance taip pat gali turėti kilpą ar ne, todėl nustatykite kilpos informaciją.

Kadangi aš kuriu kaip ActiveSound žaidimo būseną, nustatau emitento informaciją, kuri yra garso atkūrimo objektas. Jei norite pritaikyti garso trimatės vietos informaciją, gausite Emitter reikiamą vertę.

Apply3D Metodas aprašytas toliau, tačiau tai yra 3D informacijos iš emitento taikymo garsui procesas.

Pagrindinis 3D garso procesas yra pradėti atkūrimą naudojant SoundEffectInstance.Play 3D informacijos rinkinį. Likusi dalis yra periodiškai atnaujinti 3D informaciją, kol garsas bus baigtas groti.

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

3D efekto taikymo konkrečiam garso egzemplioriui procesas naudojant klausytojus ir emitentus.

Kiekvieną kartą mes nustatome bendrosios instancijos _emitter vertę. Jei jau AudioEmitter turite SoundEffectInstance.Apply3D vieną, tiesiog perduokite klausytoją ir emitentą į metodą.

Audio3DGame klasė

Galiausiai, pažvelkime į tai, kas yra žaidimo klasė.

laukas

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 Registruojasi GameComponents , bet turi jį kaip lauką, nes jis jį pasiekia atskirai.

Kiti apibrėžia šunų, kačių subjektus, tekstūras žemės piešimui, keturkampį, fotoaparato informaciją ir įvesties informaciją.

Konstruktorius

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 Generuoti ir GameComponents registruotis naudojant .

Jūs taip pat sukūrėte kačių ir šunų klases.

LoadContent metodas

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

Įkelkite tekstūras, reikalingas kiekvienam piešiniui.

QuadDrawer čia generuojama GraphicsDevice , nes reikia .

Atnaujinimo metodas

/// <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 Metodai ir UpdateCamera metodai yra įrenginio įvesties gavimo ir fotoaparato tvarkymo procesas, kuris bus aptartas vėliau.

Kadangi fotoaparato padėtis ir klausytojo padėtis beveik visada yra tokia pati, klausytojas po fotoaparato atnaujinimo proceso nustato tą pačią reikšmę.

_cat Atitinkamai skambinkite ir _dog atnaujinkite metodus, kad galėtumėte judėti ir girgždėti.

Piešimo metodas

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

Generuoja vaizdo ir projekcijos transformacijas iš fotoaparato informacijos.

Žemei "QuadDrawer" nupieštas stačiakampis rodomas vertikaliai, todėl jis pasukamas taip, kad būtų horizontalus ir vidutiniškai padidintas. _quadDrawer.DrawQuad Antrasis metodo argumentas nurodo tekstūros pakartojimų skaičių, kuris nurodo, kad 32x32 lapai rodomi vienas šalia kito.

_cat ir _dog yra skelbimų lentos viduje, todėl fotoaparato vietos informacija perduodama ir piešiama.

HandleInput metodas

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

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

Gaunama informacija klaviatūroje ir žaidimų pulte, nustatoma žaidimo pabaiga.

UpdateCamera metodas

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

Fotoaparatas yra valdomas judėti.

Tai taip pat apima skaičiavimus, tokius kaip pagreitis ir trintis, bet manau, kad tai tikriausiai atsižvelgia į Doplerio poveikį 3D garsui. Kadangi aš nedarau nieko ypatingo apie patį skaičiavimą, aš to neaptarinėsiu.

Suvestinė

Aš jį apėmė ilgai, bet paprastai pakanka kreiptis į klasę AudioManager , kaip žaisti 3D garsą. Tiesą sakant, dauguma sunkumų yra padaryti pagal sistemą, nes tai, ką SoundEffectInstance mes darome, yra 3D informacijos nustatymas į . Jei atrinkote tik 3D garso dalis, galų gale parašysite šiek tiek darbo žaidimo klasėje. Tačiau rašau patarimus pagal originalią istoriją, todėl tai buvo daug ilgiau.