• 通过XACT添加声音——Sound类


    Sound类

    创建Sound类真的很简单。你已经在第一章看到了一些Sound类,sound cue回放非常简单。为了使使用起来更简单,您可以定义一个枚举包含所有的声音cue名称。通过这种方式可以确保每一个sound cue确实存在,而且你不会输错名称。这样做的另一个优点是智能感知,它将会显示隐藏在XACT项目中所有可用的sound cue。花费两分钟时间写这些枚举是值得的。在Sound类中的Play方法帮助下,现在播放sound cue很容易。

    /// <summary>
    /// Play
    /// </summary>
    /// <param name="soundName">Sound name</param>
    public static void Play(string soundName)
    {
      if (soundBank == null)
        return;
    
      try
      {
        soundBank.PlayCue(soundName);
      } // try
      catch (Exception ex)
      {
        Log.Write("Playing sound " + soundName + " failed: " +
          ex.ToString());
      } // catch
    } // Play(soundName)
    
    /// <summary>
    /// Play
    /// </summary>
    /// <param name="sound">Sound</param>
    public static void Play(Sounds sound)
    {
      Play(sound.ToString());
    } // Play(sound)

    您也可以通过让字符串私有使得只允许声音枚举。如果sound bank无法在构造函数中初始化(例如,如果该文件丢失)此方法将立即返回而您无法播放任何声音。错误会被记录到日志文件中。接着你调用PlayCue播放并忘记sound cue。如果失败你只写入日志文件,因为你不想因为某些声音文件的丢失打断正常的程序逻辑。

    正如你之前所见,您也可以使用GetCue方法记住一个sound cue,然后做多个事情。如果您想自己停止cue而不是等待声音放完,这样做是很有用的。作为一个例子,下面的代码用来停止播放音乐:

    someSoundCue = soundBank.GetCue("SomeSound");
    someSoundCue.Play();
    
    ...
    someSoundCue.Stop(AudioStopOptions.Immediate);

    本书中的游戏的Sound类中的大部分代码是相同的,下面看看不同和特殊功能(见图9-14)。

    1
    图 9-14

    首先你会发现在Sound枚举中有不同的sound cue名称。Rocket Commander和赛车游戏使用自定义的picth cue。XNA Shooeter不使用任何特殊设置,你只需在游戏开始时播放音乐,然后播放所有音效。

    为了使输入播放声音的代码更舒适,创建了几个辅助方法。例如,PlayExplosionSound只是取代了下面的代码使其能更快并更容易编写:

    Sound.Play(Sound.Sounds.Explosion);

    对于音乐播放添加了两个额外的方法:StartMusic和StopMusic,它们也保存了music cue的音轨。

    每个sound类中还有一个单元测试用来检查回放声音是否正常,并检查音量是否正确。下面是Rocket Commander声音类中的单元测试:

    /// <summary>
    /// Test play sounds
    /// </summary>
    public static void TestPlaySounds()
    {
      TestGame.Start(
        delegate
        {
          if (Input.MouseLeftButtonJustPressed ||
            Input.GamePadAJustPressed)
            Sound.Play(Sounds.Bomb);
          else if (Input.MouseRightButtonJustPressed ||
            Input.GamePadBJustPressed)
            Sound.Play(Sounds.Click);
          else if (Input.KeyboardKeyJustPressed(Keys.D1))
             Sound.Play(Sounds.GameMusic);
          else if (Input.KeyboardKeyJustPressed(Keys.D2))
             Sound.Play(Sounds.MenuMusic);
          else if (Input.KeyboardKeyJustPressed(Keys.D3))
             Sound.Play(Sounds.Explosion);
          else if (Input.KeyboardKeyJustPressed(Keys.D4))
             Sound.Play(Sounds.Fuel);
          else if (Input.KeyboardKeyJustPressed(Keys.D5))
             Sound.Play(Sounds.Victory);
          else if (Input.KeyboardKeyJustPressed(Keys.D6))
             Sound.Play(Sounds.Defeat);
          else if (Input.KeyboardKeyJustPressed(Keys.D7))
          {
            Sound.PlayRocketMotorSound(0.75f);
            Sound.ChangeRocketMotorPitchEffect(0.5f);
          } // else if
          else if (Input.KeyboardKeyJustPressed(Keys.D8))
            Sound.StopRocketMotorSound();
          TextureFont.WriteText(2, 30,
            "Press 1-8 or A/B or left/right "+
            "mouse buttons to play back sounds!");
      });
    } // TestPlaySounds()

    最后,Update方法被BaseGame类中的Update方法自动调用。Update方法只为您确保在XACT中所有参数,循环,时间值的更新。

    火箭发动机声音

    快速看一下Rocket Commander中的火箭发动机声音。前面你已经看到完成这个工作所需的代码,下面是如何整合在一起并配合Rocket Commander游戏引擎,一开始这是用DirectSound写的,但在XACT中工作得也很好:

    /// <summary>
    /// Play rocket motor sound
    /// </summary>
    public static void PlayRocketMotorSound()
    {
      // Get new cue everytime this is called, else we get Xact throwing
      // this: The method or function called cannot be used in the manner
      // requested.
      rocketMotorSound = soundBank.GetCue(Sounds.RocketMotor.ToString());
      // Plays the sound looped, set in XACT
      rocketMotorSound.Play();
      // Make motor category a little silent
      motorCategory.SetVolume(0.86f);
    } // PlayRocketMotorSound(volume)
    
    /// <summary>
    /// Change rocket motor pitch effect
    /// </summary>
    /// <param name="pitchFactor">Pitch factor</param>
    public static void ChangeRocketMotorPitchEffect(float pitchFactor)
    {
      rocketMotorSound.SetVariable("Pitch",
        55 * MathHelper.Clamp(pitchFactor - 1, -1, 1));
    } // ChangeRocketMotorPitchEffect(pitchFactor)
    
    /// <summary>
    /// Stop rocket motor sound
    /// </summary>
    public static void StopRocketMotorSound()
    {
      rocketMotorSound.Stop(AudioStopOptions.Immediate);
    } // StopRocketMotorSound()

    游戏开始后你只需调用PlayRocketMotorSound方法就能播放火箭的声音,然后通过ChangeRocketMotorPitchEffect方法修改它:

    // Adjust rocket playback frequency to flying speed
    Sound.ChangeRocketMotorPitchEffect(0.66f + speed * 0.9f);

    如果你失败或任务结束,则调用StopRocketMotorSound方法停止播放火箭的声音。

    赛车游戏中的声音逻辑工作方法类似,但更加复杂,因为你有13个不同的发动机声音。看一下赛车游戏的sound类了解更多细节。

    Whoosh,那是什么呀?

    初版本的Rocket Commander使用自己的3D音效计算公式并使用DirectSound的音量和和panning属性。在XNA中不能改变panning。所有声音必须以在XACT中创建和设置的方式播放。对于3D声音,你应该使用真实的3D声音代码,在XNA电测版本中我写了一些播放3D声音的代码,并实现了一个在三维世界中的3D监听对象。

    这个3D监听对象在XNA中被移除,现在您不能使用3D音效。希望将来会做出改变,如果3D可以被实现,我一定会更新这本书中的代码,但现在你只能播放单声道的声音,没有立体声或环绕声。

    如果你可以使用X3DAudio和X3DAudioListener (这些类可能有不同的名称,重要的是您可以设置和播放3D音频效果,并且在3D listener类的帮助下确定玩家的位置),在设置了所有重要的cue后,下面的代码用于播放3D声音:

    // Setup 3D listener for 3D sound
    Sound.Listener = new X3DAudioListener(
      zAxis, yAxis, cameraPosition, movementVector);

    现在,为每个声音设置发射器并播放3D音频实例。目前还没有C#代码可以做到这一点,如果你对此感到困惑,你可以看看下面的链接去了解X3Daudio类是如何使用C++的。在C#中做法类似,但希望能更容易编写。

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/ audio_xact_overview_x3daudio.asp

    菜单声音

    这里有一些关于菜单提示声音的小技巧:

    • 使用如PlayMenuHighlight或PlayMenuClick之类的辅助方法播放声音,而不是使用Sound枚举。
    • 如果你想用不同的音量播放菜单声音,例如主要按钮声音响而小控件声音轻,可以在XACT中建立两个sound cue而不是编写自己的自定义代码,这样做工作量很大而且没有必要。
    • 尝试写辅助方法判断鼠标是否移到了控件上并重用此代码,这样,你就无需每次都自己处理播放点击或高亮的声音。

    • 请确认您还支持Xbox 360控制器和键盘。编写一个只支持鼠标的游戏在Xbox 360毫无意义,因为Xbox 360不支持鼠标。

    • 当移动到菜单项时播放高亮的声音,用户按下手柄键或按下space或Enter键选择菜单时播放点击的声音。

  • 相关阅读:
    JAVA软件工程师应该具备哪些基本素质?
    java编程题(一)
    js继承之Object.create()
    【3D计算机图形学】变换矩阵、欧拉角、四元数
    JS的get和set使用示例
    深入浅析JavaScript中的constructor
    图片预加载之模拟img.load()
    threejs里面的vector3源码解析
    javascript事件轮询
    关于URL编码的一些结论
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120243.html
Copyright © 2020-2023  润新知