ऑडियो 3 डी

पेज अद्यतन :
पेज निर्माण की तारीख :

इस टिप्स पर नोट्स

यह नमूना निम्न साइट्स पर प्रकाशित प्रोग्राम्स पर आधारित है. मैं इसे समझने और जापानी में समझाने के लिए आसान बनाने के लिए कोड को थोड़ा बदल देता हूं। असल में, हम मूल कोड का उपयोग करते हैं, इसलिए यदि आप वास्तव में इसे अपने गेम प्रोग्राम में अपनाते हैं, तो इसे समय पर सही करें और इसका उपयोग करें।

संदर्भ साइट

इसके अलावा, यह धारणा है कि आप MonoGame और XNA के बारे में कुछ बुनियादी ज्ञान है पर समझाया गया है. देखें MonoGame युक्तियाँ और XNA युक्तियाँ ruddly के लिए युक्तियाँ.

विशेष रूप से, जैसा कि गणित, वैक्टर, त्रिकोणमितीय कार्य, आव्यूह, आदि आवश्यक हैं, इसलिए कृपया जानें कि वे कुछ हद तक क्या हैं।

पर्यावरण

प्लेटफार्म
  • विंडोज 10
  • कोड का उपयोग अन्य मोनोगेम-सक्षम प्लेटफ़ॉर्म पर किया जा सकता है
दृश्य स्टूडियो
  • विजुअल स्टूडियो 2019
.NET कोर
  • 3.1
मोनोगेम
  • 3.8

नमूनों के बारे में

कैमरे की स्थिति के आधार पर, आप कुत्ते की स्थिति और बिल्ली की स्थिति से कॉल सुन सकते हैं। बिल्ली सर्कल और मूल हलकों, और खिलाड़ी कुंजी के साथ कैमरे की स्थिति को नियंत्रित कर सकते हैं। सुनिश्चित करें कि जिस तरह से आप ध्वनि सुनते हैं वह कैमरे की स्थिति या बिल्ली की स्थिति में प्रत्येक परिवर्तन के साथ बदलता है। मुझे लगता है कि इयरफोन का उपयोग करके समझना आसान है। मैं चैनल 5.1 पर अपुष्ट हूँ.

कैसे काम करने के लिए

कीबोर्ड गेमपैड (XInput) माउस टच करने के लिए क्या है
कैमरा आगे और पीछे की ओर ↑↓ बाएँ छड़ी (ऊपर और नीचे) - -
कैमरा ओरिएंटेशन परिवर्तित करें ←→ बाएँ छड़ी (बाएँ और दाएँ) - -
खेल का अंत Esc पीठ - -

क्या तैयार करने के लिए

  • कुत्ता स्क्वील ऑडियो फ़ाइल
  • तीन बिल्ली squeal ऑडियो फ़ाइलें
  • कुत्ता छवि फ़ाइल
  • बिल्ली चित्र फ़ाइल
  • ग्राउंड छवि फ़ाइल

आधिकारिक साइट पर मूल नमूना पूर्वनिर्मित सामग्री .xnb फ़ाइलों का उपयोग करता है। यदि आप नमूने को आधिकारिक साइट पर रखना चाहते हैं, तो mgcbs का उपयोग न करें, उन्हें सीधे अपने Visual Studio समाधान में जोड़ें, और बिल्ड टाइम पर उनकी प्रतिलिपि बनाएँ।

मुझे नहीं पता कि मूल नमूना इस विधि को क्यों ले रहा है, लेकिन मुझे लगता है कि यह शायद इसलिए है क्योंकि हम परियोजना के पुराने संस्करणों को माइग्रेट कर रहे हैं जैसा कि है। बेशक, आप एक ही फ़ाइल उत्पन्न करने के लिए mgcb का उपयोग कर सकते हैं। इस साइट पर डाउनलोड की जा सकने वाली परियोजनाओं को MGCB संस्करण में संशोधित किया गया है.

प्रोग्राम

सभी कोड के लिए प्रोग्राम डाउनलोड करें।

