Хороший способ воспроизвести звук, когда что-то происходит? Как это звучит?

10

Так что я думал о том, как монолитно мои занятия занимают много времени. Например, в методе Characterкласса Jumpможно иметь ссылку на объект звукового эффекта и воспроизводить его. Само по себе это хорошо, но если принять во внимание физику, анимацию, столкновения и т. Д., Метод Jump становится огромным, и у Characterкласса много зависимостей от множества разных вещей. Тем не менее, это может быть хорошо. Однако что, если мы больше не хотим, чтобы звук воспроизводился, когда персонаж прыгает? Теперь мы должны найти эту конкретную строку кода в путанице Jumpкода и закомментировать ее или что-то еще.

Итак .. я думал ..

Что, если вместо этого был какой-то AudioSystemкласс, и все, что он делал, это подписывался на случайные события, которые его интересуют в других классах. Например, у Characterкласса может быть Jumpedсобытие (я полагаю, тоже статическое), которое вызывается внутри Characterкласса в методе. Тогда Characterкласс ничего не узнает о небольшом звуковом эффекте, который воспроизводится, когда персонаж прыгает. Это AudioSystemбыл бы огромный класс, к которому программист мог бы вернуться, чтобы связать звуковые эффекты с определенными событиями, происходящими в игре, с использованием статических событий. Тогда, если он получил слишком большой , он может быть отделен в подклассы , как EffectsAudioSystem, BackgroundAudioSystem, AmbientAudioSystemи так далее.

Затем в опциях игры можно установить флажок, чтобы включить или отключить эти виды звуков, и все, что нужно сделать, это просто отключить эту единственную систему с простым и единственным логическим флагом. Эта идея систем также может быть распространена на такие вещи, как физика, анимация и т. Д. До такой степени, что большинство игровых ответов, возникающих в результате действий игрока, подключаются через эти сложные и не связанные между собой системы.

Итак, мой вопрос может быть немного расплывчатым, но как это звучит? Я никогда не слышал много разговоров об этой системе. Это все в моей голове прямо сейчас без какого-либо кодирования, сделанного до сих пор, так что, возможно, это одна из тех сделок, «хороших в теории, но не на практике». Будет ли система такого типа работать с более крупной игрой или она в конечном итоге сломается и станет еще большим беспорядком спагетти, чем оригинальная система?

Ричард Уильямс
источник
5
Звучит как здравая идея :) (На более серьезном замечании: использование сообщений для связи между слабо связанными подсистемами / классами, как правило, хорошая идея для разработки)
bummzack
1
вот как это делается, вы должны поместить свой рендеринг в отдельный класс, а также, если у вас его еще нет (например, у вас не должно быть функции draw () в классе Character).
Дрета

Ответы:

2

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

Таким образом, либо вам нужно будет собрать эти данные и отправить их в AudioManager через очень специфическое событие / сообщение с скопированными в них данными, либо вы отправите ссылку на символ в сообщении, чтобы AudioManager мог получить доступ к данным, как пути заканчиваются грязно, и теперь аудио-менеджер должен выбрать звук для материала андеграунда и т. д.

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

Таким образом, будет огромный список ненужных классов для обслуживания, которые вводят глубокую связь между персонажем и AudioManager, за исключением того, что теперь он разбросан по всему исходному коду. Не только в Character- и AudioManager-классах.

Тем не менее, хорошая идея отделить ваш код, но сообщения - это просто еще один способ глубоких связей. Некоторый код просто должен быть связан, используйте самый прямой способ связать их, не перегружайте.

