Âm thanh3D

Trang Cập Nhật :
Ngày tạo trang :

Ghi chú về Mẹo này

Mẫu này dựa trên các chương trình được công bố trên các trang web sau. Tôi thay đổi mã một chút để dễ hiểu và giải thích nó bằng tiếng Nhật. Về cơ bản, chúng tôi sử dụng mã gốc như hiện tại, vì vậy nếu bạn thực sự áp dụng nó trong chương trình trò chơi của mình, hãy sửa nó kịp thời và sử dụng nó.

Trang tham chiếu

Ngoài ra, nó được giải thích trên giả định rằng bạn có một số kiến thức cơ bản về MonoGame và XNA. Xem Mẹo MonoGameMẹo XNA cho bánh lái.

Đặc biệt, vì toán học, vectơ, hàm lượng giác, ma trận, v.v. là điều cần thiết, vì vậy hãy biết chúng là gì ở một mức độ nào đó.

môi trường

nền tảng
  • Windows 10
  • Mã có thể được sử dụng trên các nền tảng hỗ trợ MonoGame khác
Visual Studio
  • Visual Studio 2019
.NET Core
  • 3.1
MonoGame
  • 3.8

Giới thiệu về mẫu

Dựa trên vị trí của máy ảnh, bạn có thể nghe thấy cuộc gọi từ vị trí của và vị trí của con mèo. Con mèo vòng tròn và vòng tròn nguồn gốc, và người chơi có thể điều khiển vị trí của máy ảnh bằng chìa khóa. Hãy chắc chắn rằng cách bạn nghe âm thanh thay đổi với mỗi thay đổi ở vị trí của máy ảnh hoặc vị trí của con mèo. Tôi nghĩ rằng thật dễ hiểu khi sử dụng tai nghe. Tôi chưa được xác nhận trên kênh 5.1.

Cách vận hành

Làm gì để làm Bàn phím Gamepad (XInput) Mouse Touch
Máy ảnh về phía trước và phía sau ↑↓ Gậy trái (Trên và Dưới) - -
Thay đổi hướng camera ←→ Gậy trái (Trái và Phải) - -
Kết thúc trò chơi Esc Lưng - -

Những gì cần chuẩn bị

  • Tệp âm thanh tiếng rít chó
  • Ba tệp âm thanh ré lên mèo
  • Tệp Hình ảnh Chó
  • Tệp ảnh mèo
  • Tệp ảnh mặt đất

Mẫu gốc trên trang web chính thức sử dụng nội dung xây dựng sẵn .xnb tệp. Nếu bạn muốn giữ các mẫu trên trang web chính thức, không sử dụng mgcb, thêm chúng trực tiếp vào giải pháp Visual Studio của bạn và sao chép chúng tại thời điểm xây dựng.

Tôi không biết tại sao mẫu ban đầu lại sử dụng phương pháp này, nhưng tôi nghĩ có lẽ vì chúng tôi đang di chuyển các phiên bản cũ hơn của dự án như hiện tại. Tất nhiên, bạn có thể sử dụng mgcb để tạo cùng một tệp. Các dự án có thể được tải xuống trên trang web này đã được sửa đổi thành phiên bản MGCB.

chương trình

Tải xuống chương trình cho tất cả các mã.

Mẫu này được thiết kế để làm cho mã trông tổng quát hơn một chút trong khi làm cho việc phát lại âm thanh trông đẹp trong thời gian chạy. Sử dụng Audio3D sẽ chỉ ít mã hơn nhiều, nhưng nó được mô tả dọc theo mẫu gốc. Tôi sẽ giữ những phần ít quan trọng hơn.

Dự án bao gồm các tệp mã sau:

  • Audio3DGame
  • AudioManager
  • Mèo
  • Chó
  • IAudioEmitter
  • Chương trình
  • QuadDrawer
  • SpriteEntity

Lớp QuadDrawer

Lớp này là một lớp trợ giúp để vẽ đa giác hình chữ nhật. Đa giác hình chữ nhật thường được sử dụng chủ yếu để hiển thị sprite 3D (bảng quảng cáo). Mẹo này được sử dụng cho bảng quảng cáo cho mèo và chó, cũng như cho màn hình chữ nhật của mặt đất.

Lớp học này không liên quan gì đến Audio3D.

trường

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

Thông tin tối thiểu cần thiết để vẽ đa giác. Vẽ đa giác từ dữ liệu đỉnh mà không cần chuẩn bị dữ liệu mô hình.

Constructor

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

Bởi vì lớp này có thể sử dụng phổ biến, bạn GraphicsDevice nhận được một phiên bản được tạo trong quá trình khởi tạo lớp trò chơi.