यह नमूना कोड को थोड़ा अधिक सामान्य दिखने के लिए डिज़ाइन किया गया है, जबकि ध्वनि प्लेबैक को रनटाइम पर अच्छा दिखता है। Audio3D का उपयोग करना केवल बहुत कम कोड होगा, लेकिन इसे मूल नमूने के साथ वर्णित किया गया है। मैं कम महत्वपूर्ण भागों को रखूंगा।

प्रोजेक्ट में निम्न कोड फ़ाइलें होती हैं:

  • Audio3DGame
  • AudioManager
  • बिल्ली
  • कुत्ता
  • IAudioEmitter
  • प्रोग्राम
  • QuadDrawer
  • स्प्राइटेंटी

QuadDrawer वर्ग

यह वर्ग आयताकार बहुभुजों को खींचने के लिए एक सहायक वर्ग है। आयताकार बहुभुज का उपयोग अक्सर मुख्य रूप से 3 डी स्प्राइट्स (बिलबोर्ड) को प्रदर्शित करने के लिए किया जाता है। इस युक्तियों का उपयोग बिल्लियों और कुत्तों के लिए बिलबोर्ड के साथ-साथ जमीन के आयताकार प्रदर्शनों के लिए भी किया जाता है।

इस वर्ग का Audio3D से कोई लेना-देना नहीं है।

खेत

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

बहुभुज खींचने के लिए आवश्यक न्यूनतम जानकारी। मॉडल डेटा तैयार किए बिना वर्टेक्स डेटा से बहुभुज आरेखित करें.

निर्माता

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

क्योंकि यह वर्ग सार्वभौमिक रूप से उपयोग करने योग्य है, आपको GraphicsDevice गेम क्लास प्रारंभ प्रक्रिया में बनाई गई एक आवृत्ति प्राप्त होती है।

यहां, हम स्प्राइट को आकर्षित करने के लिए आवश्यक प्रभाव और आयताकार बहुभुज के लिए आवश्यक 4 शीर्षों की स्थिति निर्धारित करते हैं। ड्राइंग करते समय आकार को स्केल किया जाना चाहिए, इसलिए यह -1 से 1 है।

DrawQuad विधि

/// <summary>
/// 3Dワールドの一部として四角形を描画します。
/// </summary>
public void DrawQuad(Texture2D texture, float textureRepeats, Matrix world, Matrix view, Matrix projection)
{
  // 指定されたテクスチャとカメラマトリックスを使用するようにエフェクトを設定します。
  _effect.Texture = texture;

  _effect.World = world;
  _effect.View = view;
  _effect.Projection = projection;

  // 指定された数のテクスチャの繰り返しを使用するように頂点配列を更新します。
  _vertices[0].TextureCoordinate = new Vector2(0, 0);
  _vertices[1].TextureCoordinate = new Vector2(textureRepeats, 0);
  _vertices[2].TextureCoordinate = new Vector2(0, textureRepeats);
  _vertices[3].TextureCoordinate = new Vector2(textureRepeats, textureRepeats);

  // 矩形を描画します。
  _effect.CurrentTechnique.Passes[0].Apply();

  _graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
}

पारित बनावट को एक आयत पर सेट करता है और इसे खींचता है। चूंकि यह एक बुनियादी प्रक्रिया है, इसलिए ध्यान देने योग्य कुछ भी नहीं है।

यदि एक बिंदु है, तो तर्क में textureRepeats एक चर जिसे कहा जाता है, निर्दिष्ट किया जा सकता है, ताकि बनावट के निर्देशांक को बदला जा सके। vertexPositionTexture.TextureCoordinate 0 से 1 तक की श्रेणी से परे सेट है, तो बनावट डिफ़ॉल्ट रूप से बार-बार खींचा जाता है। इसका उपयोग करके, यह व्यक्त करना संभव है कि टाइल्स को बार-बार व्यवस्थित किया जा सकता है। वास्तव में, जमीन पर चेकर्ड पैटर्न में कई सरल काले और सफेद छवियों को पंक्तिबद्ध किया गया प्रतीत होता है।

IAudioEmitter इंटरफ़ेस

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

