Я пытаюсь спроектировать систему сущностей на основе компонентов для целей обучения (а позже и использовать в некоторых играх), и у меня возникают некоторые проблемы с обновлением состояний сущностей.
Я не хочу иметь метод update () внутри компонента, чтобы предотвратить зависимости между компонентами.
В настоящее время я имею в виду, что компоненты содержат данные и компоненты обновления системы.
Итак, если у меня есть простая 2D-игра с некоторыми объектами (например, игрок, враг1, враг2), которые имеют компоненты Transform, Movement, State, Animation и Rendering, я думаю, что я должен иметь:
- MovementSystem, которая перемещает все компоненты Movement и обновляет компоненты State.
- И RenderSystem, которая обновляет компоненты Animation (компонент анимации должен иметь одну анимацию (то есть набор кадров / текстур) для каждого состояния и обновлять ее, означает выбор анимации, соответствующей текущему состоянию (например, jump, moving_left и т. Д.), И обновление индекса кадра). Затем RenderSystem обновляет компоненты Render с помощью текстуры, соответствующей текущему кадру анимации каждого объекта, и отображает все на экране.
Я видел несколько реализаций, таких как Artemis Framework, но я не знаю, как решить эту ситуацию:
Допустим, в моей игре есть следующие сущности. Каждый объект имеет набор состояний и одну анимацию для каждого состояния:
- игрок: «холостой», «moving_right», «прыжки»
- враг1: "перемещение_вверх", "перемещение_для"
- враг 2: "движущийся влево", "движущийся вправо"
Каковы наиболее приемлемые подходы для обновления текущего состояния каждого объекта? Единственное, о чем я могу думать, - это иметь отдельные системы для каждой группы объектов и отдельные компоненты State и Animation, поэтому у меня будут PlayerState, PlayerAnimation, Enemy1State, Enemy1Animation ... PlayerMovementSystem, PlayerRenderingSystem ... но я думаю, что это плохо решение и ломает цель иметь систему на основе компонентов.
Как вы можете видеть, я совершенно заблудился здесь, поэтому я очень признателен за любую помощь.
РЕДАКТИРОВАТЬ: Я думаю, что решение, чтобы сделать эту работу, как я намерен это следующее:
Вы делаете составные компоненты состояния и анимации достаточно общими, чтобы их можно было использовать для всех объектов. Содержащиеся в них данные будут модификатором изменений, например, какие анимации воспроизводятся или какие состояния доступны. - Byte56
Теперь я пытаюсь выяснить, как спроектировать эти два компонента достаточно универсально, чтобы я мог использовать их повторно. Хорошим решением может быть наличие UID для каждого состояния (например, ходьба, бег ...) и сохранение анимации на карте в AnimationComponent, заданном этим идентификатором?
источник
statecomponent
иanimationcomponent
достаточно универсальным, чтобы использоваться для всех сущностей. Содержащиеся в них данные будут модификатором изменений, например, какие анимации воспроизводятся или какие состояния доступны.Ответы:
IMHO,
Movement
компонент должен содержать текущее состояние (Movement.state
), аAnimation
компонент должен наблюдать за изменениямиMovement.state
и обновлять свою текущую анимацию (Animation.animation
) соответственно, используя простой поиск идентификатора состояния для анимации (как это было предложено в конце OP). Очевидно, это средствоAnimation
будет зависеть отMovement
.Альтернативная структура могла бы иметь общий
State
компонент, которыйAnimation
наблюдает иMovement
модифицирует, который в основном представляет собой модель-представление-контроллер (в этом случае состояние-анимация-движение).Другой альтернативой было бы, чтобы объект отправлял событие своим компонентам при изменении его состояния.
Animation
будет слушать это событие и обновлять его анимацию соответственно. Это устраняет зависимость, хотя можно утверждать, что зависимая версия является более прозрачной конструкцией.Удачи.
источник
Movement
будет контролироватьState
(не наблюдать). Последний случай: ДаMovement
,entity.dispatchEvent(...);
или около того, и все другие компоненты, прослушивающие событие такого типа, получат его. Производительность, конечно, хуже чистых вызовов методов, но не намного. Вы можете объединить объекты событий, например. Кстати, вам не нужно использовать сущность в качестве «узла событий», вы также можете использовать выделенную «шину событий», полностью исключая свой класс сущностей.О вашей проблеме: если STATE используется только в анимации, вам даже не нужно показывать это другим компонентам. Если он имеет более одного использования, то вам нужно выставить его.
Система компонентов / подсистем, которую вы описываете, чувствует себя в большей степени основанной на иерархии, чем на компонентной. В конце концов, то, что вы описываете как компоненты, на самом деле является структурой данных. Это не значит, что это плохая система, просто я не думаю, что она слишком хорошо подходит для компонентного подхода.
Как вы заметили, зависимости являются большой проблемой в компонентных системах. Есть разные способы справиться с этим. Некоторые требуют, чтобы каждый компонент объявлял свои зависимости и делал строгую проверку. Другие запрашивают компоненты, реализующие определенный интерфейс. Третьи передают ссылку на зависимые компоненты, когда они создают каждый из них.
Независимо от того, какой метод вы используете, вам понадобится какой-нибудь GameObject, который будет действовать как набор компонентов. То, что предоставляет GameObject, может сильно различаться, и вы можете упростить свои межкомпонентные зависимости, перенеся некоторые часто используемые данные на уровень GameObject. Unity делает это с помощью преобразования, например, заставляет все игровые объекты иметь один.
Что касается проблемы, которую вы задаете для разных состояний / анимации для разных игровых объектов, то вот что я хотел бы сделать. Во-первых, я бы не стал слишком увлекаться на данном этапе реализации: реализовывайте только то, что вам нужно сейчас, чтобы заставить его работать, затем добавляйте навороты по мере необходимости.
Итак, я бы начал с компонента State: PlayerStateComponent, Enemy1State, Enemy2State. Компонент состояния позаботится об изменении состояния в соответствующее время. State - это нечто, почти все ваши объекты, поэтому оно может находиться в GameObject.
Тогда будет AnimationCompoment. Это будет словарь анимаций, привязанный к состоянию. В update () измените анимацию, если состояние меняется.
Есть отличная статья о построении фреймворка, которую я не могу найти. Он сказал, что когда у вас нет опыта работы с доменом, вы должны выбрать одну проблему и выполнить простейшую реализацию, которая решает текущую проблему . Затем вы добавляете еще одну проблему / вариант использования и расширяете структуру по мере продвижения, чтобы она росла органично. Мне очень нравится такой подход, особенно когда вы работаете с новой концепцией, как вы делаете.
Реализация, которую я предложил, довольно наивна, но вот некоторые возможные улучшения, поскольку вы добавляете больше вариантов использования:
источник
В дополнение к ответу ADB вы можете использовать http://en.wikipedia.org/wiki/Dependency_injection , которое помогает, когда вам нужно создать множество компонентов, передавая их как ссылки на их конструкторы. Очевидно, что они все равно будут зависеть друг от друга (если это требуется в вашей кодовой базе), но вы можете поместить всю эту зависимость в одно место, где устанавливаются зависимости, а остальной части кода не нужно знать о зависимости.
Этот подход также хорошо работает, если вы используете интерфейсы, потому что каждый класс компонентов просто запрашивает то, что ему нужно или где он должен быть зарегистрирован, и только среда внедрения зависимостей (или место, где вы все настраиваете, обычно приложение) знает, кому что нужно ,
Для простых систем вы можете обойтись без использования DI или чистого кода, ваши классы RenderingSystem звучат так, как будто вы должны вызывать их статически или, по крайней мере, иметь их в каждом компоненте, что в значительной степени делает их зависимыми друг от друга и трудными для изменения. Если вы заинтересованы в более чистом подходе, проверьте ссылки на ссылку DI wiki выше и прочитайте о Чистом коде: http://clean-code-developer.com/
источник