Ở đây, chúng tôi đặt hiệu ứng cần thiết để vẽ sprite và vị trí của 4 đỉnh cần thiết cho đa giác hình chữ nhật. Kích thước nên được thu nhỏ khi vẽ, vì vậy nó là -1 đến 1.

Phương pháp 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);
}

Đặt kết cấu đã truyền thành hình chữ nhật và vẽ nó. Vì đây là một quá trình cơ bản, không có gì để lưu ý.

Nếu có một điểm, một biến được gọi là có thể được chỉ định trong textureRepeats đối số, để tọa độ của kết cấu có thể được thay đổi. Nếu vertexPositionTexture.TextureCoordinate được đặt ngoài phạm vi từ 0 đến 1, kết cấu được vẽ nhiều lần theo mặc định. Sử dụng nó, có thể thể hiện rằng gạch có thể được sắp xếp nhiều lần. Trên thực tế, các mẫu ca rô trên mặt đất dường như có nhiều hình ảnh đen trắng đơn giản được xếp hàng.

Giao diện IAudioEmitter

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

Được định nghĩa là một thực thể phát ra âm thanh. Vì các thực thể phát ra âm thanh lần này là chó và mèo, chúng được thừa hưởng trong các lớp tương ứng của chúng. Emitter cần các thông tin sau:

Sử
dụng tài sản
Vị trí Vị trí thực thể
Về phía trước Hướng mà thực thể đang phải đối mặt (vector)
Lên Sự trỗi dậy của thực thể. Hướng mà đầu tồn tại trong một người
Vận tốc Tốc độ mà thực thể di chuyển. Được sử dụng để tính giá trị Doppler.

Lớp SpriteEntity

Một lớp học để đại diện cho sprites 3D (bảng quảng cáo). Nó cũng là một bộ phát, và thừa hưởng IAudioEmitter . Chó và mèo thừa hưởng lớp học này.

tài sản

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

Nó có thông tin vị trí của thực thể, v.v. Về cơ bản, tôi có thông tin như một người phát ra. Nó cũng là một thực thể vẽ, vì vậy nó cũng có một hình ảnh (Texture) để hiển thị.

Phương pháp cập nhật

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

Mô tả vị trí của thực thể và quá trình phát âm thanh, nhưng thực hiện nó trong lớp có nguồn gốc.

Phương pháp vẽ

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

Chó và mèo có hình ảnh và vị trí khác nhau, nhưng cơ chế vẽ khác hoàn toàn giống nhau, vì vậy tôi mô tả chúng ở đây.

Mỗi biến đổi và kết cấu được chuyển đến QuadDrawer để hiển thị một đa giác hình chữ nhật. Vì chuyển đổi phối hợp là kiến thức cơ bản, giải thích không được đề cập.

Matrix.CreateConstrainedBillboard Sử dụng phương pháp và thông tin máy ảnh để dễ dàng đại diện cho bảng quảng cáo, vì vậy hãy sử dụng chúng hiệu quả.

Lớp học chó

Đó là một lớp học thực hiện vẽ chó và hát phát lại. SpriteEntity Kế thừa lớp học. vẫn ở một vị trí cố định trong không gian 3D.

trường

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

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

_timeDelay Được sử dụng trong khoảng thời gian để chơi tiếng khóc.

SoundEffectInstance _activeSound Là một ví dụ để chơi một âm thanh. SoundEffectInstance Như bạn thường thấy trong lớp phát lại âm thanh, bạn có thể sử dụng điều này như trong âm thanh 3D. Nhân tiện _activeSound , tôi chỉ nhận được một tài liệu tham khảo từ lớp AudioManager sau đó, vì vậy tôi sẽ không loại bỏ nó ở phía lớp Dot.

Phương pháp cập nhật

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

Trong mẫu này, vẫn ở cùng một vị trí trong một thời gian dài, vì vậy bốn thông số đầu tiên được chỉ định bằng một cuộc tấn công quyết định. Vẽ được thực hiện trong lớp cơ bản.

_timeDelay sau đó được sử dụng làm thời gian còn lại để dừng lại, chơi tiếng khóc.

AudioManager Sẽ đượcPlay3DSound sao chép trong không gian 3D bằng cách chuyển tên của tiếng khóc, thông tin vòng lặp và thông tin của riêng bạn như một bộ phát ra .

Lớp Dog được thiết kế để lặp lại tiếng khóc, vì vậy bạn không phải suy nghĩ quá sâu vì đó chỉ là một sự điều chỉnh, chẳng hạn như chơi hoặc ngừng phân nhánh.

Lớp mèo

Đây là một lớp học thực hiện vẽ mèo và hát phát lại. SpriteEntity Kế thừa lớp học. Con mèo đang di chuyển xung quanh nguồn gốc.

trường

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

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

_timeDelay được sử dụng theo cách tương tự như lớp Dog, với thời gian còn lại trước tiếng kêu tiếp theo.