एक इकाई के रूप में परिभाषित किया गया है जो ध्वनि उत्सर्जित करता है। चूंकि इस बार ध्वनि उत्सर्जित करने वाली संस्थाएं कुत्ते और बिल्लियां हैं, इसलिए उन्हें अपनी संबंधित कक्षाओं में विरासत में मिला है। उत्सर्जक को निम्न जानकारी की आवश्यकता है:

गुण उपयोग
पद एंटिटी स्थिति
आगे जिस दिशा का सामना निकाय कर रहा है वह (वेक्टर)
ऊपर इकाई का ऊपर। वह दिशा जिसमें सिर किसी व्यक्ति में मौजूद होता है
वेग वह गति जिस पर इकाई चलती है। डॉपलर मानों की गणना करने के लिए उपयोग किया जाता है।

स्प्राइटेंटी वर्ग

3डी स्प्राइट्स (बिलबोर्ड) का प्रतिनिधित्व करने के लिए एक वर्ग। यह एक उत्सर्जक भी है, और विरासत में मिलता है IAudioEmitter । कुत्तों और बिल्लियों को इस वर्ग का वारिस मिलता है।

जायदाद

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

इसमें एंटिटी की लोकेशन की जानकारी आदि है। मूल रूप से मेरे पास एक उत्सर्जक के रूप में जानकारी है। यह एक ड्राइंग इकाई भी है, इसलिए इसमें प्रदर्शित करने के लिए एक छवि (बनावट) भी है।

अद्यतन विधि

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

इकाई की स्थिति और ध्वनि खेलने की प्रक्रिया का वर्णन करता है, लेकिन इसे व्युत्पन्न वर्ग में लागू करता है।

आरेखित विधि

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

कुत्तों और बिल्लियों के पास अलग-अलग छवियां और स्थितियां हैं, लेकिन अन्य ड्राइंग तंत्र बिल्कुल समान है, इसलिए मैं उन्हें यहां वर्णन करता हूं।

प्रत्येक परिवर्तन और बनावट को एक आयताकार बहुभुज प्रदर्शित करने के लिए QuadDrawer को पारित किया जाता है। चूंकि समन्वय परिवर्तन बुनियादी ज्ञान है, इसलिए स्पष्टीकरण को कवर नहीं किया गया है।

Matrix.CreateConstrainedBillboard आसानी से बिलबोर्ड का प्रतिनिधित्व करने के लिए विधि और कैमरा जानकारी का उपयोग करें, इसलिए उनका प्रभावी उपयोग करें।

कुत्ते वर्ग

यह एक वर्ग है जो कुत्ते ड्राइंग और गायन प्लेबैक करता है। SpriteEntity कक्षा को विरासत में लेना। कुत्ता 3 डी स्पेस में एक निश्चित स्थिति में रहता है।

खेत

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

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

_timeDelay रोने को खेलने के लिए अंतराल पर उपयोग किया जाता है।

SoundEffectInstance _activeSound एक ध्वनि खेलने के लिए एक उदाहरण है. SoundEffectInstance जैसा कि आप अक्सर ध्वनि प्लेबैक की कक्षा में देखेंगे, आप इसका उपयोग कर सकते हैं जैसा कि 3 डी ध्वनि में है। वैसे _activeSound , मैं केवल AudioManager वर्ग से बाद में एक संदर्भ प्राप्त होता है, तो मैं इसे डॉट वर्ग पक्ष पर छोड़ नहीं होगा.

अद्यतन विधि

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

इस नमूने में, कुत्ता लंबे समय तक एक ही स्थिति में रहता है, इसलिए पहले चार पैरामीटर एक निर्णायक हड़ताल द्वारा निर्दिष्ट किए जाते हैं। ड्राइंग मूल कक्षा में किया जाता है।

_timeDelay तब रोने के लिए, रोकने के लिए शेष समय के रूप में उपयोग किया जाता है।

AudioManager रोने, लूप जानकारी, और एक उत्सर्जक के रूप में अपनी खुद की जानकारी के नाम को पारित करके 3 डी अंतरिक्ष में पुन: पेश कियाPlay3DSound जाएगा।

