netlib.narod.ru< Назад | Оглавление | Далее >

Класс Sound

Создать звуковой класс действительно просто. Вы уже видели несколько звуковых классов в первых главах, и воспроизводить звуковые реплики легко. Чтобы сделать жизнь еще проще, вы можете определить перечисление с именами звуковых реплик в нем. Таким образом вы убедитесь, что каждая звуковая реплика реально существует и вы не допустили опечатку в каком-либо звуке. Другое замечательное преимущество такого подхода — IntelliSense, показывающая вам доступные звуковые реплики, которые, если бы у вас не было такого перечисления, оставались скрытыми в проекте XACT. Потратить пару минут на написание перечисления — это самая ценная вещь, которую вы можете сделать для воспроизведения звука в XNA. Теперь воспроизводить звуковые реплики очень просто с помощью метода Play класса Sound.

/// <summary>
/// Play
/// </summary>
/// <param name="soundName">Имя звука</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">Звук</param>
public static void Play(Sounds sound)
{
  Play(sound.ToString());
} // Play(sound)

Вы можете сделать версию со строковым параметром закрытой и разрешить использовать только версию, получающую член перечисления Sounds. В случае, если звуковой банк не был инициализирован в конструкторе (например, если отсутствует файл), этот метод немедленно возвратит управление и вы не сможете воспроизводить никакие звуки. Если это произошло, конструктор уже записал сообщение об ошибке в файл журнала. Затем вы просто вызываете PlayCue для воспроизведения и забываете о звуковой реплике. В случае сбоя вы регистрируете сообщение об ошибке в журнале, но не передаете исключение далее в вызывающую функцию, поскольку хотите иметь воспроизводимый звук, а не прерывать вашу программную логику только потому что какой-то звуковой файл отсутствует или какой-то эффект не работает.

Как говорилось раньше, вы можете также использовать метод GetCue, чтобы запомнить звуковую реплику и затем делать с ней различные вещи. Это также полезно, если вы хотите останавливать реплику самостоятельно, вместо того, чтобы ждать, пока воспроизведение закончится. Вот пример, как можно останавливать воспроизведение музыки:

someSoundCue = soundBank.GetCue("SomeSound");
someSoundCue.Play();

...

someSoundCue.Stop(AudioStopOptions.Immediate);

Хотя основная часть класса Sound одинакова для большинства проектов этой книги, взгляните на различия и специальную функциональность, поскольку базовый код воспроизведения мы уже обсудили (рис. 9.14).


Рис. 9.14

Рис. 9.14


Первая вещь, которую вы отметите, — различные имена звуковых реплик в перечислении Sounds. И Rocket Commander XNA и Racing Game используют собственную переменную высоты тона реплики, которую мы обсудим через минуту. Игра XNA Shooter не использует ничего специального; вы просто запускаете музыку в начале игры, а затем воспроизводите все звуковые эффекты, когда нуждаетесь в них, и все.

Чтобы сделать печатание кода воспроизведения звука более комфортабельным, были созданы несколько вспомогательных методов. Например, PlayExplosionSound просто заменяет показанный ниже код, делая проще и быстрее написание кода, необходимого для воспроизведения этого звукового эффекта:

Sound.Play(Sound.Sounds.Explosion);

Для воспроизведения музыки добавлены два дополнительных метода, которые управляют музыкальной репликой в случае, если вы хотите остановить или перезапустить музыку: StartMusic и StopMusic.

Также в каждом звуковом классе есть тестовый модуль для проверки того, что воспроизведение звука работает так, как предполагалось, который используется еще и для того, чтобы проверить, у всех ли звуков правильно заданы параметры громкости. Вот тестовый модуль из класса Sound игры Rocket Commander XNA:

/// <summary>
/// Проверка воспроизведения звуков
/// </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 вызывается автоматически методом Update вашего класса BaseGame внутри графического движка. Метод Update просто гарантирует, что все параметры, зацикливания и временные значения будут обновлены для вас внутри XACT.

Звук двигателя ракеты

Давайте быстро взглянем на звук двигателя ракеты из игры Rocket Commander XNA. Вы уже видели весь код, необходимый для этой работы, но, возможно, будет хорошо посмотреть, как все объединяется вместе и совмещается с движком Rocket Commander, который изначально был написан для DirectSound, но теперь замечательно работает и с XACT.

