Как реализовать поведение в компонентной игровой архитектуре?

21

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

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

На мой взгляд, у меня есть два подхода к реализации:

  • Создайте один AI-компонент, содержащий всю логику игрока (либо отделенную от реального компонента, либо встроенную как PlayerAIComponent). Я могу легко, как применить ограничения состояния без создания связи между отдельными компонентами, составляющими объект игрока. Однако AI-компонент не может быть разбит. Если у меня есть, например, враг, который может только стоять и ходить или только ходить и время от времени размахивать мечом, я должен создать новые AI-компоненты.
  • Разбейте поведение на компоненты, каждый из которых идентифицирует определенное состояние. Затем я получаю StandComponent, WalkComponent и SwingComponent. Чтобы обеспечить соблюдение правил перехода, я должен соединить каждый компонент. SwingComponent должен отключить StandComponent и WalkComponent на время колебания. Когда у меня есть враг, который только стоит, время от времени размахивая мечом, я должен убедиться, что SwingComponent отключает WalkComponent, только если он присутствует. Хотя это позволяет лучше смешивать и сопоставлять компоненты, это может привести к кошмару удобства сопровождения, так как каждый раз, когда добавляется зависимость, существующие компоненты должны обновляться, чтобы соответствовать новым требованиям, предъявляемым к персонажу в зависимости.

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

Подводя итоги: следует ли мне разбить всю логику ИИ на один компонент или разбить каждое логическое состояние на отдельные компоненты, чтобы легче создавать варианты сущностей?

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

Диаграмма компонентов

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

Вопрос в том, являются ли это единственными двумя вариантами структурирования ИИ в компонентной сущности, и если да, то что даст максимальную гибкость?

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

Ответы:

6

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

Я думаю, что согласен с Грегори, что у вас не должно быть отдельных компонентов состояния стенда и ходьбы. Это просто компонент движения со скоростью 0. С другой стороны, если у вас есть объекты, которые не могут двигаться, вы должны либо разделить его, либо просто поместить какое-то логическое ограничение в состояние движения, которое предотвращает ненулевую скорость ,

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

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

Tesserex
источник
Разве государственная структура не подразумевает первую ситуацию? Это приводит к тому, что один AIComponent реализует конечный автомат, содержащий различные объекты состояния. Под вторым вариантом я имел в виду, что WalkComponent и SwingComponent имеют тот же тип, что и, скажем, RenderComponent и PhysicsComponent.
призрак
@ghostonline Насколько идея идет, вроде. В реализации не очень. AIComponent будет отдельным, как на второй диаграмме. Он не будет содержать другие компоненты. Более важный вопрос для вашей второй ситуации: если разработчик просто выбирает компоненты без программиста, как сущность узнает, когда следует изменить состояние? Разные состояния подразумевают разные переходы состояний - кому-то еще нужно их указать.
Tesserex
Вы имеете в виду добавление компонента AIComponent к объекту на диаграмме 2, который будет управлять компонентом Stand / Walk / Swing? Моя идея заключалась в том, что компоненты посылают сигналы блокировки или активации при определенных условиях. Например, SwingComponent будет излучать общие сигналы, например, сигнал "bound_feet" при запуске и "release_feet" при завершении свинга. WalkComponent будет отключать и включать себя на основе этих сигналов. Поскольку «переходы состояний» заключены в самих компонентах, разработчику не понадобится программист, соединяющий компоненты вместе.
призрак
@ghostonline Это хорошо работает для вещей, которые имеют фиксированные правила, такие как «не может ходить, покачиваясь», но как насчет переходов между стойкой и ходьбой? Если стоять контролирует, как он узнает, чтобы попробовать ходить? Логика стояния может захотеть выбрать либо ходьбу, либо свинг, на что влияет полное отсутствие способности к ходьбе - в этом случае она всегда должна выбирать свинг. Но я думаю, что вы на правильном пути.
Tesserex
2

По крайней мере, я бы оставил AI игрока (или то, что я бы назвал Player Controller) своим собственным компонентом. В большинстве игр игрок принципиально отличается от неигровых персонажей, которых нельзя обобщать между собой, кроме как в основах, таких как очки жизни.

Для NPC я вижу StandComponent и WalkComponent как аспекты одного и того же. Вы когда-нибудь собираетесь иметь WalkComponent без StandComponent? Я сомневаюсь в этом. Аналогично, RunComponent будет просто WalkComponent с более высокой скоростью и различными анимациями. Я вижу ценность в наличии NPCMovementComponent и отдельного NPCSwordFighterComponent, но даже для меня это похоже на чрезмерную работу.

Грегори Эйвери-Вейр
источник
Я бы не стал так сильно разделять движение NPC и игрока. Действия движения, которые управляют анимацией и физикой, могут определенно быть разделены; это то, что выбирает действия или переходы, которые отличаются (игрок принимает данные, пока ИИ ... ИИ). Я согласен, что у вас будет PlayerController, но у вас также будет AIController, оба из которых могут использовать компоненты Movement / Swing Components для выполнения реальной анимации / физики.
доморощенный
Правда. Я предполагаю, что все движущиеся объекты имеют PhysicsComponent или MovementComponent, который обрабатывает их движение, и что PlayerController и AIController будут использовать это для обработки движения. Движение определенно должно быть отдельным компонентом, так как могут быть вещи, которые должны двигаться, которые не имеют ИИ или имеют самый простой ИИ (глупые физические объекты, такие как ящики или мусор).
Грегори Эйвери-Вейр
2

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

Конечный автомат C ++

Выше приведен конкретный пример конечного автомата в c ++, который может использоваться как игроками, так и ИИ.

Кайл С
источник
1

То, что вы хотите, это компонент, управляющий движением персонажей (игрока и NPC). Компонент AI или компонент игрока отправит команды этому компоненту движения и проверит, можно ли инициировать действие. Это будет заключать ваши ограничения движения в один компонент. Ваш код AI и код игрока не должны знать, как исполняется свинг-меч. ИИ будет иметь внутренние состояния, например: холостой, атакующий, бегущий.

Стивен
источник
1
TYPO: "Он получит ..." что от компонента AI?
щенок