Майк Земдер
источник
1
Как хорошо продуманная система обмена сообщениями "просто еще один способ глубоких связей"? Отправка сообщений - это абсолютный минимум связи, при котором объекты никогда не общаются. То, как вы его разработали, может вызвать проблемы, но если система воспринимает только звук, местоположение и тип, она решает все его проблемы и не вводит ни одной из тех, которые, по вашему мнению, могут возникнуть. Аудиосистема не должна рассчитывать, какой звук необходим, она должна абстрагироваться от всех настроек и, предпочтительно, от проблем с распространением. ru.wikipedia.org/wiki/Coupling_(computer_programming)
ClassicThunder
1
@ClassicThunder заключается в том, что на практике этот подход не очень хорошо масштабируется. Он хорошо работает для простых приложений и пока все, что вам нужно, это обычный PlaySoundEvent. Но вопрос в том, что AudioManager прослушивает специализированное событие OnJump (), чтобы персонаж мог избавиться от аудио-работы. Это, однако, не будет иметь место с простым PlaySoundEvent, так как персонаж должен выбрать звук и отправить его в AudioManager, который лишает законной силы вводить OnJumpEvent, чтобы избавиться от работы со звуком.
Майк Земдер
1
Однако при использовании OnJumpEvent вы можете либо добавить ссылку на символ в событие, либо скопировать все важные данные из символа в событие. Конечно, вы правы, последний не будет вводить глубокую связь, но будет страдать от проблем с дублированием данных и новым объектом передачи данных, который необходимо поддерживать, как и для всех других новых событий.
Майк Земдер
1
-1 потому что, хотя я согласен с тем, что такие специализированные сообщения (OnJump), скорее всего, плохая идея, это просто длинная фраза «Нет, это плохая идея» вместо полезной информации, чтобы заставить человека сделать событие PlaySound, которое принимает имя звукового эффекта и трехмерной позиции и / или громкости, в которой это произошло.
Джеймс
@ Джеймс, спасибо за вклад, я не хотел сказать, использовать событие PlaySound, я хотел сказать, что события - хорошая абстракция для приложения с GUI-базой данных, но непрактичная для сложной игры.
Майк Земдер
2

Я не думаю, что система передачи сообщений закончена над разработкой вообще. Фактически, это может значительно облегчить выполнение задач в фазе полировки. Ты делаешь это правильно!

То, что вы описали, было именно тем, что я собрал для нашей игры Global Game Jam в прошлом году. Я отвечал за создание и редактирование SFX, а также за интеграцию музыки, написанной мной и другим композитором, в игру так, чтобы это не отстой.

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

пример

В нашей игре вы были динозавром, летающим на космическом корабле, натыкающемся на планеты, чтобы набрать очки. Мы работали во Flash, поэтому инфраструктура, управляемая данными, не требовалась. AudioManager был классом, состоящим из нескольких статических методов, единственной целью которых было контролировать звуки, происходящие в ответ на игровое событие.

Если бы я написал его на C ++, то потребовалось бы немного больше времени, чтобы абстрагировать все возможные варианты поведения звуков. Требования к сообщению, уведомляющему систему о совершенном действии, не будут слишком сложными. Для этого просто понадобится тип сообщения, объект происхождения или объект, на который влияют, доступ к некоторому виду контекста игрового состояния и больше ничего. Протокол может расти по мере роста потребностей игры. Естественно, если вы делаете все это в реализации в коде (например, в нашем неаккуратном коде GGJ), у вас проблема с монолитным классом хуже. Но это легко смягчить, создав систему, управляемую данными.

В любом случае, вот как наша игровая аудиосистема реагировала на различные сообщения:

  • Игрок сталкивается с планетой: это вызовет звук взрыва планеты, достаточно простой. затем сразу же после этого запросил бы работающий комбинированный счетчик. Если бы он был достаточно высоким, он запланировал бы звуковой эффект, который должен был быть воспроизведен спустя полсекунды или около того, когда динозавр сделал рев победы. Также на заднем плане была вычислена случайная численность населения планеты (что-то вроде 600-3000 - я понятия не имею, почему был выбран этот диапазон, это была какая-то заброшенная механика игрового процесса, и я до сих пор лежу, чтобы сделать звук интересным), и поэтому я использовал это, чтобы измерить громкость далеких звуков криков (планетные граждане встречаются с безвременной судьбой).

  • Игрок удерживает пробел для ускорения: при получении этого звучал небольшой «свистящий» звук движителя, но одновременно с этим за 1,5 секунды усилился рев двигателя с низкой петлей. Система частиц также использовала это, чтобы запустить эмиттер IIRC

  • Плеер отпускает пробел для замедления: теперь, когда игрок отпустил пробел, аудиосистема знала, что она должна уменьшить цикл двигателя вниз. Если бы у меня было больше времени, я бы предпочел наложить на него еще один звук, который был своего рода скулящим звуком.

  • Игрок сталкивается со злой космической шахтой: космические мины плохие, поэтому не только присутствует металлический ударный звук в сочетании со взрывом (который просто превращается в один звук), но также есть случайно выбранный звук ужаса динозавра, который играет. Более вероятно, что вы выберете больше «плачущих» звуков, так как здоровье игрока становится ниже.

Уже забавная игра становится приятной игрой, когда ее саундтрек активен и динамичен, даже с небольшим простым поведением, как я описал выше. Да, есть некоторая логистика, чтобы убедиться, что переданы правильные данные. Но эй, BFD. Это будет далеко не самая сложная вещь, которую вам придется написать в большем объеме кода игры.

На самом деле, FMOD и Wwise работают так. У них нет центрального диспетчера сообщений, но вы эффективно публикуете события в их центральных системах, и они реагируют, воспроизводя звуковой эффект, который был предварительно разработан аудио-разработчиком в инструменте разработки. Думайте об этом как о предоставлении своей игре живого диджея. Он сидит и наблюдает за тем, что происходит, и запускает аудиоклипы в нужное время, чтобы держать вещи интересными, смешивая их, чтобы они хорошо вписывались в существующую аудиосистему.

[EDIT] Кроме того, я вижу, что вы пометили этот C #. Это XNA, и если да, то используете ли вы XACT? Если вы используете XNA, вы должны использовать XACT.

michael.bartnett
источник
1
Это может работать для небольшого проекта, это может быть даже весело. Однако в большом вы получаете огромное количество классов сообщений, которые необходимо поддерживать, тогда как простой вызов функции имел бы такой же эффект. Вот почему система событий плохо масштабируется, становится сложнее управлять тем, что больше получает проект.
Майк Земдер
1
Кстати, мы работаем с FMOD в моей студии, нет системы сообщений / событий, вы не отправляете события в FMOD, вы просто вызываете метод c-function или c ++ для воспроизведения чего-либо. Они просто называют свои звуки «событиями», что не делает их системой событий, это просто термин, который они используют вместо звука.
Майк Земдер
Нет почему? Вы просто вызываете функцию напрямую, а не используете событие для передачи параметров. Событие в конце концов является ничем иным, как вызовом функции, просто передачей параметров в объекте события, а не передачей их напрямую. Единственное отличие - это новая косвенность, введенная системой событий, но в конце ее простой вызов функции, только излишне усложненный.
Майк Земдер
@MaikSemder Как вызовы методов не оказываются в их собственной запутанной паутине гадости? Также я попытался отметить это различие между системой событий и «событиями», используемыми Wwise и FMOD. Идея, к которой я стремлюсь, заключается в том, что сложная звуковая логика не относится к классам игровых объектов, а абстрагирование звуковой логики так, что интерфейс похож на диспетчеризацию события, облегчает получение богатой звуковой логики. Я действительно вижу небольшую функциональную разницу между EventManager->dispatch("Sound:PlayerJump")и soundSystem->playFMODEvent("/MyGame/Player/Jump").
Майкл Бартнетт
2
Может быть преимущество более простого кодирования, но оно не бесплатное, оно связано с затратами на производительность, обслуживание и более сложную отладку. Я хочу сказать, что для больших проектов выгода не стоит. Вы имеете дело с большим количеством объектов, чем без событий, и вам приходится платить за это. Единственное место, где я хотел бы рассмотреть использование системы сообщений, - это межпотоковая связь для предотвращения блокировки между потоками.
Майк Земдер
0

Я согласен с Майком Семдером в том, что система передачи сообщений может быть чрезмерно сложной (пока что в любом случае).

Насколько я понимаю, ваш класс в настоящее время выглядит как «монолитный класс» Bjorn , как можно видеть в «монолитном классе» здесь .

Я предлагаю вам прочитать эту статью, и, хотя полная система компонентов пока будет излишней, если вы прочитаете «Разделение остальных», это должно дать вам хороший способ абстрагировать ваше поведение и в конечном итоге, возможно, перейти к более сложному решение. Это даст вам хорошую базу для начала в любом случае.

deceleratedcaviar
источник