За десятилетия игровые программисты разработали множество методов для формализации и помощи в решении проблемы реализации умного и забавного NPC. Наиболее известные методы:

  • (Конечные) конечные автоматы
  • Деревья поведения

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

С ростом популярности ECS (Entity Component System) возникает вопрос: Совместимы ли эти методы с ECS?

Я думаю, что да, хотя нам нужно изучить, какой ценой.

Начнем с конечных автоматов

Конечный автомат - очень хороший выбор, если вы можете идентифицировать дискретные состояния NPC и если вам нужно ограничить возможность перехода из одного состояния в другое. Часто мы также можем определить события / действия, которые будут отвечать за преобразование состояния, и события / действия, которые будут запускаться при выполнении преобразования.

В ECS состояние представлено компонентами, которые связаны сущностью. Манипулирование состоянием выполняется системами, которые запрашивают сущности по типу компонентов. В ECS сущность может быть связана только с одним экземпляром определенного типа компонента, но, поскольку у нас может быть «бесконечное» количество типов компонентов, пространство состояний также становится бесконечным.

Давайте посмотрим на более практичный пример.

Светофор может иметь 3 состояния: красный, желтый и зеленый. Если мы определим компоненты флагов для каждого состояния, мы сможем добавить все три компонента в одну и ту же сущность, нарушив нашу логику. Чтобы наложить ограничение на состояние, мы можем определить только один компонент: TrafficLightStateComponent, который содержит значение enum TrafficLightState, которое имеет 3 случая red, yellow, green. Таким образом, мы можем быть уверены, что объект, представляющий светофор, может находиться только в одном допустимом состоянии.

А как насчет ограничений в отношении преобразования государства?

Допустим, мы хотим убедиться, что red не может напрямую перейти на green, не находясь в состоянии yellow. На самом деле это намного сложнее. Что мы могли бы сделать, так это реализовать TrafficLightStateComponent таким образом, чтобы разработчики не могли устанавливать значение напрямую, а использовали только общедоступные методы изменения, которые будут проверять, правдоподобен ли переход, который мы хотим выполнить.

Как насчет выполнения действий по изменению состояния?

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

Возможная реализация в Unity ECS

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

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

Деревья поведения

По моему скромному мнению, деревья поведения - отличный способ сделать поток управления сложным алгоритмом, настраиваемым и «выражаемым» на определенном уровне абстракции. Все, что мы можем сделать с деревом поведения, можно сделать с помощью языка программирования общего назначения, но он недоступен для разработчиков игр и его труднее оценить, особенно если у вас есть инструменты для визуализации состояния дерева поведения во время выполнения.

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

Хотя есть много интересных вопросов

  • Должно ли дерево запускаться при каждом тике?
  • Должны ли мы поддерживать состояние работающего узла и при запуске дерева оно должно переходить непосредственно к последнему работающему узлу?
  • Должны ли узлы работать с группой объектов или с одним объектом?
  • Должны ли мы заставить деревья работать параллельно для каждой сущности с помощью задач?
  • Как должно быть представлено дерево (в редакторе)?
  • Должны ли узлы дерева иметь свои собственные параметры / состояние или все должно быть определено с помощью компонентов и сущностей?

Все это отличные вопросы, и ИМХО действительно сложно дать однозначный ответ. Думаю, единственный разумный ответ:

Зависит от инструментария дерева поведения, который вы себе представляете.

Вам необходимо определить фактическую выгоду, которую вы хотите получить, выражая алгоритм NPC с деревом поведения. Ограничение ECS приносит с собой преимущества и недостатки. И никогда не забывайте:

Если он не подходит, не заставляйте его.