Из чего состоит персонаж в Unreal Engine?
Как уже упоминалось в разделе Режим игры / Состояние игры, инфраструктура игрового процесса Unreal Engine поможет разобраться в том, как устроены персонажи в Unreal Engine. Игрок состоит из пешки, представляющей его физическое присутствие в игровом мире, и контроллера, который определяет его поведение. Такой модульный подход используется для ИИ и сетевой репликации. Сама иерархия выглядит следующим образом:
Начнём с импорта ресурсов, создания пешки и работы с контроллером игрока. В игре Parrot в качестве героя, управляемого игроком, будет капитан Барбаросса (перейдите на сайт Quaternius, где вы сможете скачать пиратский набор от Quaternius).
Импорт графических ресурсов
Экспортируйте сетку/анимации из предпочитаемого вами инструмента 3D-моделирования в формат, поддерживаемый игровым движком. В данном случае разработчики решили использовать формат .fbx. Ресурсы капитана Барбароссы находятся в папке Содержимое/Assets/Quaternius/PirateKit/Characters/Barbarossa. Для импорта файла .fbx нажмите правой кнопкой мыши для вызова контекстного меню или перетащите его в «Каталог ресурсов». Окно настроек импорта .fbx станет доступным. Выберите подходящие параметры импорта. В данном случае проверьте, чтобы не был выбран какой-либо из скелетов, а также чтобы был отмечен пункт Импортировать анимации. Также необходимо создать новый материал атласа, который будет индексироваться по вашей сетке. Этот материал можно повторно использовать для различных ресурсов пиратского набора. Теперь у вас должны быть эти 3 файла и все анимации, включённые в .fbx.
Для удобства организации файлы последовательности анимации размещены в папке Animations рядом с тремя файлами:
Скелет, скелетная сетка и физические ресурсы
Скелет представляет собой иерархию, которая используется для определения костей (иногда называемых шарнирами) в скелетной сетке. Эти кости должны совпадать с каркасом в инструменте 3D-моделирования, который вы использовали ранее. Скелеты можно повторно использовать в скелетных сетках при условии, что их каркасы совместимы. Также вы могли заметить, что был создан физический ресурс. Физические ресурсы определяют физику и коллизию, используемые скелетной сеткой. Они содержат твёрдые тела и ограничения для симуляции. Для каждой скелетной сетки можно иметь не более одного физического ресурса, который можно включить или отключить. Вы также можете настраивать физические ресурсы на этапе их импорта или создавать новые ресурсы из скелетной сетки.
Схема с анимацией
Скелетная сетка готова, поэтому можно приступить к её анимированию с помощью Схемы с анимацией. Схема с анимацией похожа на систему анимации Mecanim в Unity. Граф Animation в анимационные схемах Blueprint не имеет больших отличий и работает схожим образом. Логический поток в обеих системах выстраивается на условиях и позволяет переводить состояния анимации в конечную выходную позу. Создайте новую схему с анимацией в вашей папке через контекстное меню и выберите ваш скелет. Схема с анимацией будет называться ABP_Captain_Barbarossa и располагаться по пути Содержимое/Blueprints/Player.
В левой части Инспектора схемы вы можете увидеть два графа: граф Event и граф Animation. Граф Animation представляет собой конечный автомат, управляющий финальной выходной позой. В свою очередь, в графе Event вы сможете определять логику, связанную с анимацией. В отличие от Unity, где в компонент Mecanim требуется передавать данные, анимационные схемы Blueprint могут сами получать требуемые данные для заданного события. К примеру, вы можете запросить значение скорости персонажа и управлять анимацией уже на основании полученного значения. Оптимальным вариантом будет использование узла Event Blueprint Initialize Animation (Инициализация анимации в схеме события) в графе Event, а также Get the Owning Actor (Получить актор-владелец), после чего кэшировать их компонент перемещения в переменную. Это позволит при каждом такте BlueprintThreadSafeUpdateAnimation проверять значение скорости напрямую из компонента перемещения. Кроме того, вы также можете передавать переменные между графом событий или графом анимации.
Обязательно самостоятельно ознакомьтесь с уже настроенной схемой анимации для капитана Барбаросса. Двойной щелчок по узлу позволяет отобразить данные о том, как конечные автоматы, состояния и правила состояний настроены для конечной выходной позы. Там же вы сможете найти примеры использования проигрывателя последовательностей и пространств смешивания. Аналогичном образом, граф событий показывает, как анимация выполняется на основе данных персонажа: эту взаимосвязь мы подробнее разберём далее в статье.
Пешка
Анимация для скелетной сетки готова, поэтому пора приступить к созданию пешки, которая будет использоваться режимом игры. Разработчики решили использовать персонажа Unreal Engine по умолчанию, являющегося дочерним классом класса C++ пешки по умолчанию. У класса персонажа есть компонент перемещения персонажа, который особенно пригодится для игры и является ещё одним классом, от которого можно будет отталкиваться.
Пешки как игрока, так и противника имеют некоторые общие функции, такие как очки жизни, возможность попадания и смерть. Эти возможности делаются общими за счёт создания класса C++ AParrotCharacterBase, наследующегося от ACharacter. Этот класс послужит хорошей основой, поскольку пешки противника и игрока различаются по поведению.
Далее создайте AParrotPlayerCharacter на C++ для обработки логики конкретно для игрока. Наконец, создадим схему для визуального представления вашего персонажа. В качестве схемы попугая будет выступать BP_ParrotPlayerCharacter, находящийся в разделе Содержимое/Blueprints/Player. Иерархия наследования выглядит следующим образом:
Открыв BP_ParrotPlayerCharacter, вы должны увидеть несколько компонентов в инспекторе компонентов в левой части окна редактора. В компоненте сетки вы можете задать ресурс скелетной сетки, а также схему с анимацией в классе анимации. Если сетка расположена неправильно, вы можете изменить значения преобразования, чтобы выровнять её относительно компонента капсулы. Должно получиться следующее:
Далее вы можете назначить класс пешки по умолчанию для схемы в ресурсе режима игры.
Теперь в игре есть анимированная пешка, которую можно использовать!
Контроллер игрока
Пешка уже готова, так что приступим к созданию контроллера игрока. Контроллер игрока по сути представляет собой то, за счёт чего внутриигровой персонаж будет следовать командам игрока. При создании игры следует продумать то, где мы будет определять события ввода. Для простых игр, где пешки не меняются, пешка вполне подойдёт. Однако при более сложных системах поведения лучше использовать контроллер игрока. Пешки по сути являются «временными» объектами, которые можно привязать к контроллеру игрока или отвязать от него. Пешки можно создавать и уничтожать, в то время как контроллер игрока сохраняется на протяжении всей игры.
Конкретно для контроллера игрока вам не понадобится прописывать логику на C++: достаточно просто создать схему, которая будет выполнять за вас всё необходимое. BP_ParrotPlayerController находится в папке Содержимое/Blueprints/Player. Иерархия наследования выглядит следующим образом:
Внутри схемы вы можете заметить узлы событий ввода, которые непосредственно связаны с базовой логикой игрового процесса. Эти события ввода, в частности, связаны с расширенным вводом. О том, как здесь выполняется настройка, вы можете узнать в разделе документации Расширенный ввод. Кэширование пешки персонажа игрока (попугая) в самом начале игры позволяет использовать её для последующего вызова базовых функций перемещения. Сюда относятся Добавить ввод перемещения, Прыжок и StopJump.
Самое время всё протестировать! В схеме режима игры задайте новый класс контроллера игрока и проверьте, есть ли возможность использовать контроллер в игре:
В выпадающем списке редактора уровней проверьте, что у вас выбран верный режим игры:
Наконец, проверьте, чтобы на карте был актор PlayerStart и камера для просмотра. После нажатия на кнопку запуска игры вы увидите, как ваш персонаж двигается и воспроизводит анимации:
Компонент перемещения персонажа в игре Parrot
Базовый класс ACharacter имеет широкий набор встроенных функций и возможностей. В качестве примера рассмотрим компонент актора UCharacterMovement. Компонент перемещения персонажа обрабатывает всю логику его перемещения по миру. Он поддерживает ходьбу, бег, падение, плавание, полёт, а также пользовательские режимы перемещения. Рекомендуем изучить это самостоятельно, чтобы получить представление о том, как работает система перемещения персонажа, а также чтобы понять, насколько широкие возможности предоставляют компоненты акторов.
В данном случае базовый компонент перемещения персонажа не давал того ощущения игры, которое разработчики хотели получить от игры. Однако он стал отличной основой, на которой удалось реализовать изначальную задумку. Класс C++ UParrotCharacterMovementComponent наследуется от компонента UCharacterMovementComponent. Далее мы можем задать компонент перемещения для компонента перемещения CDO в BP_ParrotPlayerCharacter следующим образом:
Какую функцию выполняет компонент перемещения в игре Parrot? Компонент позволяет создать прыжки в стиле классических платформеров за счёт переопределения функций базового компонента перемещения, связанных с прыжками. Используя настраиваемые параметры, вы можете менять шкалу гравитации и скорость прыжка персонажа игрока, чтобы он достигал максимальной высоты за определённое время. При достижении наивысшей точки вы можете начать применять шкалу гравитации падения. Если игрок отпустит кнопку прыжка раньше, вы можете применить множитель, чтобы соответствующим образом масштабировать гравитацию.
Это позволит добиться ощущения прыжка как в классических платформерах, в отличие от простого применения импульса по оси Z.
Благодаря тому, что всю основную работу за вас выполняет базовый компонент перемещения персонажа, вы можете сразу заняться логикой прыжков для компонента перемещения персонажа игры. Для получения полного понимания того, как все компоненты перемещения работают вместе, обратите внимание на значения в инспекторе для BP_ParrotPlayerCharacter на компоненте перемещения. Логику перемещения можно сделать ещё более комплексной, чтобы она подходила для самых разнообразных ситуаций.