오디오3D

페이지 업데이트 :
페이지 생성 날짜 :

이 팁에 대한 참고 사항

이 샘플은 다음 사이트에 게시된 프로그램을 기반으로 합니다. 일본어로 쉽게 이해하고 설명할 수 있도록 코드를 조금 바꿉니다. 기본적으로 원래 코드를 있는 것처럼 사용하므로 실제로 게임 프로그램에서 채택하는 경우 적시에 수정하고 사용합니다.

참조 사이트

또한 모노게임과 XNA에 대한 기본적인 지식이 있다는 가정하에 설명되어 있습니다. 모노게임 팁XNA 팁을 참조하십시오.

특히 수학, 벡터, 삼각함수, 행렬 등이 필수적이므로 어느 정도 는 무엇인지 알려주십시오.

환경

플랫폼
  • 윈도우 10
  • 코드는 다른 모노게임 지원 플랫폼에서 사용할 수 있습니다.
비주얼 스튜디오
  • 비주얼 스튜디오 2019
.NET 코어
  • 3.1
모노게임
  • 3.8

샘플 에 대해

카메라의 위치에 따라, 당신은 강아지의 위치와 고양이의 위치에서 전화를들을 수 있습니다. 고양이원이 원과 원을 그리며, 플레이어는 키로 카메라의 위치를 제어할 수 있습니다. 카메라의 위치 또는 고양이의 위치가 변경될 때마다 소리가 바뀌는지 확인합니다. 이어폰을 사용해 이해하기 쉽다고 생각합니다. 채널 5.1에서 확인되지 않았습니다.

작동 방법

키보드 게임 패드 (XInput) 마우스 터치를 할 수있는 일
카메라 앞뒤로 ↑↓ 왼쪽 스틱(상단 및 아래쪽) - -
카메라 방향 변경 ←→ 왼쪽 스틱(왼쪽 및 오른쪽) - -
게임의 끝 에크 (주) 뒤로 - -

준비해야 할 것

  • 개 비경발 오디오 파일
  • 세 고양이 비명 오디오 파일
  • 개 이미지 파일
  • 고양이 사진 파일
  • 접지 이미지 파일

공식 사이트의 원래 샘플은 미리 빌드된 콘텐츠 .xnb 파일을 사용합니다. 공식 사이트에 샘플을 유지하려면 mgcbs를 사용하지 말고 Visual Studio 솔루션에 직접 추가하고 빌드 시간에 복사하지 마십시오.

원래 샘플이 이 메서드를 사용하는 이유를 모르겠지만 이전 버전의 프로젝트를 마이그레이션하기 때문일 수 있습니다. 물론 mgcb를 사용하여 동일한 파일을 생성할 수 있습니다. 이 사이트에서 다운로드할 수 있는 프로젝트는 MGCB 버전으로 수정되었습니다.

프로그램

모든 코드에 대한 프로그램을 다운로드합니다.

이 샘플은 런타임에 사운드 재생이 잘 보이면서 코드를 좀 더 일반화하도록 설계되었습니다. Audio3D를 사용하면 코드가 훨씬 적지만 원래 샘플을 따라 설명됩니다. 덜 중요한 부분을 유지하겠습니다.

프로젝트는 다음 코드 파일로 구성됩니다.

  • 오디오3D게임
  • 오디오 관리자
  • 고양이
  • 아이오디오에미터
  • 프로그램
  • 쿼드 드로어
  • 스프라이트엔티티

쿼드러커 클래스

이 클래스는 직사각형 다각형 그리기를 위한 도우미 클래스입니다. 직사각형 다각형은 주로 3D 스프라이트(광고판)를 표시하는 데 사용됩니다. 이 팁은 고양이와 개를위한 광고판뿐만 아니라 땅의 직사각형 디스플레이에 사용됩니다.

이 클래스는 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 라는 변수를 지정할 수 있습니다. 정점텍스처.텍스처코디네이터가 0에서 1 범위를 초과하여 설정된 경우 텍스처는 기본적으로 반복적으로 그려집니다. 이를 사용하면 타일을 반복적으로 배치 할 수 있음을 표현할 수 있습니다. 사실, 지상에 체크 패턴은 여러 개의 간단한 흑백 이미지가 줄지어 있는 것처럼 보입니다.

IAudioEmitter 인터페이스

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

사운드를 방출하는 엔터티로 정의됩니다. 이번에는 소리를 방출하는 엔티티는 개와 고양이이기 때문에 각자의 수업에서 상속받습니다. 에미터는 다음과 같은 정보가 필요합니다.

속성 사용
위치 엔터티 위치
전달 엔터티가 직면한 방향(벡터)
위로 엔터티의 최대입니다. 머리가 사람에 존재하는 방향
속도 엔터티가 이동하는 속도입니다. 도플러 값을 계산하는 데 사용됩니다.

스프라이트엔티티어 클래스

3D 스프라이트(광고판)를 나타내는 클래스입니다. 그것은 또한 방출기이며 상속됩니다 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; }

