Создание естественного искусственного интеллекта

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

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

Я начал с создания шаблона одной из таких точек интереса для работы. Первой я создал обеденный стол со стульями, за которым ИИ будет ходить, чтобы поесть. POI состоит из родительского объекта с некоторым количеством дочерних объектов, которые представляют места, которые может занять ИИ. В случае с обеденным столом родительским объектом является стол, а местами - стулья, на которых сидят гости, а также одно дополнительное место рядом со столом, за которым может стоять работник. Родительский объект имеет скрипт POI, который содержит ссылки на различные рабочие и гостевые места, а также типы задач, которые выполняет POI.

Каждый из спотов также содержит 3 трансформации, трансформацию визуального объекта, одну для начальной позиции визуального объекта и одну для позиции, в которой визуальный объект должен находиться, чтобы быть использованным. Это нужно для того, чтобы, когда ИИ придет посидеть на стульях, стул можно было вытащить из-под стола, чтобы использовать, и задвинуть обратно, когда ИИ уйдет. Затем есть глобальный POIManager, который является синглтоном, существующим в сцене и хранящим ссылку на все POI в сцене, и обрабатывает получение POI и задач для ИИ.

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

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

Этот скриптовый объект содержит необходимую информацию для создания задания, количество времени, которое требуется для его выполнения, кто может выполнить задание, и задание, которое создается по его завершении, подробнее об этом позже. Затем я создал подкласс TaskTracker под названием OccupantTaskTracker, который принимает OccupantTaskOutline и POISpot - местоположение задачи. Сам класс очень прост, в нем есть метод, позволяющий получить местоположение спота для задачи, чтобы ИИ мог отправиться в это место. Прибыв на место, задача говорит локации подготовиться к тому, чтобы ИИ занял ее, в случае со стульями это означает, что стулья выдвигаются. После того как стулья передвинуты, задание говорит жертве занять место, в результате чего ИИ "садится" на стул. В данный момент анимация отсутствует, поэтому ИИ просто стоит внутри стульев. В этот момент запускается задание, которое запускает таймер, добавляющий прогресс к заданию, по истечении указанного времени задание завершается, и задание говорит жертве освободить место, а стулу вернуться в исходное положение.

По завершении задания локация создает новое задание, и здесь в дело вступает выходная задача из контура задания. Новая задача создается как обычно, но если это рабочая задача, то она отправляется в рабочие места POI, а если гостевая, то в гостевые места POI. Цель этой системы - сделать возможными как повторяющиеся задания, которые после выполнения создадут еще один свой экземпляр, так и серии заданий, которые создают разные задания после их выполнения в серии. Например, задание на ужин за столами создает задание на уборку для работника, а задание на уборку, в свою очередь, создает задание на ужин для гостей.

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

Таков общий обзор всей системы. Это невероятно переусложненный способ реализации данной функциональности, но смысл был в том, чтобы создать систему, которую можно легко расширить для других типов задач. Например, сейчас я работаю над созданием другого типа задачи, в которой ИИ будет искать объект, оставленный игроком на уровне, собирать его и возвращать на прежнее место. Поскольку я проделал большую работу по созданию фундамента систем, мне невероятно легко создавать новые задачи с очень небольшим техническим долгом. Для дальнейшего масштабирования проекта может быть полезен найм удаленной команды разработчиков.