Audio3D

Actualización de la página :
Fecha de creación de la página :

Notas sobre estos consejos

Este ejemplo se basa en los programas publicados en los siguientes sitios. Cambio un poco el código para que sea más fácil de entender y explicar en japonés. Básicamente, usamos el código original tal cual, por lo que si realmente lo adopta en su programa de juego, corríjalo de manera oportuna y úselo.

Sitio de referencia

Además, se explica asumiendo que tiene algunos conocimientos básicos sobre MonoGame y XNA. Consulte Consejos de MonoGame y Consejos de XNA para el ruddly.

En particular, como las matemáticas, los vectores, las funciones trigonométricas, las matrices, etc. son esenciales, así que por favor sepa cuáles son hasta cierto punto.

medio ambiente

plataforma
  • Windows 10
  • El código se puede utilizar en otras plataformas habilitadas para MonoGame
Visual Studio
  • Visual Studio 2019
.NET Core
  • 3.1
MonoJuego
  • 3.8

Acerca de las muestras

Según la posición de la cámara, puede escuchar la llamada desde la posición del perro y la posición del gato. El gato rodea y rodea el origen, y el jugador puede controlar la posición de la cámara con la tecla. Asegúrese de que la forma en que escucha el sonido cambia con cada cambio en la posición de la cámara o la posición del gato. Creo que es fácil de entender usando auriculares. No estoy confirmado en el canal 5.1.

Cómo operar

Qué hacer con el teclado Gamepad (XInput) Mouse Touch
Cámara hacia adelante y hacia atrás ↑↓ Stick izquierdo (superior e inferior) - -
Cambiar la orientación de la cámara ←→ Stick izquierdo (izquierda y derecha) - -
Fin del juego Esc Atrás - -

Qué preparar

  • Archivo de audio de chillido de perro
  • Tres archivos de audio chillones de gato
  • Archivo de imagen de perro
  • Archivo de imagen de gato
  • Archivo de imagen de tierra

El ejemplo original en el sitio oficial utiliza archivos .xnb de contenido precompilados . Si desea mantener los ejemplos en el sitio oficial, no use mgcbs, agréguelos directamente a la solución de Visual Studio y cópielos en el momento de la compilación.

No sé por qué la muestra original está tomando este método, pero creo que probablemente se deba a que estamos migrando versiones anteriores del proyecto tal como están. Por supuesto, puede usar mgcb para generar el mismo archivo. Los proyectos que se pueden descargar en este sitio han sido modificados a la versión MGCB.

programa

Descargue el programa para obtener todo el código.

Este ejemplo está diseñado para hacer que el código se vea un poco más general mientras hace que la reproducción de sonido se vea bien en tiempo de ejecución. Usar Audio3D solo sería mucho menos código, pero se describe a lo largo de la muestra original. Me quedaré con las partes menos importantes.

El proyecto consta de los siguientes archivos de código:

  • Audio3DGame
  • AudioManager
  • Gato
  • Perro
  • IAudioEmitter
  • Programa
  • QuadDrawer
  • SpriteEntidad

Clase QuadDrawer

Esta clase es una clase auxiliar para dibujar polígonos rectangulares. Los polígonos rectangulares a menudo se usan principalmente para mostrar sprites 3D (vallas publicitarias). Este consejo se utiliza para vallas publicitarias para gatos y perros, así como para exhibiciones rectangulares del suelo.

Esta clase no tiene nada que ver con Audio3D.

campo

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

Información mínima requerida para dibujar polígonos. Dibuje polígonos a partir de datos de vértices sin preparar datos de modelo.

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

Dado que esta clase se puede usar universalmente, GraphicsDevice recibirá una instancia creada en el proceso de inicialización de la clase de juego.

Aquí, establecemos el efecto necesario para dibujar el sprite y la posición de los 4 vértices requeridos para el polígono rectangular. El tamaño debe escalarse al dibujar, por lo que es de -1 a 1.

Método 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);
}

Establece la textura pasada en un rectángulo y la dibuja. Dado que este es un proceso básico, no hay nada que tener en cuenta.

Si hay un punto, se puede especificar una variable llamada en textureRepeats el argumento, de modo que se puedan cambiar las coordenadas de la textura. Si vertexPositionTexture.TextureCoordinate se establece más allá del rango de 0 a 1, la textura se dibuja repetidamente de forma predeterminada. Al usarlo, es posible expresar que los azulejos se pueden organizar repetidamente. De hecho, los patrones a cuadros en el suelo parecen tener múltiples imágenes simples en blanco y negro alineadas.

Interfaz IAudioEmitter

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

Definido como una entidad que emite sonido. Dado que las entidades que emiten sonido esta vez son perros y gatos, se heredan en sus respectivas clases. El emisor necesita la siguiente información:

