Приветствую!
Если вы давно мечтали оживить свой игровой мир в Unreal Engine, добавив в него NPC (неигрового персонажа), который будет перемещаться по карте или даже преследовать игрока, то вы попали по адресу! В этой статье я подробно расскажу, как шаг за шагом создать такого персонажа: от настройки базового AI до реализации логики преследования.
Неважно, новичок вы в Unreal Engine или уже имеете опыт, этот гайд поможет вам разобраться в основах работы с искусственным интеллектом и создании интерактивных NPC. Ну что, поехали🚀
И так.
Идём на сайт: www.mixamo.com , регистрируемся.
Теперь переходим к его скачиванию.
Далее нам нужны анимации для нашего персонажа. И первая анимация - это бег. Для этого идём на страницу Animations сайта www.mixamo.com и в поисковой строке пишем "Run".
В открывшемся окне скачивания выбираем такие параметры, как "60 FPS" и "Without Skin".
Где значение FPS (от англ. frame per second) - это количество кадров, сменяющих друг друга за одну секунду. А Without Skin - без текстуры. В последнем, всё потому что мы уже скачали персонажа с текстурами, и нам нужна лишь анимация под конкретный скелет.
Теперь выберем анимацию "Idle" для нашего персонажа. Это тип анимации, которая будет срабатывать, когда наш персонаж ничего не делает. Другими словами анимация по умолчанию.
Повторяем все те действия, что и при скачивании анимации бега.
Теперь запускаем нашу программу Unreal Engine версии 5.4.4. Открываем нужный проект и в каталоге ресурсов создаём папку для нашего персонажа.
В папке персонажа создадим новую папку, отвечающую за модель нашего персонажа, которую так и назовём "Model"
Помните, чтобы не возникало ошибок в будущих проектах, никогда не используйте в названиях файлов кириллицу.
Перейдём к импорту модели нашего персонажа в необходимую папку. Для этого откроем в пуске компьютера папку, где скачен наш персонаж в T-pose и через ЛКМ (левый клик мыши) перенесём в программу Unreal папку Model
После успешного импорта должны появится файлы разного формата.
Теперь в папке нашего персонажа создадим папку отвечающую за все анимации. Назовём её соответственно Animations.
Повторяем все те же действия с импортом файлов анимации как и в случае переноса самого персонажа. Однако совершаем с привязкой к основном скелету персонажа.
Т.е. в появившемся окне импорта, в разделе "Skeleton" выбираем скелет нашего персонажа, который уже был загружен в Unreal.
Ниже, в разделе "Animations Length" выбираем параметр "Animated Time" и жмём "Импорт всего".
Повторяем действия для анимации стояния, она же "Idle" (по умолчанию) и жмём "Импорт всего".
Теперь перейдём к созданию "Bluerprint". Краткая теоретическая информация.
Blueprint (или блюпринт) — система визуального программирования в Unreal Engine. Она позволяет создавать игровые объекты и логические последовательности без написания кода.
Через ПКМ (правую кнопку мыши) в папке вашего персонажа создаём "Класс Bluerprint"
В открывшемся окне выбираем третью позицию под названием "Character".
Character Blueprint в Unreal Engine — это специализированный класс Blueprint, предназначенный для создания и управления персонажами, управляемыми игроком, и NPC. Т.е. как раз он нам и нужен.
Обязательно даём название. В моём случае этот файл будет называться "NPC_DeD"
Открываем созданный нами файл, раздел окно просмотра (по умолчанию), значения класса по умолчанию. Справой стороны, сведения, сетка, строка "Skeletal Mesh Asset" и выбираем в выпадающем меню скелет нашего персонажа (T-pose).
Далее необходимо нашего персонажа разместить в "Capsule".
Capsule в Unreal Engine — это простая коллизия (Simple Collision) в виде куба, сферы или капсулы. Она используется для обнаружения столкновений с другими объектами.
Нажмём клавишу "E" (англ.), после чего у нас активируется вращение нашего персонажа. Повернём его в сторону направления стрелки капсулы (Capsule).
Жмём клавишу "W" (англ.) - она отвечает за перемещение объектов по трём осям: X, Y и Z. И подвинем наш объект по необходимой высоте.
Вернёмся в папку нашего персонажа и создадим следующий файл класса Blueprint, который находится в разделе все классы.
Нам необходим файл, класса Blueprint, "Ai Controller"
— это особый тип контроллера, который используется для управления персонажами с помощью искусственного интеллекта.
Переименовываем файл на "NPC_AI"
Вернёмся к файлу персонажа, перейдём в раздел "Значения класса по умолчанию", в поисковой строке "Сведения" пишем слово "Controller". Ниже находим строку "Пешка". И в разделе "AI Controller Class" выберем наш созданный контроллер (NPC_AI). Проще говоря, в будущем этим персонажем будет управлять именно этот файл.
Откроем файл "NPS_AI" (Наш будущий искусственный интеллект персонажа) и перейдём в раздел "Event Graph".
Создадим первую ноду. Сначала разберемся, что такое нода. По сути их огромное количество, и они все базируются для выполнения тех или иных условий. Активируют событие, текстуры, звуки, отвечают за логику поведения, физику объектов и много чего ещё.
Ноды — это узлы, которые используются для выполнения определённых задач или вычислений.
И первая нода, которая присутствует у нас на Event Graph называется "Event Begin Play"
"Event Begin Play" — это событие, которое срабатывает при старте уровня. Также оно может вызываться внутри вызванного на сцену блупринта, например, при спауне персонажа.
Так вот, от "Event Begin Play" создаём ноду "Run Behavior Tree", она же нода отвечающая за запуск дерева поведения.
Вернемся в папку с нашим персонажем и создадим то самое дерево поведения. Для этого через ПКМ откроем контекстное меню создания файлов, перейдём в раздел "Искусственный интеллект", из выпадающего меню выберем "Дерево поведения".
Дадим название файлу "NPC_BT".
Для полноценной работы нашего "Behavior Tree" необходим ещё один файл. Находится он в том же разделе, что и дерево поведения, в называется "Информационная доска" (Blackboard Data). Создаём.
Даём название "BB_NPC"
Откроем вновь файл "NPC_AI", перейдём в "Event Graph" и в ноде "Run Behavior Tree", в выпадающем меню выберем наше дерево поведения созданное ранее "BB_NPC".
Дерево в свою очередь для своих действий будет брать информацию (ключи) с контейнера данных (Информационной доски). Для этого её необходимо подключить. Откроем файл отвечающий за наше дерево, "NPC_BT". Раздел сведения, Behavior Tree, Blackboard Asset и в выпадающем меню выберем нашу информационную доску "BB_NPC"
Открываем файл "BB_NPC", создаём новый ключ типа "Vector", даём имя "Run Location"
Vector-ключ в Blackboard Data — это ключ, который используется для хранения точек в трёхмерном пространстве.
Возвращаемся в наше дерево поведения и через удерживание ЛКМ создадим первую ноду "Sequence" (секвенцию) от "ROOT".
Root (корень) в дереве поведения (Behavior Tree) для NPC — это узел, который автоматически добавляется при создании Behavior Tree. Он используется для настройки свойств дерева поведения и назначения актива Blackboard.
А Root — начальная точка дерева поведения. С её помощью можно добавлять различные узлы, которые определяют поведение NPC.
Создадим следующую ноду от "ROOT" под названием "Move To"
Move To — это нода в дереве поведения для NPC, которая позволяет перемещать персонажа к указанной точке или актору.
Нажмём на ноду "Move To" и сведениях перейдём в раздел "Blackboard Key", выберем из выпадающего меню параметр "Run Location", т.е. выберем ключ отвечающий за перемещение в пространстве.
Теперь создадим новую задачу для нашего дерева поведения. Для это обратимся к левой верхней панели рабочего пространства и нажмём "Новая задача". В появившемся окне пока ничего не меняем и просто жмём "Сохранить"
Откроем созданный файл. Перейдём в раздел "Графы", ниже "Функции", выпадающее меню "Переопределитель", и выберем функцию "Receive Execute AI". После проделанных манипуляций она должна появиться на нашем "Event Graph".
Receive Execute AI — это событие, которое вызывается, когда задача начинает выполняться. С помощью Receive Execute AI можно получить доступ к боту (AI), к Blackboard и нужным переменным, чтобы сразу начать «атаковать» или запускать нужную логику.
От ноды «Receive Execute AI» создаём ноду «Set Blackboard Value as Vector»
Set Blackboard Value as Vector — это функция, которая задаёт ключу blackboard значение случайной точки.
В левой панели нашей схемы создаём новую переменную, даём имя "Blackboard" и в значение булево меняем на "Blackboard Key Selector".
"Blackboard Key Selector" — это структура, которая помогает определить типы разрешённых записей в blackboard. Иными словами, с помощью Blackboard Key Selector можно, например, определить, какие записи могут храниться в blackboard: только точки или объекты, полученные из класса актора.
От "Controlled Pawn" создаём ноду "Get Actor Location". С помощью этой ноды можно получить координаты.
Теперь создадим ноду, которая будет вычислять новые координаты для персонажа, исходя из его текущего местоположения, но в пределах заданного радиуса, называется "Get Random Reachable PointlnRadius". Выставим этот радиус в пределах 1000.
Нашу ранее созданную переменную "Blackboard" подключим в "Key" ноды "Set Blackboard Value as Vector" перетянув из левого меню через ЛКМ прямо в необходимое место.
"Random Location" ноды "Get Random Reachable PointlnRadius" подключим узел к "Value" ноды "Set Blackboard Value as Vector"
И завершим нодой, которая будет сообщать нашему дереву, что задача выполнена успешно. Для этого от "Set Blackboard Value as Vector" создадим ноду "Finish Execute".
Чтобы происходила проверка условий успешного завершения задачи, из "Return Value" ноды "Get Random Reachable PointlnRadius" подключим узел к "Success" ноды "Finish Execute".
В панели ресурсов найдём файл, созданный нами ранее, отвечающий за новую задачу. Его название примерно такое: "BTTask_BluprintBase_New". Переименуем его в "Run Task" и вернемся в файл нашего дерева.
И теперь перед "Move To" создадим последовательный узел "Run Task".
Нажмём на него и в боковой панели слева (сведения) выберем параметр "Run Location"
Следующий последовательный узел будет отвечать за анимацию, которая будет запускаться при движении нашего NPC по локации. Создаём секвенцию "Play Animation".
Переходим в раздел сведения, "Animation to Play" и выбираем анимацию бега.
Далее, аналогичным способом создадим анимацию "стояния", когда NPC достигнет определенной точки. Другими словами, чтобы он останавливался и наслаждался местными красотами.
Завершим последним последовательным узлом нашего дерево ИИ секвенцией "Wait"
Wait — узел, который позволяет дереву ждать до завершения указанного времени ожидания (Wait Time).
С помощью этого узла можно, например, сделать так, чтобы персонаж не бегал постоянно, а подождал определённое количество секунд.
В итоге, нашего дерево поведения NPC должно в конце выглядеть примерно таким образом.
Перейдём в наш мир и создадим собственно карту передвижения NPC. Для этого в расстановке акторов найдём "Nav Mesh Bounds Volume". Он и определит зону передвижения, которая будет использоваться искусственным интеллектом для навигации.
Добавим его в нашу сцену.
Увеличим площадь (и высоту по необходимости) данного актора.
Жмём на "Play" в верхнем разделе меню и наслаждаемся своей проделанной работой. (Тестовый пример)
Отлично, теперь сделаем так, чтобы NPC преследовал нашего игрока. Для этого откроем файл "BB_NPC" и создадим новый ключ, категории Key Type Object, даём имя "NPC_Target". В "Key Type" данного ключа выбираем базовый класс "Actor".
Key Type Object — это тип ключа, который позволяет хранить ссылку на объект конкретного типа (в нашем случае, Character)
Далее перейдём в файл "NPC_AI" и от ноды "Run Behavior Tree" создадим ноду "Set Value as Object", т.е. добавим функцию, которая позволяет установить значение как объект.
А нода "Get Player Character" позволяет получить тот самый объект (актор). Следовательно подключим её к области переменной "Object", хранящей в себе отсылку к определённому объекту.
В свободном месте "Event Graph" через ПКМ создадим ноду "Get Blackboard" и подключим к ноде "Set Value as Object" в раздел "Target".
В данной ситуации основная цель Blackboard — обеспечить коммуникацию между разными частями дерева поведения, чтобы они могли обмениваться информацией и принимать обоснованные решения.
В раздел "Key Name" ноды "Set Value as Object" подключим созданную ноду "Make Literal Name" и в поле "Value" даём имя "NPC_Target"
Make Literal Name — позволяет указать имя ключа переменной из Blackboard.
Сверимся с конечной схемой и перейдём к последнему этапу.
В нашем дереве поведения NPC, в секвенции "Move To" нам осталось поменять ключ информационной доски вместо "Run Location" (бег по территории) на "NPC_Target" (преследование игрока), который и будет отвечать за данный тип поведения. Запускаем симуляцию. (Тестовый пример преследования)
Не забываем всё сохранять и компилировать на протяжении всей нашей работы.
Здесь мы подошли к финалу этой непростой, но интересной темы. В завершении, можно поэкспериментировать с NPC и построить ему невероятную локацию с препятствиями. Заодно и проверить, как он справится со сложным маршрутом.