कुत्ते की कक्षा को रोने को लूप करने के लिए डिज़ाइन किया गया है, इसलिए आपको बहुत गहराई से सोचने की ज़रूरत नहीं है क्योंकि यह सिर्फ एक समायोजन है, जैसे कि ब्रांचिंग खेलना या रोकना।

बिल्ली वर्ग

यह एक वर्ग है जो बिल्ली ड्राइंग और गायन प्लेबैक करता है। SpriteEntity कक्षा को विरासत में लेना। बिल्ली मूल के चारों ओर घूम रही है।

खेत

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

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

_timeDelay कुत्ते वर्ग के रूप में उसी तरह से उपयोग किया जाता है, अगले स्क्वील से पहले बाकी समय के साथ।

तीन प्रकार के बिल्ली कॉल हैं जो बेतरतीब ढंग से चुने गए और खेले जाते हैं, लेकिन उनके पास Audio3D के साथ कुछ भी नहीं करना है क्योंकि वे एक बोनस तत्व हैं।

अद्यतन विधि

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

चूंकि बिल्ली एक परिपत्र गति में मूल के चारों ओर घूमती है, इसलिए यह इसे संसाधित करती है ताकि यह त्रिकोणमितीय फ़ंक्शन का उपयोग करके सर्कल के प्रक्षेपवक्र को स्थानांतरित कर सके। नतीजतन, स्थिति, आगे और वेग एक के बाद एक बदल गए हैं। इसलिए, जब आप कार्यक्रम चलाते हैं, तो आप देख सकते हैं कि बिल्ली का रोना चारों ओर घूम रहा है, भले ही आप कैमरे को स्थानांतरित न करें।

_timeDelay निम्नलिखित कोड एक ऐसी प्रक्रिया है जिसमें बिल्ली के रोने को यादृच्छिक रूप से असाइन किया जाता है और नियमित अंतराल पर खेला जाता है। audioManager.Play3DSound मैं खुद को उस विधि से गुजर रहा हूं जो एक उत्सर्जक है। आप देख सकते हैं कि ध्वनि की प्लेबैक स्थिति एक-एक करके बदलती है।

AudioManager वर्ग

यह अंत में Audio3D का सार है। एक 3 डी ध्वनि में एक श्रोता और एक उत्सर्जक होता है। उत्सर्जक पहले से ही कुत्तों और बिल्लियों को परिभाषित करता है, इसलिए AudioManager वर्ग श्रोताओं को परिभाषित करता है। आमतौर पर कई उत्सर्जक होते हैं, जबकि केवल एक श्रोता होता है।

यह वर्ग इनहेरिट करता है औरGame पंजीकृत करता है GameComponent और कक्षा में घटक का उपयोग करता है।

ActiveSound वर्ग

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

इसे कोड के नीचे परिभाषित किया गया है, लेकिन यह उस राज्य को संरक्षित करने के लिए एक वर्ग है जो खेल रहा है। इसमें साउंड इंस्टेंस बजाने और एमिटर बजाने के बारे में जानकारी है।

खेत

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 लोड करने के लिए ऑडियो फ़ाइल (संपत्ति नाम) का नाम निर्धारित करता है। चूंकि यह एक नमूना प्रोग्राम है, इसलिए इसे पहले थोक में ऑडियो फ़ाइल लोड करने के लिए परिभाषित किया गया है। आयातित ध्वनि डेटा में संग्रहीत किया जाता है _soundEffects .

AudioListener Listener श्रोता की परिभाषा है। श्रोता जानकारी में परिभाषित किया गया है क्योंकि यह public खेल वर्ग से सेट किया गया है।

AudioEmitter _emitter ध्वनि प्लेबैक के लिए 3 डी लागू करते समय उत्सर्जक की परिभाषा है। इस नमूने में, जब एक ध्वनि खेल रहा है, प्रत्येक उत्सर्जक वस्तु का मान करने के लिए _emitter सेट किया गया है, तो यह एक प्रपत्र है कि एक उदाहरण के रूप में एक साझा करता है। बेशक, आप प्रत्येक AudioEmitter वस्तु के लिए हो सकता है।

