Создание патрулирующего врага в Unreal Engine 5 на Blueprints

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

1. Подготовка окружения: Настройка NavMeshBoundsVolume и создание Character Blueprint

Подготовка окружения: Настройка NavMeshBoundsVolume и создание Character Blueprint

Добро пожаловать в курс «Создание патрулирующего врага в Unreal Engine 5 на Blueprints». Это первая статья нашего цикла, в котором мы пройдём путь от пустой сцены до создания полноценного искусственного интеллекта (ИИ), способного самостоятельно перемещаться по уровню, патрулировать территорию и реагировать на окружение.

Прежде чем мы начнём писать логику поведения, нам необходимо подготовить фундамент. Искусственный интеллект в играх не обладает зрением в человеческом понимании. Он не «видит» стены или обрывы. Ему нужна специальная карта проходимости, которая подскажет, где можно идти, а где — нет. Кроме того, нам потребуется само «тело» нашего врага — игровой объект, который будет подчиняться физике и командам перемещения.

В этой статье мы разберем два критически важных этапа:

  • Настройку навигационной сетки (NavMesh).
  • Создание и базовую настройку Character Blueprint для нашего врага.
  • Что такое NavMesh и зачем он нужен?

    Представьте, что вы находитесь в совершенно темной комнате. Чтобы передвигаться и не натыкаться на мебель, вам нужна карта или тактильные ощущения. Для ИИ в Unreal Engine такой картой является Navigation Mesh (или сокращенно NavMesh).

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

    > NavMesh — это невидимая для игрока сетка полигонов, которую движок использует для построения путей от точки А в точку Б, огибая препятствия.

    Без этой сетки функция AI Move To, которую мы будем использовать в будущих уроках, просто не сработает, так как враг не будет знать, существует ли путь к цели.

    !Визуализация навигационной сетки (NavMesh) в редакторе, показывающая доступные для прохода зоны зеленым цветом.

    Настройка NavMeshBoundsVolume

    Чтобы движок сгенерировал навигационную сетку, нам нужно указать ему область, внутри которой это необходимо сделать. Для этого используется специальный объем — NavMeshBoundsVolume.

    Шаг 1: Добавление объема на уровень

  • Откройте ваш проект в Unreal Engine 5.
  • Убедитесь, что панель Place Actors (Размещение актеров) открыта. Если её нет, перейдите в меню Window -> Place Actors.
  • В строке поиска панели введите Nav Mesh Bounds Volume.
  • Перетащите этот актер во вьюпорт (на вашу сцену).
  • Шаг 2: Масштабирование зоны

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

  • Выберите NavMeshBoundsVolume на сцене или в панели Outliner.
  • Используйте инструмент масштабирования (клавиша R) или панель Details, чтобы изменить параметры Scale (Масштаб) или Brush Settings.
  • Убедитесь, что объем полностью покрывает пол и немного уходит под него, а также достаточно высок, чтобы вместить персонажа.
  • Шаг 3: Визуализация и проверка

    Самый важный этап — проверка того, что сетка построилась корректно. Unreal Engine позволяет увидеть NavMesh прямо в редакторе.

  • Нажмите клавишу P (английскую) на клавиатуре.
  • Если вы всё сделали правильно, пол внутри объема окрасится в зеленый цвет.
  • Если зеленого цвета нет: * Проверьте, пересекает ли NavMeshBoundsVolume геометрию пола. * Убедитесь, что у пола есть коллизия (Collision).

    Зеленые участки — это места, где враг сможет пройти. Красные участки (если они есть) или отсутствие цвета означают препятствия.

    Создание Character Blueprint

    Теперь, когда у нас есть «дорога», нам нужен «пешеход». В Unreal Engine существует несколько базовых классов для создания сущностей:

    * Actor: Статичный или простой объект. * Pawn: Объект, которым можно управлять (игрок или ИИ), но без сложной физики движения. * Character: Специализированный тип Pawn, который уже имеет компонент для ходьбы, бега, прыжков и плавания.

    Для нашего врага мы выберем класс Character, так как он содержит компонент CharacterMovementComponent. Этот компонент берет на себя сложную математику передвижения, гравитации и взаимодействия с навигационной сеткой.

    Шаг 1: Создание ассета

  • В Content Browser (Браузере контента) выберите папку, где будете хранить блюпринты (рекомендуется создать папку Blueprints -> AI).
  • Нажмите правой кнопкой мыши на свободном месте.
  • Выберите Blueprint Class.
  • В появившемся окне «Pick Parent Class» выберите Character.
  • Назовите новый файл BP_EnemyBase. Использование суффикса Base полезно, если вы захотите в будущем создать разные типы врагов, наследуясь от этого класса.
  • !Меню выбора родительского класса при создании нового Blueprint.

    Шаг 2: Настройка внешнего вида (Mesh)

    Откройте созданный BP_EnemyBase двойным кликом. Вы попадете в редактор блюпринтов.

  • В панели Components (слева) выберите компонент Mesh (CharacterMesh0).
  • В панели Details (справа) найдите секцию Skeletal Mesh.
  • В поле Skeletal Mesh Asset выберите модель вашего персонажа. Если вы используете стандартный шаблон от третьего лица, это может быть SK_Mannequin или SKM_Quinn.
  • Скорее всего, после выбора меша он окажется в неправильном положении относительно капсулы (Capsule Component).

    * Capsule Component — это физическая оболочка врага. Именно она сталкивается со стенами. * Меш должен находиться строго внутри капсулы.

    Опустите меш по оси Z (обычно на -90 единиц) и поверните его по оси Z (обычно на -90 градусов), чтобы лицо персонажа смотрело в ту же сторону, куда указывает синяя стрелка (ArrowComponent). Синяя стрелка показывает «перед» (Forward Vector) персонажа.

    Шаг 3: Настройка Character Movement

    Это ключевой момент для правильного поведения ИИ при патрулировании.

  • В панели Components выберите CharacterMovement.
  • В панели Details найдите строку поиска и введите Rotation.
  • Найдите галочку Orient Rotation to Movement (Ориентировать вращение по движению) и включите её.
  • Зачем это нужно? Когда ИИ получает команду идти в точку, он начинает двигаться. Если эта галочка включена, персонаж автоматически повернется лицом в сторону движения. Без этой настройки враг будет «плыть» боком или спиной, сохраняя изначальный поворот.

    Также в компоненте CharacterMovement вы можете настроить скорость врага: * Max Walk Speed: Максимальная скорость ходьбы. Для патрулирования рекомендуется ставить значение ниже, чем для погони (например, 200 или 300).

    Размещение врага на уровне

    Последний шаг подготовки — поместить нашего врага в мир.

  • Скомпилируйте (Compile) и сохраните (Save) ваш блюпринт.
  • Перейдите в главное окно редактора.
  • Перетащите BP_EnemyBase из Content Browser на сцену.
  • Убедитесь, что он стоит ногами на полу, в зоне, которая при нажатии P подсвечивается зеленым.
  • Итоги

    Мы успешно подготовили почву для создания интеллекта. У нас есть: * NavMeshBoundsVolume, который определяет, где ИИ может ходить. * BP_EnemyBase, который обладает физикой, моделью и настройками для правильного поворота при движении.

    В следующей статье мы перейдем к программированию логики: научим нашего врага выбирать случайные точки на NavMesh и перемещаться к ним.

    2. Создание системы путевых точек (Waypoints) и логика их хранения

    Создание системы путевых точек (Waypoints) и логика их хранения

    В предыдущей статье мы подготовили фундамент: настроили навигационную сетку (NavMesh) и создали базового персонажа (Character Blueprint). Теперь наш враг может физически находиться в мире и знает, где находятся стены и обрывы. Однако у него пока нет цели. Он просто стоит на месте.

    Чтобы создать патрулирующего врага, нам нужно задать ему маршрут. В отличие от случайного блуждания, патрулирование подразумевает движение по строго определенным местам — контрольным точкам. В игровой разработке эти точки называются Waypoints (путевые точки).

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

    Что такое Waypoint и зачем нужен отдельный класс?

    Технически, путевая точка — это просто координата в пространстве (Vector: X, Y, Z). Мы могли бы просто создать массив векторов внутри врага и вбивать цифры вручную. Но это неудобно:

  • Вам придется копировать координаты из редактора.
  • Если вы захотите подвинуть точку патрулирования, вам придется заново переписывать координаты.
  • Вы не видите эти точки визуально на уровне.
  • Поэтому лучшая практика — создать специальный Actor, который будет служить маркером. Враг будет хранить ссылки на эти акторы. Если вы подвинете актор-маркер на уровне, враг автоматически пойдет к новому месту, так как он ссылается на объект, а не на жестко прописанные цифры.

    Шаг 1: Создание Blueprint для путевой точки

    Давайте создадим простой объект, который будет служить нашей точкой маршрута.

  • Перейдите в Content Browser.
  • Откройте папку с вашими блюпринтами (например, Blueprints -> AI).
  • Нажмите правой кнопкой мыши -> Blueprint Class.
  • Выберите родительский класс Actor.
  • Назовите его BP_Waypoint.
  • Визуализация точки

    Откройте созданный BP_Waypoint. Сейчас он пуст. Нам нужно добавить что-то, чтобы мы могли видеть его в редакторе, но чтобы игрок не видел его в игре.

    Для этого идеально подходит компонент Billboard (Билборд). Это иконка, которая всегда смотрит на камеру редактора.

  • В панели Components нажмите + Add.
  • Найдите и выберите Billboard.
  • (Опционально) В панели Details вы можете изменить иконку в поле Sprite, чтобы она отличалась от стандартной головы дракона (например, выберите текстуру TargetIcon или подобную).
  • Теперь у нас есть объект, который легко найти и выделить на сцене.

    !Визуальное представление компонента Billboard внутри блюпринта путевой точки.

    Шаг 2: Подготовка врага к хранению маршрута

    Теперь нам нужно научить нашего врага (BP_EnemyBase) запоминать список этих точек. Для этого мы будем использовать Массивы (Arrays).

    Создание переменной

  • Откройте ваш блюпринт врага BP_EnemyBase.
  • Перейдите на вкладку My Blueprint (обычно слева).
  • В секции Variables нажмите +.
  • Назовите новую переменную PatrolPath.
  • В панели Details (справа) найдите Variable Type.
  • В поиске типа введите BP_Waypoint и выберите Object Reference (Ссылка на объект).
  • Сейчас переменная может хранить только одну точку. Нам нужно, чтобы она хранила целый список.

  • Рядом с типом переменной есть иконка (обычно полоска или пилюля). Нажмите на неё и выберите иконку в виде сетки 3x3 кубиков — это превратит переменную в Array (Массив).
  • Делаем переменную редактируемой (Instance Editable)

    Это критически важный шаг. По умолчанию переменные, созданные в блюпринте, являются «внутренними» и одинаковыми для всех копий врага. Но мы хотим, чтобы один враг патрулировал коридор, а другой — улицу. Им нужны разные списки точек.

  • Выделите переменную PatrolPath.
  • В панели Details поставьте галочку напротив Instance Editable.
  • Альтернативный способ: нажмите на иконку закрытого глаза справа от названия переменной в списке Variables. Глаз должен стать открытым и зеленым.
  • Теперь мы можем настраивать этот список прямо на уровне для каждого конкретного врага.

    Шаг 3: Расстановка точек и настройка маршрута на уровне

    Пришло время соединить всё вместе.

  • Скомпилируйте и сохраните оба блюпринта (BP_Waypoint и BP_EnemyBase).
  • Перейдите в редактор уровня.
  • Перетащите несколько экземпляров BP_Waypoint на сцену. Расставьте их так, чтобы они образовали замкнутый маршрут (например, вокруг здания).
  • Выберите вашего врага (BP_EnemyBase), который уже стоит на уровне.
  • Посмотрите в панель Details.
  • В категории Default (или там, где вы создали переменную) вы увидите Patrol Path.
  • Добавление точек в массив

    Вы можете добавлять элементы в массив, нажимая на значок +. Но есть способ быстрее и нагляднее:

  • Нажмите на +, чтобы добавить элемент с индексом 0.
  • Вместо выбора из выпадающего списка, нажмите на иконку Пипетки (Pick Actor from Scene) рядом с полем выбора.
  • Кликните пипеткой по первому BP_Waypoint во вьюпорте.
  • Повторите процедуру для остальных точек в том порядке, в котором враг должен их проходить.
  • !Процесс добавления путевых точек в массив врага через панель деталей.

    Теперь этот конкретный враг знает, по каким точкам ему нужно идти.

    Логика выбора следующей точки (Теория)

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

    Для этого нам понадобится еще одна переменная в BP_EnemyBase:

  • Создайте переменную CurrentPatrolIndex.
  • Тип переменной: Integer (Целое число).
  • Это число будет указывать на номер точки в массиве (0 — первая точка, 1 — вторая и т.д.).
  • Математика циклического патрулирования

    Когда враг доходит до точки, мы должны увеличить индекс на 1. Но что делать, когда враг дошел до последней точки? Если мы просто прибавим 1, индекс выйдет за пределы массива, и возникнет ошибка.

    Нам нужно, чтобы после последней точки индекс снова становился равен 0. Для этого в программировании используется оператор Modulo (остаток от деления), который в Unreal Engine обозначается как %.

    Формула расчета следующего индекса выглядит так:

    Где: * — индекс следующей точки, к которой нужно идти. * — текущий индекс точки, к которой враг шел (или дошел). * — шаг приращения (переход к следующей по порядку). * — оператор взятия остатка от деления (Modulo). * — общее количество точек в массиве (Length of Array).

    Пример работы формулы: Представьте, у нас есть 3 точки (индексы 0, 1, 2). Значит .

    * Текущий индекс 0: (Идем к точке 1). * Текущий индекс 1: (Идем к точке 2). * Текущий индекс 2: (Остаток от деления 3 на 3 равен 0. Идем к точке 0).

    Таким образом, мы создаем бесконечный цикл без использования сложных ветвлений If/Else.

    Итоги

    В этой статье мы:

  • Создали специальный актор BP_Waypoint для визуализации маршрута.
  • Настроили массив в BP_EnemyBase для хранения ссылок на эти точки.
  • Сделали переменную редактируемой (Instance Editable), чтобы настраивать уникальные маршруты для каждого врага.
  • Разобрали математическую логику зацикливания маршрута.
  • Теперь у нас есть «мозг», наполненный данными о маршруте. В следующей статье мы заставим «тело» двигаться, используя ноды AI Move To и события On Success.

    3. Программирование AI Controller и использование функции AI Move To

    Программирование AI Controller и использование функции AI Move To

    Мы продолжаем наш курс по созданию патрулирующего врага в Unreal Engine 5. В предыдущих статьях мы подготовили сцену, настроили NavMesh (навигационную сетку), создали персонажа врага и расставили путевые точки (Waypoints). У нас есть «тело» (Character) и «карта» (NavMesh), а также маршрут. Но наш враг всё ещё стоит на месте.

    В этой статье мы займёмся созданием «мозга» для нашего персонажа. Мы разберем, что такое AI Controller, как он управляет пешкой (Pawn), и запрограммируем логику передвижения, используя мощную встроенную функцию AI Move To.

    Понимание концепции: Pawn и Controller

    В Unreal Engine существует четкое разделение между сущностью, которая находится в мире, и сущностью, которая принимает решения. Это можно сравнить с автомобилем и водителем.

    * Pawn (или Character): Это «автомобиль». У него есть колеса (Movement Component), кузов (Mesh) и физика. Он может двигаться, но сам не знает, куда и зачем. * Controller: Это «водитель». Он сидит внутри Pawn и нажимает на педали. Контроллер говорит: «Едь вперед» или «Поверни направо».

    Для игрока существует Player Controller, который считывает нажатия клавиш. Для искусственного интеллекта существует AI Controller.

    !Схема взаимодействия Pawn и AI Controller: контроллер «вселяется» в пешку, чтобы управлять ею.

    Хотя мы могли бы написать логику движения прямо в блюпринте персонажа (BP_EnemyBase), профессиональный подход требует создания отдельного AI Controller. Это позволяет легко менять «мозги» у разных врагов или пересаживать один и тот же интеллект в разные тела.

    Шаг 1: Создание AI Controller

    Давайте создадим «водителя» для нашего врага.

  • Перейдите в папку с вашими блюпринтами (Blueprints -> AI).
  • Нажмите правой кнопкой мыши -> Blueprint Class.
  • В окне выбора родительского класса разверните список All Classes (внизу) или найдите строку поиска.
  • Введите AIController и выберите этот класс.
  • Назовите новый ассет BP_EnemyController.
  • Шаг 2: Назначение контроллера врагу

    Теперь нужно сказать нашему врагу (BP_EnemyBase), что им должен управлять именно этот новый контроллер, а не стандартный пустой.

  • Откройте BP_EnemyBase.
  • В панели Details (убедитесь, что выбрано само название класса в самом верху списка компонентов или (Self)) найдите секцию Pawn.
  • Найдите параметр AI Controller Class.
  • В выпадающем списке выберите созданный нами BP_EnemyController.
  • Чуть ниже найдите параметр Auto Possess AI.
  • Измените его значение на Placed in World or Spawned.
  • > Важно: Настройка Auto Possess AI критически важна. Если оставить значение по умолчанию (Placed in World), то враг будет работать только если вы поставили его на уровень вручную. Если вы создадите врага через спаунер во время игры, он будет стоять и ничего не делать. Значение Placed in World or Spawned гарантирует работу в обоих случаях.

    Шаг 3: Программирование логики движения

    Теперь самое интересное. Откройте BP_EnemyController. Мы будем работать в Event Graph.

    Получение ссылок на данные

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

    Мы будем использовать событие Event On Possess. Оно срабатывает один раз в момент, когда контроллер «вселяется» в пешку.

  • В Event Graph нажмите правой кнопкой мыши и найдите событие Event On Possess (или используйте Event BeginPlay, но On Possess надежнее для AI).
  • У этого события есть пин Possessed Pawn. Вытяните из него связь и введите Cast to BP_EnemyBase.
  • Что такое Casting (Приведение типов)? Контроллер знает, что он управляет каким-то Pawn. Но Pawn — это общий класс. В нем нет переменной PatrolPath. Мы говорим движку: «Проверь, является ли этот Pawn именно BP_EnemyBase. Если да — дай мне доступ к его переменным».

  • От пина As BP Enemy Base (синий выход ноды Cast) нажмите правой кнопкой мыши и выберите Promote to Variable. Назовите переменную ControlledEnemy.
  • Теперь у нас есть сохраненная ссылка на нашего конкретного врага, и мы можем брать из него путевые точки.

    Создание функции движения

    Чтобы не загромождать граф, создадим кастомный ивент (Custom Event), который будет отвечать за отправку врага к точке.

  • Нажмите правой кнопкой мыши на свободном месте -> Add Custom Event.
  • Назовите его MoveToNextWaypoint.
  • Теперь нам нужно узнать, к какой точке идти. Вспомните, что в BP_EnemyBase мы храним массив точек и текущий индекс.

  • Вытащите переменную ControlledEnemy в граф (Get).
  • От неё вытяните связь и найдите Get Patrol Path (наш массив).
  • Снова от ControlledEnemy вытяните связь и найдите Get Current Patrol Index (наше число).
  • Из массива Patrol Path вытяните ноду Get (a copy).
  • Подключите Current Patrol Index в поле индекса ноды Get.
  • Теперь у нас есть ссылка на конкретный BP_Waypoint, к которому нужно идти прямо сейчас.

    Использование AI Move To

    Это главная нода для передвижения ИИ в Unreal Engine.

  • Внутри события MoveToNextWaypoint нажмите правой кнопкой мыши и добавьте ноду AI Move To.
  • Внимание: Убедитесь, что вы выбрали именно AI Move To, а не Simple Move To. У AI Move To есть часы в правом верхнем углу (Latent Action) и выходы On Success / On Fail.
  • !Нода AI Move To — основной инструмент для перемещения персонажей по NavMesh.

    Настройка ноды AI Move To:

    * Pawn: Кого двигаем? Подключите сюда ControlledEnemy (или Get Controlled Pawn). * Destination: Конкретные координаты (Vector). Мы это использовать не будем, так как у нас есть движущиеся акторы. * Target Actor: Целевой объект. Подключите сюда выход из ноды Get, которую мы получили из массива (наш BP_Waypoint). * Acceptance Radius: Как близко нужно подойти? Установите, например, 50.0. Если поставить 0, враг будет пытаться войти прямо в центр точки, что может вызвать застревание.

    Обработка результата (On Success)

    Когда враг дойдет до точки, сработает выход On Success.

  • От On Success добавьте ноду Delay (Задержка). Пусть враг постоит 1-2 секунды, имитируя осмотр территории.
  • После задержки нам нужно переключить индекс на следующий. В прошлой статье мы вывели формулу:
  • Где — новый индекс, — текущий индекс, — шаг приращения, — оператор остатка от деления (Modulo), — количество точек в массиве.

    Реализуем это в блюпринте:

  • Возьмите ControlledEnemy -> Get Current Patrol Index.
  • Добавьте + (Add), прибавьте 1.
  • Возьмите ControlledEnemy -> Get Patrol Path -> Length (длина массива).
  • Используйте ноду % (Integer). Подключите результат сложения в верхний пин, а длину массива — в нижний.
  • Результат запишите обратно в переменную врага: ControlledEnemy -> Set Current Patrol Index.
  • Замыкание цикла

    После того как мы обновили индекс, нужно снова вызвать команду движения.

  • После Set Current Patrol Index вызовите наш кастомный ивент MoveToNextWaypoint.
  • Таким образом, мы создали бесконечный цикл: Иди -> Подожди -> Выбери следующую -> Иди.

    Запуск логики

    Остался последний штрих. Мы создали логику, но не запустили её. Вернитесь к событию Event On Possess (или BeginPlay).

    После того как мы записали переменную ControlledEnemy, просто вызовите MoveToNextWaypoint один раз. Это будет «первый толчок», который запустит всю цепочку патрулирования.

    Возможные проблемы и решения

    Если ваш враг не двигается:

  • Нет NavMesh: Нажмите P на уровне. Если пол не зеленый, AI Move To сразу выдаст On Fail.
  • Враг висит в воздухе: Если враг не касается NavMesh, он не сможет построить путь.
  • Забыли Auto Possess: Проверьте настройки в BP_EnemyBase, стоит ли там Placed in World or Spawned.
  • Пустой массив: Убедитесь, что на уровне вы добавили точки в массив Patrol Path конкретного врага.
  • Итоги

    В этой статье мы: * Разобрали роль AI Controller. * Научились использовать Casting для доступа к данным пешки. * Освоили ноду AI Move To для навигации. * Реализовали циклический алгоритм патрулирования.

    Теперь ваш враг самостоятельно ходит по заданному маршруту! Но пока он полностью игнорирует игрока. В следующих статьях мы добавим ему «зрение» и «слух» с помощью системы Pawn Sensing, чтобы он мог заметить нас и начать погоню.

    4. Реализация цикла патрулирования и добавление задержек на точках

    Реализация цикла патрулирования и добавление задержек на точках

    Добро пожаловать в продолжение курса «Создание патрулирующего врага в Unreal Engine 5 на Blueprints». В предыдущих частях мы проделали огромную работу: настроили навигацию (NavMesh), создали акторы путевых точек (Waypoints) и научили контроллер врага перемещать пешку от одной точки к другой.

    Однако, если вы запустили проект после прошлого урока, вы могли заметить одну деталь: наш враг ведет себя как робот-марафонец. Он добегает до точки и мгновенно, без секунды промедления, разворачивается к следующей. Это выглядит неестественно. Живые существа (и даже патрульные роботы) обычно останавливаются, осматриваются или просто делают паузу перед тем, как продолжить путь.

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

    Анализ текущей логики движения

    Давайте вспомним, как выглядит наш скрипт в BP_EnemyController на данный момент. У нас есть кастомное событие MoveToNextWaypoint, которое вызывает ноду AI Move To.

    Логика работает следующим образом:

  • Контроллер получает команду двигаться.
  • Враг бежит к цели.
  • Как только он касается радиуса цели, срабатывает выход On Success.
  • Мы мгновенно вычисляем новый индекс и снова вызываем команду движения.
  • Проблема кроется именно в пункте 4. Компьютер выполняет инструкции за микросекунды, поэтому для человеческого глаза остановки не происходит вовсе.

    !Схема логики патрулирования с добавлением блока ожидания.

    Добавление фиксированной задержки

    Самый простой способ исправить ситуацию — использовать ноду Delay.

  • Откройте ваш BP_EnemyController.
  • Найдите ноду AI Move To внутри события MoveToNextWaypoint.
  • Обратите внимание на пин On Success (При успехе). Сейчас он, скорее всего, сразу идет к математическим вычислениям индекса.
  • Разорвите связь между On Success и следующей нодой (обычно это Set Current Patrol Index или вычисление).
  • Вытяните связь из On Success и добавьте ноду Delay.
  • В параметре Duration (Длительность) ноды Delay установите значение, например, 2.0. Это означает, что враг будет ждать 2 секунды перед тем, как продолжить выполнение кода.

    Теперь соедините выход Completed ноды Delay с логикой вычисления следующего индекса.

    Добавление случайности (Randomization)

    Фиксированная задержка в 2 секунды лучше, чем ничего, но она все еще предсказуема. Игрок быстро заметит паттерн: «Ага, он стоит ровно 2 секунды». Чтобы сделать поведение более органичным, мы будем использовать случайные числа.

    В Unreal Engine для этого есть отличная нода: Random Float in Range.

  • В BP_EnemyController найдите вашу ноду Delay.
  • Вытяните связь из пина Duration влево и введите в поиске Random Float in Range.
  • У вас появятся два поля: Min и Max.
  • Установите значения: * Min: 1.0 (минимум 1 секунда). * Max: 4.0 (максимум 4 секунды).

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

    Обработка ошибок движения (On Fail)

    В программировании ИИ важно всегда задавать вопрос: «А что, если что-то пойдет не так?». Нода AI Move To имеет выход On Fail (При неудаче). Он срабатывает, если: * Враг застрял. * Точка находится за пределами NavMesh. * Путь заблокирован динамическим препятствием.

    Если мы оставим этот пин пустым, то при ошибке враг просто остановится навсегда. Его логика прервется, так как цепочка событий оборвалась.

    Давайте сделаем простую систему восстановления:

  • От пина On Fail вытяните связь к новой ноде Delay.
  • Установите время, например, 1.0 секунду.
  • После задержки соедините выход с вызовом события MoveToNextWaypoint (без изменения индекса).
  • Логика: Если враг не смог дойти до точки, он подождет секунду и попробует снова пойти к той же самой точке. Если препятствие исчезнет, он продолжит путь.

    Продвинутая логика: Индивидуальное время для каждой точки

    Что если мы хотим, чтобы на углу здания враг стоял долго (осматривал улицу), а в коридоре проходил точку почти без остановки? Случайное число тут не подойдет, так как оно не привязано к контексту места.

    Мы можем хранить время ожидания прямо внутри наших акторов BP_Waypoint.

    Шаг 1: Модификация BP_Waypoint

  • Откройте блюпринт путевой точки BP_Waypoint.
  • Создайте новую переменную (Variables -> +).
  • Назовите её WaitTime.
  • Тип переменной: Float.
  • Важно: Откройте «глаз» рядом с переменной (сделайте её Instance Editable).
  • Скомпилируйте и сохраните.
  • Установите значение по умолчанию (Default Value), например, 2.0.
  • Теперь на уровне вы можете выбрать любую точку и в панели Details задать ей уникальное время ожидания.

    Шаг 2: Чтение данных в контроллере

    Вернемся в BP_EnemyController.

  • Вспомните, что у нас есть ссылка на текущую целевую точку. Мы получаем её из массива PatrolPath по индексу.
  • Перед тем как вызвать Delay, нам нужно получить данные из этой точки.
  • Возьмите ссылку на текущий BP_Waypoint (элемент массива, к которому мы только что шли).
  • Вытяните из него связь и введите Get Wait Time.
  • Подключите это значение в пин Duration ноды Delay.
  • Теперь время ожидания диктуется не случайностью, а настройками конкретной точки на уровне. Это дает вам полный дизайнерский контроль над темпом патрулирования.

    Математика цикла (Повторение и закрепление)

    В прошлом уроке мы использовали формулу для зацикливания маршрута. Давайте убедимся, что она стоит в правильном месте — строго после задержки.

    Формула расчета индекса:

    Где — это индекс следующей точки, к которой нужно направиться, — текущий индекс точки, на которой враг находится сейчас, — шаг приращения (переход к следующему элементу), — оператор взятия остатка от деления (Modulo), а — общее количество точек в массиве (длина массива).

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

    Правильный порядок действий:

  • Дошли (On Success).
  • Подождали (Delay).
  • Обновили индекс (Math).
  • Пошли дальше (MoveTo).
  • Визуальная отладка (Visual Logger)

    Как понять, сколько именно времени ждет враг, не глядя в блюпринт? Можно использовать ноду Print String.

  • Перед нодой Delay добавьте Print String.
  • В пин In String подключите то значение времени (Random или из Waypoint), которое вы подаете в Delay.
  • Теперь при запуске игры в левом верхнем углу будут появляться сообщения: «2.54», «1.1», «3.0». Это поможет убедиться, что система работает корректно.
  • Итоги

    В этой статье мы значительно улучшили поведение нашего ИИ: * Избавились от роботизированного бега без остановок. * Научились использовать Random Float in Range для создания естественной вариативности. * Рассмотрели способ настройки уникальных задержек через переменные в BP_Waypoint. * Обезопасили логику, обработав ветку On Fail.

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

    В следующей статье мы займемся системой восприятия (Pawn Sensing). Мы научим врага видеть игрока, прерывать патрулирование и переходить в режим преследования.

    5. Настройка анимационного блупринта и финальное тестирование врага

    Настройка анимационного блупринта и финальное тестирование врага

    Добро пожаловать в заключительную статью курса «Создание патрулирующего врага в Unreal Engine 5 на Blueprints». Мы проделали долгий путь: настроили навигацию, создали интеллект, научили врага ходить по маршруту и даже добавили реалистичные паузы.

    Однако, если вы запустите игру сейчас, то увидите одну существенную проблему: наш враг перемещается, скользя по полу в позе «Т», или просто стоит в статической позе, перемещаясь силой мысли. Это разрушает погружение в игру. Чтобы вдохнуть жизнь в нашего персонажа, нам нужно настроить анимации.

    В этой статье мы создадим Animation Blueprint, настроим смешивание анимаций покоя и ходьбы (Blend Space) и проведем финальное тестирование всей системы патрулирования.

    Понимание Animation Blueprint

    В Unreal Engine анимация персонажа управляется специальным типом ассета — Animation Blueprint (AnimBP). Это «мозг», отвечающий исключительно за движения тела. Он работает параллельно с основным блюпринтом персонажа (BP_EnemyBase).

    AnimBP состоит из двух основных частей:

  • Event Graph: Здесь мы вычисляем параметры (например, скорость движения или находится ли персонаж в воздухе).
  • Anim Graph: Здесь мы используем эти параметры, чтобы переключать состояния (State Machine) или смешивать анимации.
  • Наша задача — научить AnimBP узнавать, с какой скоростью движется враг, и на основе этого плавно переключаться между анимацией стояния (Idle) и ходьбы (Walk).

    Шаг 1: Создание Blend Space 1D

    Прежде чем создавать сам блупринт, нам нужен инструмент для смешивания анимаций. Если враг стоит, должна играть анимация Idle. Если он идет медленно — Walk должна проигрываться медленно. Если он бежит — Run.

    Для простых переходов, зависящих от одной переменной (скорости), используется Blend Space 1D.

  • Перейдите в папку с анимациями вашего персонажа (обычно Content -> Characters -> Mannequin -> Animations или создайте свою папку Animations в папке AI).
  • Нажмите правой кнопкой мыши -> Animation -> Legacy -> Blend Space 1D.
  • Примечание: В новых версиях UE5 можно использовать обычный Blend Space, но для линейной скорости 1D подходит идеально.*
  • В появившемся окне выберите скелет вашего врага (например, SK_Mannequin_Skeleton).
  • Назовите файл BS_EnemyPatrol.
  • Настройка осей

    Откройте созданный BS_EnemyPatrol.

  • В панели Asset Details (слева) найдите секцию Axis Settings -> Horizontal Axis.
  • Name: Назовите ось Speed (Скорость).
  • Minimum Axis Value: Оставьте 0.0 (персонаж стоит).
  • Maximum Axis Value: Установите значение, равное максимальной скорости вашего врага. В BP_EnemyBase мы настраивали Max Walk Speed. Обычно для патрулирования это около 200 или 300. Давайте установим 300.
  • Добавление анимаций

    Внизу вы видите шкалу (график). Справа — Asset Browser со списком анимаций.

  • Найдите анимацию покоя (например, Idle или MF_Idle). Перетащите её на шкалу в точку 0.0.
  • Найдите анимацию ходьбы (например, Walk_Fwd или MF_Walk_Fwd). Перетащите её на шкалу в точку 300.0 (или в конец шкалы).
  • Теперь, если вы зажмете Shift и поводите курсором по графику, вы увидите, как персонаж плавно переходит из стоячего положения в шаг.

    !Настройка Blend Space 1D: плавный переход от покоя к ходьбе.

    Шаг 2: Создание Animation Blueprint

    Теперь создадим сам контроллер анимаций.

  • В Content Browser нажмите правой кнопкой мыши -> Animation -> Animation Blueprint.
  • В окне выбора родительского класса выберите AnimInstance.
  • Внизу выберите тот же скелет, который вы использовали для Blend Space.
  • Нажмите Create и назовите файл ABP_Enemy.
  • Шаг 3: Программирование логики (Event Graph)

    Откройте ABP_Enemy и перейдите на вкладку Event Graph.

    Наша цель здесь — каждый кадр спрашивать у врага: «С какой скоростью ты движешься?» и записывать это в переменную.

    Получение ссылки на персонажа

    В графе уже должны быть две ноды: Event Blueprint Update Animation и Try Get Pawn Owner.

  • От ноды Try Get Pawn Owner вытяните связь и создайте ноду Is Valid. Это важно, чтобы избежать ошибок, если персонаж еще не загрузился.
  • Соедините Event Blueprint Update Animation со входом Is Valid.
  • Вычисление скорости

    Скорость — это длина вектора скорости (Velocity). Вектор скорости показывает направление и быстроту движения по осям X, Y, Z.

    Математически скорость вычисляется как длина вектора :

    где — итоговая скорость (скаляр), а — компоненты вектора скорости по соответствующим осям.

    В Blueprints нам не нужно писать формулу вручную, для этого есть готовая функция.

  • От ноды Try Get Pawn Owner (или от Is Valid -> Input Object) вытяните связь и найдите ноду Get Velocity.
  • От ноды Get Velocity (желтый пин вектора) вытяните связь и найдите ноду Vector Length.
  • Примечание: Эта нода выполняет вычисление по формуле выше, превращая вектор (направление + сила) в простое число (скорость).*
  • Нажмите правой кнопкой мыши на выходном пине Vector Length (зеленый пин) и выберите Promote to Variable.
  • Назовите переменную GroundSpeed.
  • Соедините выход Is Valid (Valid) со входом ноды установки переменной Set Ground Speed.
  • Теперь каждый кадр переменная GroundSpeed будет обновляться реальной скоростью врага.

    !Логика вычисления скорости персонажа для передачи в анимацию.

    Шаг 4: Настройка графа анимаций (Anim Graph)

    Перейдите на вкладку AnimGraph (обычно слева в списке My Blueprint или двойной клик по AnimGraph в панели слоев).

    Здесь мы скажем движку, какую анимацию играть в зависимости от переменной GroundSpeed.

  • Нажмите правой кнопкой мыши на пустом месте и введите название вашего Blend Space: BS_EnemyPatrol. Выберите Player BS Enemy Patrol.
  • У этой ноды есть вход Speed. Перетащите вашу переменную GroundSpeed из панели переменных (слева) на этот пин.
  • Соедините иконку бегущего человечка (выход Blend Space) со входом Result в ноде Output Pose.
  • Теперь логика завершена: скорость из Event Graph передается в Blend Space, который смешивает анимации и отправляет результат на экран.

    Шаг 5: Назначение AnimBP врагу

    Мы создали систему анимации, но наш враг BP_EnemyBase о ней не знает. Нужно их связать.

  • Откройте блюпринт врага BP_EnemyBase.
  • Выберите компонент Mesh (CharacterMesh0) в панели Components.
  • В панели Details найдите секцию Animation.
  • Убедитесь, что Animation Mode установлен в Use Animation Blueprint.
  • В поле Anim Class выберите созданный нами ABP_Enemy.
  • Скомпилируйте и сохраните BP_EnemyBase.

    Финальное тестирование и отладка

    Настало время проверить работу всей системы, которую мы строили на протяжении курса.

    Чек-лист перед запуском:

  • NavMesh: На уровне есть зеленый пол (нажмите P).
  • Waypoints: На уровне расставлены акторы BP_Waypoint.
  • Враг: BP_EnemyBase стоит на уровне.
  • Маршрут: В деталях врага заполнен массив Patrol Path ссылками на точки.
  • Контроллер: В BP_EnemyBase в поле AI Controller Class выбран BP_EnemyController, а Auto Possess AI стоит в Placed in World or Spawned.
  • Запуск симуляции

    Нажмите кнопку Simulate (или Alt+S), чтобы запустить игру без вселения в персонажа игрока. Это позволит вам свободно летать камерой и наблюдать за врагом.

    Что вы должны увидеть:

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

    Проблема 1: Враг скользит, анимация ног не работает. Причина:* Скорее всего, вы не назначили ABP_Enemy в меш персонажа или забыли соединить Vector Length с переменной в Event Graph. Решение:* Проверьте Шаг 3 и Шаг 5.

    Проблема 2: Враг идет, но анимация проигрывается слишком быстро или медленно. Причина:* Несоответствие скорости в CharacterMovement и масштаба в Blend Space. Решение:* Если Max Walk Speed у врага 600, а в Blend Space ось до 300, то при беге анимация будет «зашкаливать». Уравняйте эти значения.

    Проблема 3: Враг застревает в точках. Причина:* Слишком маленький Acceptance Radius в ноде AI Move To или точка находится под полом. Решение:* Увеличьте радиус прибытия до 50-100 единиц или поднимите BP_Waypoint чуть выше.

    Заключение курса

    Поздравляем! Вы успешно завершили курс по созданию патрулирующего врага.

    Мы прошли путь от пустой сцены до живого персонажа: * Настроили навигационную сетку NavMesh. * Создали систему путевых точек Waypoints. * Запрограммировали AI Controller с использованием циклической логики. * Добавили случайные задержки для реалистичности. * Оживили персонажа с помощью Animation Blueprint.

    Эта база является фундаментом для любого сложного ИИ. Теперь вы можете расширять систему: добавить врагу зрение (Pawn Sensing), научить его преследовать игрока, атаковать или вызывать подкрепление. Принципы работы контроллера и деревьев анимации останутся прежними.

    Спасибо за участие в курсе, и удачи в ваших проектах на Unreal Engine 5!