Uso de la propiedad
Posición Posición de la entidad
Adelante La dirección a la que se enfrenta la entidad (vector)
Hacia arriba El ascenso de la entidad. La dirección en la que existe la cabeza en una persona
Velocidad La velocidad a la que se mueve la entidad. Se utiliza para calcular los valores Doppler.

Clase SpriteEntity

Una clase para representar sprites 3D (vallas publicitarias). También es un emisor, y hereda IAudioEmitter . Los perros y gatos heredan esta clase.

propiedad

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

Tiene la información de ubicación de la entidad, etc. Básicamente tengo información como emisor. También es una entidad de dibujo, por lo que también tiene una imagen (Textura) para mostrar.

Método de actualización

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

Describe la posición de la entidad y el proceso de reproducción de sonido, pero lo implementa en la clase derivada.

Método de dibujo

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

Los perros y los gatos tienen diferentes imágenes y posiciones, pero el otro mecanismo de dibujo es exactamente el mismo, así que los describo aquí.

Cada transformación y textura se pasa a QuadDrawer para mostrar un polígono rectangular. Dado que la transformación de coordenadas es un conocimiento básico, las explicaciones no están cubiertas.

Matrix.CreateConstrainedBillboard Use el método y la información de la cámara para representar fácilmente las vallas publicitarias, así que haga un uso efectivo de ellas.

Clase de perro

Es una clase que hace reproducción de dibujo y canto de perros. SpriteEntity Heredar la clase. El perro permanece en una posición fija en el espacio 3D.

campo

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

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

_timeDelay se utiliza a intervalos para reproducir el llanto.

SoundEffectInstance _activeSound es una instancia para reproducir un sonido. SoundEffectInstance Como verá a menudo en la clase de reproducción de sonido, puede usar esto como en el sonido 3D. Por cierto _activeSound , solo recibo una referencia de la clase AudioManager más tarde, por lo que no la descartaré en el lado de la clase Dot.

Método de actualización

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

En esta muestra, el perro permanece en la misma posición durante mucho tiempo, por lo que los primeros cuatro parámetros se especifican mediante un golpe decisivo. El dibujo se realiza en la clase básica.

_timeDelay se utiliza como el tiempo restante para detenerse, reproduciendo el grito.

AudioManager se reproduciráPlay3DSound en el espacio 3D pasando el nombre del grito, la información del bucle y su propia información como emisor a .

La clase Dog está diseñada para repetir el llanto, por lo que no tienes que pensar demasiado profundamente porque es solo un ajuste, como jugar o detener la ramificación.

Clase Cat

Es una clase que hace dibujo de gatos y reproducción de cantos. SpriteEntity Heredar la clase. El gato se mueve por el origen.

campo

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

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

_timeDelay se usa de la misma manera que la clase Dog, con el resto del tiempo antes del siguiente chillido.

Hay tres tipos de llamadas de gatos que se seleccionan y reproducen al azar, pero no tienen nada que ver con Audio3D porque son un elemento adicional.

Método de actualización

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

Dado que el gato gira alrededor del origen en un movimiento circular, lo procesa para que mueva la trayectoria del círculo utilizando una función trigonométrica. Como resultado, la posición, el avance y la velocidad han cambiado uno tras otro. Por lo tanto, cuando ejecuta el programa, puede ver que el llanto del gato está dando vueltas incluso si no mueve la cámara.

_timeDelay El siguiente código es un proceso en el que el llanto del gato se asigna aleatoriamente y se reproduce a intervalos regulares. audioManager.Play3DSound Me estoy pasando al método que es un emisor. Puede ver que la posición de reproducción del sonido cambia una por una.

Clase AudioManager

Esta es finalmente la esencia de Audio3D. Un sonido 3D consiste en un oyente y un emisor. El emisor ya define perros y gatos, por lo que la clase AudioManager define a los oyentes. Por lo general, hay múltiples emisores, mientras que solo hay un oyente.

Esta clase hereda yGame registra GameComponent y utiliza el componente de la clase.

Clase ActiveSound

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

Se define en la parte inferior del código, pero es una clase para preservar el estado que se está reproduciendo. Tiene información sobre la instancia de sonido que se está reproduciendo y el emisor que se está reproduciendo.

campo

// このマネージャーにロードされるすべてのサウンドエフェクトのリスト。
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 define el nombre del archivo de audio (nombre del recurso) que se va a cargar. Dado que es un programa de muestra, se define cargar el archivo de audio en masa primero. Los datos sonoros importados se _soundEffects almacenan en .

AudioListener Listener es la definición del oyente. La información del oyente se define en porque se public establece a partir de la clase Game.

AudioEmitter _emitter es la definición del emisor al aplicar 3D a la reproducción de sonido. En este ejemplo, al reproducir un sonido, el valor de cada objeto emisor se establece en _emitter , por lo que es un formulario que comparte uno como instancia. Por supuesto, puede tener para cada AudioEmitter objeto.