_activeSounds उस ध्वनि के बारे में जानकारी है जिसे आप पहले परिभाषित ActiveSound कक्षा में चला रहे हैं। क्योंकि उत्सर्जक जानकारी हर समय बदलती रहती है, इसका उपयोग स्थान जानकारी, आदि को अद्यतन करने के लिए और उन ध्वनि आवृत्तियों को छोड़ने के लिए किया जाता है जो खेलना समाप्त कर चुके हैं।

निर्माता

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

GameComponent चूंकि यह कक्षा को विरासत में प्राप्त करता है, Game इसलिए यह उदाहरण प्राप्त करता है और इसे आधार वर्ग में पारित करता है।

विधि प्रारंभ करें

/// <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 क्योंकि यह वर्ग को विरासत में मिलता है, इसे स्वचालित रूप से प्रारंभिक पर कहा जाता है।

SoundEffect.DistanceScale और SoundEffect.DopplerScale पैरामीटर 3 डी ध्वनि के लिए static समर्पित कर रहे हैं.

SoundEffect.DistanceScale दूर तक भी आवाज सुनना।

SoundEffect.DopplerScale डॉपलर प्रभाव का प्रभाव है। संख्या जितनी अधिक होगी, डॉपलर प्रभाव उतना ही अधिक होगा।

_soundNames लोड _soundEffects करने के लिए लूप में परिभाषित परिसंपत्ति नाम सहेजें.

निपटान विधि

/// <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 इसे स्वचालित रूप से खेल के अंत में कहा जाता है क्योंकि यह कक्षा को विरासत में मिलता है।

सभी आयातित ध्वनि परिसंपत्तियों को नष्ट करना।

अद्यतन विधि

/// <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 क्योंकि यह वर्ग को इनहेरिट करता है, इसे स्वचालित रूप से अद्यतन प्रक्रिया में कहा जाता है।

वर्तमान में चल रही ध्वनि की जाँच करें और, यदि यह Apply3D चल रहा है, तो उत्सर्जक से मेल खाने के लिए ध्वनि के स्थान को अपडेट करने के लिए विधि को कॉल करें। यदि कोई ध्वनि बजाना समाप्त हो गया है, तो आवृत्ति छोड़ दी जाती है।

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

बाहर से 3डी ध्वनि बजाने की प्रक्रिया। इसमें खेलने के लिए ध्वनि का नाम है, चाहे लूप करना है, और उत्सर्जक जानकारी है।

यदि आप कोई ध्वनि चलाना चाहते हैं, तो उस ध्वनि संसाधन से एक नई ध्वनि आवृत्ति बनाएँ जिसे आप _soundEffects में रखते हैं. SoundEffectInstance एक लूप भी हो सकता है या नहीं, इसलिए लूप जानकारी सेट करें।

चूंकि मैं एक खेल राज्य के रूप में ActiveSound बना रहा हूं, इसलिए मैंने उत्सर्जक जानकारी सेट की है जो वहां ध्वनि की प्लेबैक ऑब्जेक्ट है। यदि आप किसी ध्वनि पर 3D स्थान जानकारी लागू करना चाहते हैं, तो आपको वह मान मिलेगा जिसकी Emitter आपको आवश्यकता है.

Apply3D विधि नीचे वर्णित है, लेकिन यह एमिटर से ध्वनि के लिए 3 डी जानकारी लागू करने की प्रक्रिया है।

3 डी ध्वनि की मूल प्रक्रिया 3 डी जानकारी सेट के साथ प्लेबैक शुरू करने के SoundEffectInstance.Play लिए है। बाकी समय-समय पर 3 डी जानकारी को अपडेट करना है जब तक कि ध्वनि समाप्त नहीं हो जाती है।

लागू करें3D विधि

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

श्रोताओं और उत्सर्जकों का उपयोग करके एक निर्दिष्ट ध्वनि आवृत्ति पर 3 डी प्रभाव लागू करने की प्रक्रिया।