Có ba loại cuộc gọi mèo được chọn và phát ngẫu nhiên, nhưng chúng không liên quan gì đến Audio3D vì chúng là một yếu tố thưởng.

Phương pháp cập nhật

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

Vì con mèo quay xung quanh nguồn gốc theo chuyển động tròn, nó xử lý nó để nó di chuyển quỹ đạo của vòng tròn bằng cách sử dụng chức năng lượng giác. Kết quả là, vị trí, phía trướcVận tốc đã thay đổi từng cái một. Do đó, khi bạn chạy chương trình, bạn có thể thấy rằng tiếng kêu của con mèo đang xoay quanh ngay cả khi bạn không di chuyển máy ảnh.

_timeDelay Mã sau đây là một quá trình trong đó tiếng kêu của mèo được phân ngẫu nhiên và chơi đều đặn. audioManager.Play3DSound Tôi đang chuyển mình sang phương pháp là một người phát ra. Bạn có thể thấy rằng vị trí phát lại của âm thanh thay đổi từng cái một.

Lớp AudioManager

Đây là bản chất của Audio3D. Một âm thanh 3D bao gồm một người nghe và một bộ phát. Bộ phát đã định nghĩa chó và mèo, vì vậy lớp AudioManager định nghĩa người nghe. Thường có nhiều bộ phát, trong khi chỉ có một người nghe.

Lớp này kế thừa vàGame đăng ký GameComponent và sử dụng thành phần trong lớp.

Lớp ActiveSound

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

Nó được định nghĩa ở dưới cùng của mã, nhưng nó là một lớp để bảo tồn trạng thái đang chơi. Nó có thông tin về phiên bản âm thanh đang được phát và bộ phát đang được phát.

trường

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 xác định tên của tệp âm thanh (tên tài sản) để tải. Vì nó là một chương trình mẫu, nó được định nghĩa để tải các tập tin âm thanh với số lượng lớn đầu tiên. Dữ liệu âm thanh đã nhập được _soundEffects lưu trữ trong .

AudioListener Listener Đó là định nghĩa của người nghe. Thông tin người nghe được định nghĩa bởi vì nó public được đặt từ lớp Trò chơi.

AudioEmitter _emitter là định nghĩa của bộ phát khi áp dụng 3D để phát lại âm thanh. Trong mẫu này, khi phát âm thanh, giá trị của mỗi đối tượng phát được đặt thành _emitter , vì vậy nó là một biểu mẫu chia sẻ một như một ví dụ. Tất nhiên, bạn có thể có cho mỗi AudioEmitter đối tượng.

_activeSounds Có thông tin về âm thanh bạn đang phát trong lớp bạn đã xác định ActiveSound trước đó. Bởi vì thông tin bộ phát thay đổi mọi lúc, nó được sử dụng để cập nhật thông tin vị trí, v.v., và để loại bỏ các phiên bản âm thanh đã phát xong.

Constructor

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

GameComponent Vì nó kế thừa lớp, Game nó nhận được phiên bản và chuyển nó sang lớp cơ sở.

Khởi tạo phương pháp

/// <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 Bởi vì nó kế thừa lớp, nó được tự động gọi là khởi tạo.

SoundEffect.DistanceScaleSoundEffect.DopplerScale là các thông số dành riêng cho static âm thanh 3D.

SoundEffect.DistanceScale Để nghe âm thanh ngay cả ở phía xa.

SoundEffect.DopplerScale Là ảnh hưởng của hiệu ứng Doppler. Số lượng càng cao, hiệu ứng Doppler càng lớn.

_soundNames Lưu tên tài sản được xác định trong vòng lặp để tải _soundEffects .

Phương pháp xử lý

/// <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 Nó được tự động gọi vào cuối trò chơi vì nó kế thừa lớp học.

Phá hủy tất cả các tài sản âm thanh nhập khẩu.

Phương pháp cập nhật

/// <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 Bởi vì nó kế thừa lớp, nó được tự động gọi trong quá trình cập nhật.

Kiểm tra âm thanh hiện đang phát và, nếu nó Apply3D đang phát, hãy gọi phương pháp cập nhật vị trí của âm thanh để phù hợp với bộ phát. Nếu bất kỳ âm thanh nào đã phát xong, phiên bản sẽ bị loại bỏ.

Phương pháp 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;
}

Quá trình phát âm thanh 3D từ bên ngoài. Nó có tên của âm thanh để chơi, cho dù để vòng lặp, và phát ra thông tin.

Nếu bạn muốn phát âm thanh, hãy tạo một phiên bản âm thanh mới từ tài nguyên âm thanh mà bạn giữ trong _soundEffects. SoundEffectInstance cũng có thể có một vòng lặp hoặc không, vì vậy hãy đặt thông tin vòng lặp.