_activeSounds tiene información sobre el sonido que está reproduciendo en la clase que definió ActiveSound anteriormente. Debido a que la información del emisor cambia todo el tiempo, se utiliza para actualizar la información de ubicación, etc., y para descartar instancias de sonido que han terminado de reproducirse.

constructor

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

GameComponent Dado que hereda la clase, Game recibe la instancia y la pasa a la clase base.

Método Initialize

/// <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 Debido a que hereda la clase, se llama automáticamente en la inicialización.

SoundEffect.DistanceScale y SoundEffect.DopplerScale son parámetros dedicados al static sonido 3D.

SoundEffect.DistanceScale para escuchar el sonido incluso en la distancia.

SoundEffect.DopplerScale es la influencia del efecto Doppler. Cuanto mayor sea el número, mayor será el efecto Doppler.

_soundNames Guarde el nombre del activo definido en un bucle para cargar _soundEffects .

Método Dispose

/// <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 Se llama automáticamente al final del juego porque hereda la clase.

Destruir todos los activos sólidos importados.

Método de actualización

/// <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 Debido a que hereda la clase, se llama automáticamente en el proceso de actualización.

Compruebe el sonido que se está reproduciendo actualmente y, si se Apply3D está reproduciendo, llame al método para actualizar la ubicación del sonido para que coincida con el emisor. Si algún sonido ha terminado de reproducirse, la instancia se descarta.

Método 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;
}

El proceso de reproducir sonido 3D desde el exterior. Tiene el nombre del sonido a reproducir, si se va a repetir, y la información del emisor.

Si desea reproducir un sonido, cree una nueva instancia de sonido a partir del recurso de sonido que mantenga en el _soundEffects. SoundEffectInstance también puede tener un bucle o no, así que establezca la información del bucle.

Como estoy creando como ActiveSound un estado de reproducción, establezco la información del emisor que es el objeto de reproducción del sonido allí. Si desea aplicar información de ubicación 3D a un sonido, obtendrá Emitter el valor que necesita.

Apply3D El método se describe a continuación, pero es el proceso de aplicar información 3D del emisor al sonido.

El proceso básico del sonido 3D es iniciar la reproducción con SoundEffectInstance.Play el conjunto de información 3D. El resto es actualizar la información 3D periódicamente hasta que el sonido termine de reproducirse.

Método 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);
}

El proceso de aplicar un efecto 3D a una instancia de sonido especificada utilizando oyentes y emisores.

Establecemos el valor en el _emitter de la instancia común cada vez. SoundEffectInstance.Apply3D Si ya AudioEmitter tiene uno, simplemente pase el oyente y el emisor al método.

Clase Audio3DGame

Finalmente, veamos de qué se trata la clase Game.

campo

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 Se registra GameComponents en , pero lo tiene como campo porque accede a él individualmente.

Otros definen entidades de perros, gatos, texturas para dibujo del suelo, quaddrawer, información de la cámara e información de entrada.

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 Generar y GameComponents registrarse con .

También has generado las clases de Gato y Perro.

Método 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);
}

Cargue las texturas necesarias para cada dibujo.

QuadDrawer se GraphicsDevice genera aquí porque requiere .

Método de actualización

/// <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 Los métodos y UpdateCamera métodos son el proceso de recuperar la entrada del dispositivo y manejar la cámara, que se discutirá más adelante.

Dado que la posición de la cámara y la posición del oyente son casi siempre las mismas, el oyente se establece en el mismo valor después del proceso de actualización de la cámara.

_cat Llame a los métodos y _dog Update para moverse y chillar, respectivamente.

Método de dibujo

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

Genera transformaciones de vista y proyección a partir de la información de la cámara.

Para el suelo, el rectángulo dibujado en QuadDrawer se muestra verticalmente, por lo que se gira para que sea horizontal y se amplía moderadamente. _quadDrawer.DrawQuad El segundo argumento del método especifica el número de repeticiones de la textura, que especifica que las hojas de 32x32 aparecen una al lado de la otra.

_cat y _dog se colocan en cartelera internamente, por lo que la información de ubicación de la cámara se pasa y se dibuja.

Método HandleInput

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

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

Se adquiere información sobre el teclado y el gamepad, y se determina el final del juego.

Método 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;
}

La cámara está controlada para moverse.

También incluye cálculos como la aceleración y la fricción, pero creo que probablemente esté teniendo en cuenta el efecto Doppler en el sonido 3D. Como no hago nada especial sobre el cálculo en sí, no lo discutiré.

Resumen

Lo he cubierto extensamente, pero generalmente es suficiente para referirse a la clase sobre AudioManager cómo reproducir sonido 3D. De hecho, la mayoría de las dificultades son hechas por el marco, porque lo que SoundEffectInstance estamos haciendo es establecer información 3D en . Si has muestreado solo las partes del sonido 3D, terminarás escribiendo un poco de trabajo en la clase Juego. Sin embargo, estoy escribiendo Consejos basados en la historia original, por lo que ha pasado mucho más tiempo.