netlib.narod.ru | < Назад | Оглавление | Далее > |
Создать звуковой класс действительно просто. Вы уже видели несколько звуковых классов в первых главах, и воспроизводить звуковые реплики легко. Чтобы сделать жизнь еще проще, вы можете определить перечисление с именами звуковых реплик в нем. Таким образом вы убедитесь, что каждая звуковая реплика реально существует и вы не допустили опечатку в каком-либо звуке. Другое замечательное преимущество такого подхода — 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 |
Первая вещь, которую вы отметите, — различные имена звуковых реплик в перечислении 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#, но, надеюсь, будет гораздо более простой для написания.
В завершение этой главы вот несколько коротких советов, относящихся к звукам в меню:
Используйте для воспроизведения звуковых эффектов меню вспомогательные методы, такие как PlayMenuHighlight или PlayMenuClick вместо применения перечисления Sounds.
Если вы хотите воспроизводить конкретный звук меню с различной громкостью, например, громкий звук подсветки для главных кнопок и более тихий звук подсветки для менее значимых элементов управления, создайте две звуковые реплики в XACT вместо того, чтобы писать собственный код управления громкостью, что потребует много абсолютно не нужной работы.
Попробуйте написать вспомогательный метод определяющий, был ли указатель мыши проведен над элементом управления в этом кадре, и повторно используйте этот код или метод для всех элементов управления, чтобы унифицировать подсветку или код щелчка мыши. Этот способ позволит вам не воспроизводить звук щелчка или подсветки самостоятельно в каждом отдельном методе обработки кнопок, используемых в вашей игре.
Убедитесь, что вы поддерживаете пульт Xbox 360 и клавиатуру. Написание игр только для мыши не имеет смысла для Xbox 360, поскольку у вас нет абсолютно никакой поддержки мыши в XNA для вашей Xbox 360.
Воспроизводите звук подсветки, когда выполняется навигация по элементам меню, и воспроизводите звук щелчка, когда пользователь нажимает кнопку игрового пульта или клавишу клавиатуры, чтобы перейти к выбранному пункту меню.
netlib.narod.ru | < Назад | Оглавление | Далее > |