법인 등의 위치 정보가 있습니다. 기본적으로 나는 방사체로 정보를 가지고있다. 또한 드로잉 엔터티이므로 표시할 이미지(Texture)도 있습니다.

업데이트 방법

/// <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 클래스를 상속합니다. 개는 3D 공간에서 고정 된 위치에 남아 있습니다.

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

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

_timeDelay 울음을 재생하는 간격으로 사용됩니다.

SoundEffectInstance _activeSound 사운드를 재생하는 인스턴스입니다. SoundEffectInstance 사운드 재생 클래스에서 자주 볼 수 있듯이 3D 사운드와 마찬가지로 이 것을 사용할 수 있습니다. 그런데 _activeSound 나중에 AudioManager 클래스에서 만 참조를 받을 수 있으므로 Dot 클래스 측면에서 는 삭제하지 않습니다.

업데이트 방법

/// <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 외침의 이름, 루프 정보 및 방사체로 자신의 정보를 전달하여 3D 공간에서 재현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 나는 방사체인 방법에 자신을 전달하고 있다. 사운드의 재생 위치가 하나씩 변경되는 것을 볼 수 있습니다.

오디오 매니저 클래스

이것은 마침내 Audio3D의 본질입니다. 3D 사운드는 수신기와 방사체로 구성됩니다. 이방자는 이미 개와 고양이를 정의하므로 AudioManager 클래스는 청취자를 정의합니다. 일반적으로 여러 방사체가 있지만 수신기는 하나뿐입니다.

이 클래스는 클래스의 구성 요소를 상속하고Game 등록 GameComponent 하고 사용합니다.

액티브사운드 클래스

/// <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 사운드 재생에 3D를 적용할 때 방사체의 정의입니다. 이 샘플에서는 사운드를 재생할 때 각 방사체 개체의 값이 설정 _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 3D SoundEffect.DopplerScale 사운드 전용 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 경우 방법을 호출하여 방사체에 맞게 사운드위치를 업데이트합니다. 사운드재생이 완료되면 인스턴스가 삭제됩니다.

Play3D사운드 방법

/// <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 사운드를 재생하는 과정. 재생할 소리의 이름, 반복 여부 및 방사체 정보가 있습니다.

사운드를 재생하려면 _soundEffects 유지되는 사운드 리소스에서 새 사운드 인스턴스를 만듭니다. SoundEffectInstance 루프를 가질 수도 있으므로 루프 정보를 설정합니다.

재생 상태로 만들고 ActiveSound 있기 때문에 사운드의 재생 개체인 방사체 정보를 설정합니다. 소리 Emitter 에 3D 위치 정보를 적용하려면 필요한 값을 얻을 수 있습니다.

Apply3D 이 방법은 아래에 설명되어 있지만 방사체에서 사운드에 3D 정보를 적용하는 과정입니다.

3D 사운드의 기본 프로세스는 3D 정보 세트로 SoundEffectInstance.Play 재생을 시작하는 것입니다. 나머지는 소리가 재생이 완료 될 때까지 주기적으로 3D 정보를 업데이트하는 것입니다.

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

수신기 및 이미터를 사용하여 지정된 사운드 인스턴스에 3D 효과를 적용하는 프로세스입니다.

매번 공통 인스턴스의 _emitter 값을 설정합니다. 이미 AudioEmitter 있는 경우 SoundEffectInstance.Apply3D 수신기와 방사체를 메서드에 전달하기만 하면 됩니다.

오디오3D게임 클래스

마지막으로 게임 클래스의 내용을 살펴보겠습니다.

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 에 등록하지만 개별적으로 액세스하기 때문에 필드로 가지고 있습니다.

다른 사람들은 개, 고양이 엔티티, 접지 드로잉텍스처, 쿼드드로잉, 카메라 정보 및 입력 정보를 정의합니다.

생성자

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

각 도면에 필요한 텍스처를 로드합니다.

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 업데이트 메서드를 호출합니다.

그리기 방법

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

키보드와 게임 패드에 대한 정보가 획득되고 게임의 종료가 결정됩니다.

업데이트 카메라 방법

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

카메라가 제어되어 이동합니다.

또한 가속 및 마찰과 같은 계산도 포함되어 있지만 3D 사운드에 대한 도플러 효과를 고려할 것입니다. 나는 계산 자체에 대해 특별한 아무것도하지 않기 때문에, 나는 그것을 논의하지 않습니다.

요약

나는 길이로 덮여 있지만, 일반적으로 3D 사운드를 재생하는 방법에 대한 AudioManager 클래스를 참조하기에 충분하다. 사실, 대부분의 어려움은 프레임워크에 의해 수행되는데, 왜냐하면 우리가 하고 있는 일은 SoundEffectInstance 3D 정보를 로 설정하는 것이기 때문입니다. 3D 사운드의 일부만 샘플링한 경우 게임 클래스에서 약간의 작업을 작성하게 됩니다. 그러나 원래 스토리를 기반으로 팁을 쓰고 있으므로 훨씬 더 오래 되었습니다.