Компонентный / сущностный дизайн + деревья поведения => как интегрировать?

9

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

Таким образом, я получил (немного расширенный) сущности , которые в основном являются intидентификатором, понятным для человека именем, std::mapкомпонентами и long«индикатором типа», который используется, чтобы показать, какие компоненты присутствуют (у меня есть степень два enumдля всех компонентов типы и всякий раз, когда компонент добавляется к сущности, я автоматически изменяю это долго с помощью побитовых операций, сравните этот ответ ).

Затем есть Компоненты , также довольно простые: intID, enumкак тип компонента, указатель родительского Entity и a std::mapвсех свойств, которые этот компонент содержит.

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

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

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

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

  1. Мои БТ будут читаться из файлов (снова). В настоящее время мне трудно понять, как лучше установить связь между BT Actionэтим деревом и реальным кодированием в моем приложении. Должен ли я создать какую-то карту между именами действий, используемыми в файлах BT, и указателем функции на фактическую реализацию логики? Каков обычный подход к решению этой проблемы?

  2. Я предполагаю, что мне придется создавать BT для всех моих различных Entityтипов (то есть для каждой игровой логики / AI-соответствующей комбинации компонентов, как указано в моем многократно упомянутом длинном «индикаторе типа»). В результате не имеет смысла помещать BT Actionреализации в компоненты, так как, скорее всего, в каждом действии будет задействовано много компонентов, не так ли?

  3. Так должна ли BT Actionлогика располагаться в нескольких системах (на чьи методы указывает карта из идеи № 1)? Затем система проверила бы по моему long«индикатору типа», Entityразрешено ли для этого факту, для которого в настоящее время проверен BT и которому было приказано выполнить определенное действие (= метод в системе) (= имеет необходимые компоненты). Но тогда, если нет (потому что, например, создатель BT действительно упустил из виду конкретную ситуацию, когда необходимый компонент может больше не присоединяться к сущности во время выполнения), ничего бы не произошло.

Вопросов:

  • Существуют ли проверенные концепции для такой интеграции?
  • Что вы думаете о моих 3 очках выше?
  • Любые другие вещи, которые приходят на ум, в том числе касательно моего дизайна компонентов / сущностей в целом?
Филипп Альгайер
источник
Пункт 1: Деревья поведения - это не более чем визуальный DSL, используемый в основном для создания поведения персонажа. Компонент BehaviorTree не должен делать больше или меньше, чем компонент Script. По пункту 3: В чем причина использования карты над обычными полями?
Эрик
# 1: Что означает «DSL» в этом контексте? № 3: Извините, но я не могу следовать за вами в этом. Не могли бы вы объяснить, что вы имеете в виду?
Филипп Альгайер
1
вероятно доменно-специфический язык, т.е. пользовательский синтаксис для работы с очень специфической проблемой.
Патрик Хьюз
Патрик прав, хотя семантика также является ее частью, и «очень» может быть исключено из этого определения. - Re 3: Мои извинения, он должен гласить: «В чем причина использования карты над регулярными полями в компонентах
Эрик
Re 3: я хочу возможность позже динамически указывать дополнительные свойства вне кода C ++ (умное слово: управляемый данными). Для простоты я (по крайней мере, на данный момент) поместил в эту универсальную среду (с использованием карт) все свойства, даже те, которые зафиксированы в коде и, следовательно, могут быть настоящими полями C ++. Возможно, придется вернуться к этому позже, если это станет проблемой производительности ...
Филипп Аллгайер

Ответы:

2

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

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

В результате не имеет смысла помещать реализации BT Action в компоненты, так как, скорее всего, для каждого действия будет задействовано много компонентов, не так ли?

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

Различные доступные действия, на самом простом уровне, будут закодированы в различные объекты узла BT. Они должны быть в состоянии заставить соответствующий объект действовать, манипулируя компонентами по мере необходимости, например. доступ к компоненту движения для перемещения.

Kylotan
источник
Пункт № 1: Да, сам BT будет объектом (как я уже сказал, как версия от AiGameDev). Я просто думал о функторах для самих действий, но ваш абзац № 2 изменил это. По какой-то причине этот действительно простой подход никогда не приходил мне в голову (у сущности есть собственный экземпляр члена BT). Вероятно, из-за совершенно нового компонента, я больше не думал прямо и просто, поэтому я искал способ смешать компоненты с компонентами BT, но это действительно не нужно.
Филипп Альгайер
Главное, что я потерял ранее, было то, как связать действие с сущностью. Теперь ясно: действия знают, какому объекту через его дерево, в свою очередь, известен объект, которому он принадлежит.
Филипп Альгайер
@Philip Allgaier Мне интересно, как вы закончили создание узла BT? Вы создали его как 1 узел поведения = 1 сущность (это будет много сущностей на 1 игровой объект), или создали узел как обычный класс (не связанный с ECS), или использовали другие подходы? Поблагодарить!
cppBeginner