Покадровые вызовы функций и обмен сообщениями на основе событий в игровом дизайне


11

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

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

Игровая архитектура, управляемая событиями, подробно описана в статье : « Кодирование игр завершено Майком МакШаффри» .

Могу ли я попросить помощи по следующим вопросам:

  • Каковы преимущества и недостатки обоих подходов?
  • Где одно лучше другого?
  • Является ли управляемый событиями игровой дизайн универсальным и лучшим во всех областях? Поэтому рекомендуется для использования даже на мобильных платформах?
  • Какой из них более эффективен, а какой сложнее развивать?

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


Пример: этот вопрос вызвал здесь некоторые противоречия, поэтому позвольте мне привести вам пример: согласно MVC, движок игры разделен на три основные части:

  1. Уровень приложений (аппаратное обеспечение и связь с ОС)
  2. Игровая логика
  3. Просмотр игры

В гоночной игре Game View отвечает за максимально быстрое отображение экрана, по крайней мере, 30 кадров в секунду. Game View также прослушивает вход игрока. Теперь это происходит:

  • Игрок нажимает педаль топлива до 80%
  • GameView создает сообщение «Педаль топлива 2 нажата до 80%» и отправляет его в Game Logic.
  • Game Logic получает сообщение, оценивает, рассчитывает положение и поведение нового автомобиля и создает для GameView следующие сообщения: «Нажата педаль топлива Draw 2, нажато на 80%», «Ускорение звука автомобиля 2», «Координаты автомобиля 2 X, Y» .. ,
  • GameView получает сообщения и обрабатывает их соответственно

где вы нашли? некоторые ссылки или ссылки? я не знаю этот подход (но я знаю достаточно общую модель проектирования в целом, и я рекомендую хорошее использование принципов объектных ориентаций в целом), но я думаю, что лучше использовать основанный на событиях подход. подумать об эволюции в сетевых системах: от опрос асинхронных вызовов .. он оптимизирован в вычислениях и на уровне абстракции
nkint

Привет Нкинт, спасибо за ваш комментарий. Я в основном хотел сравнить управляемую событиями коммуникацию против вызовов с виртуальными функциями. Я немного изменю свой вопрос. Кстати, посмотрите на эту ссылку, содержащую игровые шаблоны: gameprogrammingpatterns.com .
Bunkai.Satori

5
Может быть, я тупой, но как ты собираешься заставить систему обмена сообщениями работать без полиморфизма? Разве вам не нужен какой-то базовый класс (абстрактный или другой) для определения интерфейса получателя событий? (Изменить: при условии, что вы не работаете на языке с надлежащим отражением.)
Тетрад

2
Кроме того, эффективность будет сильно зависеть от деталей реализации. Я не думаю, что «какой из них более эффективен» - это вопрос, на который можно ответить в его нынешнем виде.
Тетрад

1
Игровые объекты нужно поставить галочку. Игровые объекты должны общаться друг с другом. Эти две вещи должны произойти. Первое, что вы не делаете с сообщениями, потому что это избыточно (у вас, вероятно, есть список всех объектов где-то, просто вызовите updateих). Второе вы можете сделать с сообщениями по разным причинам.
Тетрад

Ответы:


8

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

Каковы преимущества и недостатки обоих подходов?

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

Где одно лучше другого?

Мы могли бы поговорить о памяти и ресурсах здесь. Если вы разрабатываете для какого-либо оборудования с ограниченными ресурсами, это, безусловно, проблема в использовании системы событий, которая значительно снизит это. Правда, я думаю, что проблема сводится к тому, что вам нужно, что, как я уже говорил, вы не знаете, пока не увидите, как выглядят все части. Если у вас достаточно опыта по созданию этих систем, и вы заранее точно знаете, как будут выглядеть все компоненты, вы также можете заранее ответить на этот вопрос. Я предполагаю, что у вас нет этого опыта, так как вы бы не задавали этот вопрос, если бы у вас был.

Является ли управляемый событиями игровой дизайн универсальным и лучшим во всех областях? Поэтому рекомендуется для использования даже на мобильных платформах?