/// <summary>
/// Воспроизведение звука двигателя ракеты
/// </summary>
public static void PlayRocketMotorSound()
{
  // Получаем новую реплику при каждом вызове,
  // иначе получим от XACT сообщение: The method or function
  // called cannot be used in the manner requested.
  rocketMotorSound = soundBank.GetCue(Sounds.RocketMotor.ToString());

  // Воспроизводим зацикленный звук, параметры из XACT
  rocketMotorSound.Play();

  // Делаем категорию двигателя немного тише
  motorCategory.SetVolume(0.86f);
} // PlayRocketMotorSound(volume)

/// <summary>
/// Меняем высоту тона двигателя ракеты
/// </summary>
/// <param name="pitchFactor">Коэффициент высоты тона</param>
public static void ChangeRocketMotorPitchEffect(float pitchFactor)
{
  rocketMotorSound.SetVariable("Pitch",
    55 * MathHelper.Clamp(pitchFactor - 1, -1, 1));
} // ChangeRocketMotorPitchEffect(pitchFactor)

/// <summary>
/// Остановка звука двигателя ракеты
/// </summary>
public static void StopRocketMotorSound()
{
  rocketMotorSound.Stop(AudioStopOptions.Immediate);
} // StopRocketMotorSound()

Чтобы запустить звук ракеты вы просто после начала миссии вызываете метод PlayRocketMotorSound, а затем модифицируете его во время полета с помощью метода ChangeRocketMotorPitchEffect:

// Подстраиваем частоту воспроизведения звука ракеты
// в соответствии со скоростью полета
Sound.ChangeRocketMotorPitchEffect(0.66f + speed * 0.9f);

И, наконец, StopRocketMotorSound вызывается для остановки звука ракеты, когда вы погибаете или миссия завершена.

Логика звука двигателя в гоночной игре работает аналогичным образом, но она несколько сложнее, поскольку у вас есть 13 различных звуков двигателя, вместо единственного звука ракеты в Rocket Commander XNA. За дополнительной информацией обращайтесь к коду класса Sound гоночной игры.

Фьють, что это было?

Оригинальная игра Rocket Commander использует свои собственные формулы вычисления трехмерного звука и применяет свойства громкости и панорамирования образца DirectSound, чтобы достичь правильного эффекта для игрока. В XNA, к сожалению, панорамирование менять нельзя. Все звуки воспроизводятся так, как они создавались и было задано в XACT. Для трехмерного звукового сопровождения вы в любом случае должны использовать настоящий код трехмерного звука и в первой бета-версии XNA я написал некоторый код для воспроизведения трехмерных звуков и там был объект трехмерного слушателя, перемещающийся по трехмерному миру.

Сейчас этот объект трехмерного слушателя пропал из XNA; в данный момент вы не можете использовать трехмерные звуковые эффекты. Надеюсь, в будущем это изменится, и я конечно обновлю коды игр из этой книги, когда трехмерное звуковое сопровождение снова станет возможным, но сейчас вы можете воспроизводить звуки только в монофоническом режиме; нет поддержки ни стереофонии, ни окружающего звука.

В случае если вы используете X3DAudio и X3DAudioListener (классы могут иметь другие имена; важно только, что вы их сможете как-нибудь установить и воспроизводить трехмерный звук, и что вы можете позиционировать себя с помощью класса трехмерного слушателя), следующий код может быть использован для воспроизведения трехмерного звука, после того, как вы установили все важные переменные реплики:

// Установка 3D слушателя для 3D звука
Sound.Listener = new X3DAudioListener(
  zAxis, yAxis, cameraPosition, movementVector);

Теперь установите источник для каждого звука, который вы хотите воспроизвести в вашем трехмерном мире и воспроизводите экземпляры трехмерных звуков. В настоящее время делающий это код на C# недоступен, и если вы все еще будете оставаться в недоумении, когда XNA через какое-то время в будущем обретет поддержку таких возможностей, обратитесь к приведенной ниже ссылке, чтобы увидеть как классы X3DAudio применяются в C++. Идея останется той же и в C#, но, надеюсь, будет гораздо более простой для написания.


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

Звуки в меню

В завершение этой главы вот несколько коротких советов, относящихся к звукам в меню:


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz