Обработка событий в разработке игрового движка на основе компонентов
Я предполагаю, что этот вопрос или вариации его передаются много, поэтому, если я говорю, это дубликат, и ответы лежат в другом месте, пожалуйста, сообщите мне.
Я изучал дизайн игрового движка и столкнулся с моделью на основе компонентов. Это звучит многообещающе, но я все еще разрабатываю его реализацию.
Я рассматриваю систему, в которой движок устроен из нескольких "подсистем", которые управляют некоторыми аспектами, такими как рендеринг, звук, здоровье, AI и т.д. Каждая подсистема имеет связанный с ней тип компонента, например компонент здоровья для подсистемы здравоохранения. "Сущность", например, NPC, дверь, какой-то визуальный эффект или игрок, просто состоит из одного или нескольких компонентов, которые вместе дают сущности свою функциональность.
Я идентифицировал четыре основных канала передачи информации: компонент может транслироваться для всех компонентов в его текущем объекте, компонент может транслировать его подсистему, подсистема может транслировать ее компоненты, а подсистема может транслироваться в другие подсистемы.
Например, если пользователь хотел переместить свои символы, они нажмут клавишу. Это нажатие клавиши будет подхвачено входной подсистемой, которая затем транслирует событие и будет подхвачена подсистемой проигрывателя. Подсистема плеера затем отправляет это событие всем компонентам проигрывателя (и, следовательно, составляющим эти компоненты), и эти компоненты проигрывателя будут сообщать своему компоненту позиции сущности, чтобы двигаться вперед и двигаться.
Все это для нажатия клавиши кажется немного закрученным, и я, безусловно, открыт для улучшения этой архитектуры. Но в любом случае мой основной вопрос все еще следует.
Что касается самих событий, я рассмотрел, где происходит событие, как в шаблоне посетителя. Важность того, что я хочу, состоит в том, что если событие встречается с компонентом, который он не поддерживает (поскольку в событии перемещения нет ничего непосредственного отношения к ИИ или здоровью), он игнорирует компонент. Если событие не находит компонент, который будет после него, это не имеет значения.
Шаблон посетителя почти работает. Однако для этого требуется, чтобы у меня были виртуальные функции для каждого типа компонентов (например, visitHealthComponent, visitPositionComponent и т.д.), Даже если это не имеет к ним никакого отношения. Я мог бы оставить эти функции пустыми (так что, если бы они попадались на эти компоненты, это было бы проигнорировано), но я должен был бы добавить другую функцию каждый раз, когда добавляю компонент.
Мои надежды состояли в том, что я мог бы добавить компонент, не добавляя лишние вещи в другие места, и добавлять событие, не вмешиваясь в другие вещи.
Итак, мои два вопроса:
- Есть ли какие-либо улучшения, которые мой дизайн может позволить с точки зрения эффективности, гибкости и т.д.?
- Каким будет оптимальный способ обработки событий?
Ответы
Ответ 1
Я думал об использовании сущностных систем для одного из моих собственных проектов и прошел аналогичный процесс мышления. Моя первоначальная мысль заключалась в том, чтобы использовать шаблон Observer для работы с событиями - я тоже изначально рассматривал какую-то модель посетителя, но решил против нее по тем причинам, которые вы приносите.
Мои мысли в том, что подсистемы будут предоставлять интерфейс для публикации/подписки подсистемы, и, таким образом, подсистемные зависимости будут разрешаться "полу-слабо" в сочетании. Любая подсистема, которая зависит от событий от другой подсистемы, будет знать интерфейс абонента к этой подсистеме и, следовательно, может эффективно ее использовать.
К сожалению, как эти подписчики получают обращения к своим издателям, все еще остается проблемой. На данный момент я предпочитаю какое-то динамическое создание, где создается каждая подсистема, а затем вторая фаза используется для разрешения зависимостей и помещает все подсистемы в "состояние готовности".
В любом случае, меня очень интересует, что сработало для вас и какие-либо проблемы, с которыми вы столкнулись в своем проекте:)
Ответ 2
Используйте шину событий, например агрегатор событий. То, что вы хотите, это механизм событий, который не требует связи между подсистемами, и шина событий будет делать именно это.
http://martinfowler.com/eaaDev/EventAggregator.html
http://stackoverflow.com/questions/2343980/event-aggregator-implementation-sample-best-practices
и т.д.
Ответ 3
описанная здесь архитектура http://members.cox.net/jplummer/Writings/Thesis_with_Appendix.pdf
Есть как минимум три проблемы, с которыми я столкнулся, реализуя это в реальном проекте:
-
Системы
- не сообщаются, когда что-то случается - единственный способ спросить об этом - игрок мертв? стена не видна? и т.д. - чтобы избежать этого, вы можете использовать простой MVC вместо шаблона наблюдателя.
- что, если ваш объект является композитом (т.е. состоит из объектов)? система будет проходить через всю иерархию и спрашивать о состоянии компонента.
- И главным недостатком является то, что эта архитектура объединяет все вместе - например, почему игроку нужно знать, что вы нажали клавишу?
Я считаю, что ответ - это слоистая архитектура с абстрактным представлением...
Ответ 4
Извините мой плохой английский.
Я пишу гибкий и масштабируемый java 3d Game Engine, основанный на Entity-Component System. Я закончил некоторые основные части.
Сначала я хочу сказать что-то о архитектуре ECS, я не согласен с тем, что компонент может связываться с другими компонентами в одном и том же объекте. Компоненты должны хранить только данные и системы.
В части обработки событий, я думаю, что основная обработка ввода не должна включаться в ECS. Вместо этого у меня есть система под названием Intent System и компонент, называемый Intent Component, который содержит много намерений. Цель состоит в том, что объект хочет сделать что-то в отношении объекта.
система Intent обрабатывает все намерения. Когда она обрабатывает намерение, она передает соответствующую информацию другим системам или добавляет другие объекты в объект.
Я также пишу интерфейс под названием Intent Generator. В локальной игре вы можете реализовать Keyboard Input или Mouse Input Generator, а в игре с несколькими игроками вы можете реализовать сетевой генератор намерений. В системе AI вы также можете генерировать намерения.
Вы можете думать, что система Intent обрабатывает слишком много вещей в игре. Но на самом деле, он разделяет много обработки на другие системы. И я также пишу систему Script. Для конкретного специального объекта он имеет компонент Script, который выполняет специальные функции.
Первоначально, когда я что-то развиваю, я всегда хочу создать замечательную архитектуру, которая включает в себя все. Но для разработки игр иногда это очень неэффективно. У другого игрового объекта могут быть совершенно разные функции. ECS отлично подходит как система, ориентированная на данные. но мы не можем включать в нее все для полноценной игры.
Кстати, наш игровой движок на базе ECS будет открытым исходным кодом в ближайшем будущем, тогда вы сможете его прочитать. Если вы заинтересованы в этом, я также приглашаю вас присоединиться к нам.