Универсальный и лучший во всех областях? Такое довольно общее утверждение легко отвергается. Все, что добавляет накладные расходы, должно нести свою долю рабочей нагрузки. Если вы не используете события в достаточной мере, чтобы оправдать накладные расходы на дизайн, значит, это неправильный дизайн.

Какой из них более эффективен, а какой сложнее развивать?

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


Привет Эрик, спасибо за ваше подробное мнение по моему вопросу. Пока я читаю ваши и чужие ответы, реализация сообщений о событиях, вероятно, не приведет к чуду в общем увеличении производительности игры. Вместо этого это сильно усложнит ситуацию. Я хотел бы увидеть еще несколько ответов, прежде чем закрыть этот вопрос. Поскольку вся книга освещала эту тему, это было хорошей идеей для рассмотрения. Я не очень уверен, может ли решение использовать или не использовать сообщения может быть принято в середине проекта. Если используются сообщения о событиях, я бы сказал, общий дизайн объекта тоже должен быть скорректирован.
Bunkai.Satori

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

7

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

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

Если у вас есть какая-то структура, в которой вы добавляете / удаляете игровые сущности, вы также можете включить их в свой цикл обновления вместо того, чтобы отправлять им сообщение об обновлении каждый кадр. Так почему бы не вызвать обновление ваших игровых сущностей напрямую, когда вы используете обмен сообщениями для подключения различных подсистем вашей игры? Мне также нравится концепция Signal / Slot ( см. Пример qt ) для систем, подобных событиям.

Итог: нет лучшего подхода, и при этом они не исключительны.


Привет, Буммзак. Наконец, первый ответ пришел. Спасибо вам за это :-) Когда я упоминал Event Driven Architecture, я имел в виду систему MVC с тремя ключевыми слоями: Appliaction, GameView, GameLogic. Все общение между этими тремя будет осуществляться через обмен сообщениями. Это существенно отличается от традиционной системы с циклом обновления. Каждая система имеет различную архитектуру, некоторые преимущества и недостатки, и они имеют разную стоимость производительности. Поэтому я полагаю, что в некоторых областях было бы немного лучше. После хорошего анализа мы должны прийти к выводу, какой из них лучше.
Bunkai.Satori

3
Я не понимаю, почему это отличается? Вам понадобится где-то цикл обновления, и он, вероятно, обновит контроллер, если вы хотите придерживаться MVC. Затем контроллер может сообщать модель и представление ... но поскольку контроллер обычно знает представление и модель, он также может напрямую обновлять их. Но это не заменяет какой-либо полиморфизм. Ваш вопрос и предположения звучат очень теоретически. Может быть, подкрепите их примерами кода или ссылками?
bummzack

Вышеупомянутая книга, Game Coding Complete, рекомендует отправлять сообщения о событиях через прямые вызовы виртуальных методов. Хотя система обмена сообщениями выглядит более сложной, ее преимущество в том, что каждый игровой объект не должен проверять игровой мир. Игровой мир проверяется игровой логикой только один раз, и тогда адресуются только те объекты, которые должны изменить свои состояния. Это одно из отличий и может означать экономию средств. Если вы решите, что ваши игровые объекты будут сообщаться через сообщения, они не будут называться в каждом кадре - поэтому оба подхода являются взаимоисключающими.
Bunkai.Satori

1
Проголосовал за ответ, который отражает комментарии Тетрада ниже исходного вопроса. @ Bunkai.Satori «Мир игры проверяется только один раз» - это цикл обновления, все, что нуждается в обновлении, получает его. Сообщения о событиях предназначены для выполнения редко, но они по-прежнему являются ключевыми в движке (PlayerDied, MonsterDied и т. Д.), Что проверка каждого кадра в цикле Update () будет пустой тратой, но они, скорее всего, будут сгенерированы Сам цикл обновления ().
Джеймс

1
Если у вас есть второе издание, посмотрите главу под названием «Управление главным циклом». Это должно быть названо то же самое в 3-м издании. Это должно действительно ответить на ваш вопрос.
Рэй Дей,

4

Это началось как комментарий к ответу bummzack, но получилось долго.