Vì tôi đang tạo như ActiveSound một trạng thái chơi, tôi đặt thông tin phát ra là đối tượng phát lại của âm thanh ở đó. Nếu bạn muốn áp dụng thông tin vị trí 3D cho âm thanh, bạn sẽ Emitter nhận được giá trị bạn cần.

Apply3D Phương pháp được mô tả dưới đây, nhưng đó là quá trình áp dụng thông tin 3D từ bộ phát vào âm thanh.

Quá trình cơ bản của âm thanh 3D là bắt đầu phát lại với SoundEffectInstance.Play bộ thông tin 3D. Phần còn lại là cập nhật thông tin 3D định kỳ cho đến khi âm thanh phát xong.

Phương pháp Apply3D

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

Quá trình áp dụng hiệu ứng 3D cho một phiên bản âm thanh được chỉ định bằng cách sử dụng người nghe và bộ phát.

Chúng tôi đặt giá trị cho _emitter của phiên bản chung mỗi lần. Nếu bạn SoundEffectInstance.Apply3D đã AudioEmitter có một, chỉ cần chuyển người nghe và bộ phát cho phương pháp.

Lớp Audio3DGame

Cuối cùng, chúng ta hãy xem lớp trò chơi là gì.

trường

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 Đăng ký vào , nhưng có nó như một lĩnh vực vì nó truy cập nó riêng lẻ.

Những người khác xác định các thực thể chó, mèo, kết cấu cho bản vẽ mặt đất, tứ giác, thông tin máy ảnh và thông tin đầu vào.

Constructor

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 Tạo và GameComponents đăng ký với .

Bạn cũng đã tạo ra các lớp học Mèo và Chó.

Phương pháp LoadContent

/// <summary>
/// グラフィックコンテンツをロードします。
/// </summary>
protected override void LoadContent()
{
  _cat.Texture = Content.Load<Texture2D>("CatTexture");
  _dog.Texture = Content.Load<Texture2D>("DogTexture");

  _checkerTexture = Content.Load<Texture2D>("checker");

  // 四角形ポリゴンを描画するためのクラス
  _quadDrawer = new QuadDrawer(_graphics.GraphicsDevice);
}

Tải các kết cấu cần thiết cho mỗi bản vẽ.

QuadDrawer Được GraphicsDevice tạo ra ở đây vì yêu cầu.

Phương pháp cập nhật

/// <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 Các phương pháp và UpdateCamera phương pháp là quá trình truy xuất đầu vào thiết bị và xử lý máy ảnh, sẽ được thảo luận sau.

Vì vị trí máy ảnh và vị trí người nghe hầu như luôn giống nhau, người nghe được đặt cùng một giá trị sau quá trình cập nhật máy ảnh.

_cat Gọi các phương pháp và _dog Cập nhật để di chuyển và ré lên, tương ứng.

Phương pháp vẽ

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

Tạo ra các chuyển đổi xem và chiếu từ thông tin máy ảnh.

Đối với mặt đất, hình chữ nhật được vẽ trong QuadDrawer được hiển thị theo chiều dọc, vì vậy nó được xoay theo chiều ngang và mở rộng vừa phải. _quadDrawer.DrawQuad Đối số thứ hai của phương pháp chỉ định số lần lặp lại của kết cấu, trong đó chỉ định rằng các tấm 32x32 xuất hiện cạnh nhau.

_cat và _dog được gắn biển quảng cáo nội bộ, vì vậy thông tin vị trí của máy ảnh được truyền và rút ra.

Phương pháp HandleInput

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

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

Thông tin trên bàn phím và gamepad được thu thập, và kết thúc của trò chơi được xác định.

Phương pháp 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;
}

Camera được điều khiển để di chuyển.

Nó cũng bao gồm các tính toán như tăng tốc và ma sát, nhưng tôi nghĩ rằng nó có thể tính đến hiệu ứng Doppler trên âm thanh 3D. Vì tôi không làm bất cứ điều gì đặc biệt về bản thân tính toán, tôi sẽ không thảo luận về nó.

Tóm tắt

Tôi đã đề cập đến nó rất lâu, nhưng nó thường đủ để tham khảo lớp học AudioManager về cách chơi âm thanh 3D. Trên thực tế, hầu hết các khó khăn được thực hiện bởi khuôn khổ, bởi vì những gì SoundEffectInstance chúng tôi đang làm là thiết lập thông tin 3D vào . Nếu bạn chỉ lấy mẫu các phần của âm thanh 3D, cuối cùng bạn sẽ viết một chút công việc trong lớp Trò chơi. Tuy nhiên, tôi đang viết Mẹo dựa trên câu chuyện gốc, vì vậy nó đã lâu hơn rất nhiều.