हम हर बार सामान्य आवृत्ति के _emitter के लिए मान सेट करते हैं। यदि आपके SoundEffectInstance.Apply3D पास पहले से ही AudioEmitter एक है, तो बस श्रोता और उत्सर्जक को विधि में पास करें।

Audio3DGame वर्ग

अंत में, आइए देखें कि गेम क्लास किस बारे में है।

खेत

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 में पंजीकृत करता है GameComponents , लेकिन इसे एक फ़ील्ड के रूप में है क्योंकि यह इसे व्यक्तिगत रूप से एक्सेस करता है।

अन्य लोग कुत्ते, बिल्ली संस्थाओं, जमीन ड्राइंग के लिए बनावट, क्वाडड्रावर, कैमरा जानकारी और इनपुट जानकारी को परिभाषित करते हैं।

निर्माता

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 के साथ जनरेट और GameComponents रजिस्टर करें।

आपने बिल्ली और कुत्ते की कक्षाएं भी उत्पन्न की हैं।

लोडकंट विधि

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

प्रत्येक ड्राइंग के लिए आवश्यक textures लोड करें।

QuadDrawer यहाँ उत्पन्न होता है GraphicsDevice क्योंकि आवश्यकता होती है।

अद्यतन विधि

/// <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 विधियां और UpdateCamera विधियां डिवाइस इनपुट को पुनर्प्राप्त करने और कैमरे को संभालने की प्रक्रिया हैं, जिस पर बाद में चर्चा की जाएगी।

चूंकि कैमरा स्थिति और श्रोता की स्थिति लगभग हमेशा समान होती है, इसलिए कैमरा अपडेट प्रक्रिया के बाद श्रोता को एक ही मान पर सेट किया जाता है।

_cat कॉल करें और _dog अद्यतन विधियों को स्थानांतरित करने के लिए और squeal, क्रमशः।

आरेखित विधि

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

कैमरा जानकारी से दृश्य और प्रक्षेपण रूपांतरण उत्पन्न करता है.

जमीन के लिए, QuadDrawer में खींचे गए आयत को लंबवत रूप से प्रदर्शित किया जाता है, इसलिए इसे क्षैतिज और मध्यम रूप से बड़ा करने के लिए घुमाया जाता है। _quadDrawer.DrawQuad विधि का दूसरा तर्क बनावट की पुनरावृत्ति की संख्या को निर्दिष्ट करता है, जो निर्दिष्ट करता है कि 32x32 शीट साथ-साथ दिखाई देते हैं।

_cat और _dog आंतरिक रूप से बिलबोर्ड किए जाते हैं, इसलिए कैमरे की स्थान जानकारी पारित और तैयार की जाती है।

हैंडलइनपुट विधि

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

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

कीबोर्ड और गेमपैड पर जानकारी हासिल की जाती है, और खेल का अंत निर्धारित किया जाता है।

अद्यतनCamera विधि

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

कैमरे को स्थानांतरित करने के लिए नियंत्रित किया जाता है।

इसमें त्वरण और घर्षण जैसी गणनाएं भी शामिल हैं, लेकिन मुझे लगता है कि यह शायद 3 डी ध्वनि पर डॉपलर प्रभाव को ध्यान में रख रहा है। चूंकि मैं गणना के बारे में कुछ खास नहीं करता हूं, इसलिए मैं इस पर चर्चा नहीं करूंगा।

सारांश

मैंने इसे लंबाई में कवर किया है, लेकिन आमतौर पर 3 डी ध्वनि खेलने के तरीके के लिए कक्षा को संदर्भित करने के लिए AudioManager पर्याप्त है। वास्तव में, अधिकांश कठिनाइयां ढांचे द्वारा की जाती हैं, क्योंकि हम जो SoundEffectInstance कर रहे हैं वह 3 डी जानकारी को सेट कर रहा है। यदि आपने केवल 3 डी ध्वनि के कुछ हिस्सों का नमूना लिया है, तो आप गेम क्लास में थोड़ा सा काम लिखना समाप्त कर देंगे। हालांकि, मैं मूल कहानी के आधार पर टिप्स लिख रहा हूं, इसलिए यह बहुत लंबा हो गया है।