Если вы на самом деле не сделаете это асинхронным (отправка событий в новом потоке), ваши объекты все равно будут получать памятку синхронно. Предполагая, что ваш диспетчер событий использует базовую хеш-таблицу со связанным списком в ячейке, порядок будет таким, в котором объекты были добавлены в эту ячейку.

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

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

Это отличный инструмент, но, как сказал Буммзак, не думайте, что полиморфизм и события решают одну и ту же проблему.


Привет Bearcdp, спасибо за ваш ответ. Это имеет смысл для меня. В моей голове есть одна вещь, которая голосует за сообщения о событиях: скажем, на сцене 200 человек. Если вы используете вызовы по кадрам для всех объектов, вы должны проверять все 200 объектов на предмет коллизии в каждом кадре (пример; конечно, интервалы вызовов можно управлять.) При обмене сообщениями о событиях игровой мир проверяется только один раз. Если имеется 5 коллизий, только 5 объектов получают уведомление о событии коллизии вместо 200 тестов на обнаружение коллизий с вызовами за кадр. Каково твое мнение?
Bunkai.Satori

2
изучить игровой мир ?? что это обозначает? Это должно означать выполнение тех же 200 проверок, чтобы изолировать 5, о которых нужно отправлять сообщения. С концепцией виртуальной функции игровой мир проверяется только один раз (функция каждого объекта по очереди), а затем перемещается только на те 5, которые нуждаются в изменении состояния ... без издержек системы обмена сообщениями.
Стив Х

1
Послушайте Стива Н, мир не сталкивается сам. Я в основном использую события для событий высокого уровня, таких как PlayerJump, EnemyHit. Для обеспечения эффективности проверки столкновений вам нужно выбрать структуру данных, чтобы организовать физическое расположение объектов в вашей игре, чтобы вы могли определить приоритеты, какие объекты нуждаются и не должны проверяться на предмет столкновения. После того как вы определили все пары объектов, которые столкнулись, вы можете отправить событие с соответствующими данными о столкновениях (два объекта, данные о скорости / положении / нормалях и т. Д.).
michael.bartnett

Привет Стив и Beardcp, спасибо за ваши комментарии. То, что вы написали, имеет смысл. Похоже, что может быть много возможных реализаций системы обмена сообщениями о событиях. Как упоминалось в вышеприведенной книге, может быть полная замена концепции виртуальных функций для каждого кадра. Однако, как вы говорите, система обмена сообщениями может сосуществовать с концепцией виртуальной функции для каждого кадра.
Bunkai.Satori

Почему вы говорите «по какой-то причине» в отношении указателей на функции? Это почти то, как я реализовал систему событий, когда писал ее с нуля (я работаю на языках, которые имеют первоклассные функции, но это та же идея; я передаю функцию объекту-концентратору событий, и этот объект отображает функции слушателя на события), поэтому мне интересно, есть ли недостаток этого подхода.
Джоккинг

2

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

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

Проект, используемый для любого конкретного объекта, должен основываться на потребностях этих объектов, а не на некоторой идеологии для системы в целом.

Отредактировано, чтобы быть более ясным в моем первом предложении.


Привет DeadMG, позвольте мне объяснить: В вышеупомянутом случае дизайн разделен на три основные части: уровень Appliaction (аппаратный доступ), Game Logic, Game View. То, что визуализируется для каждого кадра, - это вид игры. Однако, когда Game View записывает пользовательский ввод (например, педаль тормоза нажата в режиме игры), он отправляет сообщение «Car 2 Brake Pressed» в Game Logic для обработки. Game Logic оценивает это действие, вычисляет поведение автомобиля и отправляет сообщение в игровой вид: «Автомобиль 2 Block Tyres», «Автомобиль 2 Двигайтесь к X, Y». Таким образом, нет необходимости проверять за кадр, был ли тормоз нажат на каждом автомобиле.
Bunkai.Satori

@Bunkai: Итак, у вас есть несколько проектов, которые основаны на событиях, и некоторые проекты, которые называются каждый кадр. Это в значительной степени согласуется с моим ответом.
DeadMG

Я счастлив найти понимание с вами, так как этот вопрос был немного спорным здесь сегодня :-)
Bunkai.Satori
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.