Маленький питомец, который следует за вами, используя C++ и не используя навигационную сетку.

Кому не нравится иметь милую штучку, которая следует за вами, пока вы отправляетесь в приключения? Это то, что мы делаем!

В Unreal Engine 4 есть фантастический инструмент для реализации этого с помощью навигации, но сегодня я покажу вам, как это сделать с помощью простой математики!

Вы можете следить за этим руководством на моем канале Youtube:
https://youtu.be/ZF9sBNNJ6wk

Вы можете скачать файлы проекта (среда и анимированный кот не включены) здесь:
https://drive.google.com/file/d/1neke3iu3saryEO0CNZx-UkiF6EbgIB5T/view?usp=sharing

Создание Blend Space 1D для смешивания анимации лисы

Первое, что мы собираемся сделать, это подготовить анимацию лисы с помощью Blend Spaces.
Я скачал лису бесплатно, включая анимации из Unity Asset Store. Если вы решите использовать этот ассет, вам нужно будет открыть пакет на Unity и извлечь fbx.
Лиса и анимации уже подготовлены в файлах проекта этого туториала.
https:/ /assetstore.unity.com/packages/3d/characters/animals/toon-fox-183005

Инструмент Blend Space позволяет нам смешивать различные анимации с помощью параметра.
Мы будем использовать свойство Speed ​​в Animation Blueprint для смешивания анимаций.
Щелкните правой кнопкой мыши в браузере содержимого и выберите Blend Space 1D. в меню Анимация.

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

В окне инструмента Blend-Space в поле «Горизонтальные оси» измените поле «Имя» на «Скорость».
Установите для параметра «Максимальные оси» значение 300.

В нижнем инструменте перетащите зеленый ромб влево и перетащите Fox_Idle в эту точку.
Затем перетащите зеленый ромб на 75 и перетащите анимацию Fox_walk.
Наконец, перетащите ромб вправо сторону и используйте анимацию Fox_run в этой точке.

Если вы выполнили эти шаги, вы должны увидеть это:

Если вы переместите ромб слева направо, вы должны увидеть анимацию бездействия, ходьбы и бега с плавным смешиванием между тремя из них.

Создание схемы анимации для использования пространства смешивания

Мы собираемся создать схему анимации и использовать это перемещение в пространстве смешивания.
Вернитесь в браузер контента и создайте схему анимации.

В следующем окне выберите скелет лисы, чтобы схема анимации выбрала правильный скелет и анимацию.

На Anim Graph мы создадим конечный автомат по умолчанию, подключенный к выходной позе.

Если вы выберете узел Result в Output Pose и перетащите его, появится контекстное меню. Введите Default State Machine и выберите его.

Дважды щелкните новый конечный автомат и создайте новое состояние, перетащив булавку входа. Назовите это новое состояние Idle/Run.

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

Дважды щелкните новое состояние, чтобы мы могли подключить анимацию пространства смешивания.
Перетащите пространство смешивания Locomotion из правой панели обозревателя ресурсов и соедините его с выводом результата на выходной позе анимации.
Что такое Осталось подключить параметр Speed, которого ожидает blend-space.
Этот параметр будет UPROPERTY, объявленным в C++-классе Animation Blueprint, который мы создадим далее.

Создание класса C++ Animation Blueprint

Создайте новый C++ и выберите AnimBlueprint в качестве базового родителя. Назовите этот новый класс PetAnimInstance или аналогичный.

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

Давайте вернемся к нашему Fox Animation Blueprint и создадим родительский класс для класса.
Нажмите кнопку «Настройки класса» и выберите новый экземпляр Pet Anim в раскрывающемся списке «Родительский класс» на панели «Сведения».
Если вы скомпилируете и сохраните, вы должны увидеть унаследованное свойство Speed ​​на панели MyBlueprint.

Подключите новое свойство Speed ​​к узлу blend-space, скомпилируйте и сохраните.
Этого должно быть достаточно для нашего следующего шага, персонажа-питомца.

Создание класса C++ персонажа PetFollower

Мы готовы создать питомца, который расширяет встроенный класс Unreal Class Character.

Питомец-последователь будет иметь в качестве скелетной сетки лису и схему анимации, которую мы создали ранее.

Создайте новый класс в Content Browser, выбрав Character в качестве родительского класса и назовите его PetFollower.

Когда Unreal компилируется, вы можете начать добавлять UPROPERTY, который мы можем редактировать в классе Blueprint, который мы создадим позже:

  • SpeedMovement: насколько быстро лиса будет двигаться, следуя за актером (или главным героем).
  • MinimunDistanceToActor: минимальное расстояние, которое лиса будет держать до другого актера.
  • StopRadius: расстояние, на котором лиса начнет замедляться. Это расстояние немного больше, чем MinimunDistanceToActor.

Чтобы отслеживать актора, у нас будет ссылка-указатель.
Мы установим эту ссылку с помощью BlueprintNativeEvent StartFollow, который мы можем вызывать из других акторов.
StartFollow также изменит состояние питомца и активирует галочку, для которой я установил значение false в начале воспроизведения.

StopFollow — простая функция для сброса состояния питомца и отключения галочки. Эта функция не используется в этом уроке, но хорошо, что она есть.

Наконец, нам понадобятся еще несколько переменных, которые помогут нам в наших вычислениях.
Это:
Ссылка на аниматор, анимацию чертежа, которую мы создали ранее.
Питомец текущее состояние.
Местоположение последнего питомца

В функции BeginPlay отключаем галочку питомца, получаем ссылку на PetAnimInstance, чтобы можно было обновить свойство Speed, и инициализируем некоторые переменные

Обработка состояний питомца

Когда игра начинается, начальное состояние питомца будет 0 или ничего. Питомец не будет двигаться, и он будет в режиме ожидания.
Функция StartFollow вызовет начальное состояние 1 и активирует галочку на питомце.
План питомца вызывает функцию StartFollow, передавая главного персонажа (робота) в качестве эталона.
Вы можете вместо этого решите использовать NPC и заставить питомца следовать за ними.

Остальная логика питомца ложится на функцию Tick.

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

Также рассчитываем расстояние между ними.

Состояние 1, это состояние ожидания. Питомец будет терпеливо ждать, пока другой актер (робот) не приблизится хотя бы на 50 единиц, тогда мы переключим состояние на 2.

В состоянии 2 мы обновляем положение, вращение и скорость питомца.
Если расстояние меньше радиуса остановки, мы будем применять коэффициент для изменения скорости в каждом кадре.
Мы используем NormalizeToRange. чтобы нормализовать эту скорость между минимальным расстоянием и stopRadius. SpeedFactor будет варьироваться от 0 до 1 в зависимости от расстояния.

Если есть минимум 5 скоростей, мы будем обновлять вращение и направление в зависимости от местоположения главного героя.

Мы всегда будем обновлять переменную Speed ​​в схеме анимации, чтобы лиса правильно смешивала анимацию бездействия/ходьбы/бега.

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

Когда питомец находится в состоянии 2, а расстояние до персонажа или эталонного актера больше, чем MinimunDistance, питомец будет продолжать корректировать свое положение и вращение.

Мы всегда вычисляем Направление следования, используя OtherActorPosition и CurrentLocation. Результирующий вектор будет нормализован, поэтому его длина равна 1, и мы отбрасываем ось Z, как мы это делали с местоположениями.

Чтобы получить ротацию обновлений, мы можем использовать DirectionToFollow.Rotation(). Мы не хотим вращать питомца в любом направлении, кроме пола. Вот почему мы отказываемся от Pitch and Roll (мы не хотим, чтобы питомец вращался в неправильном направлении!)

С помощью функции FMath::RInterpTo мы можем плавно поворачивать питомца между текущим и новым целевым поворотом, чтобы поворот не прерывался резко.

Проверьте окончательный результат!

Я надеюсь, что этот урок был полезен!

Привет, я Би, и мне нравится писать о программировании, математике, видеоиграх и объединять все вместе!

В настоящее время я работаю над новой инди-игрой под названием Witchery Academy.
Я делаю эту игру на Unreal Engine 4, и мне очень приятно поделиться некоторыми приемами и системами, которые я использую.

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

Если вам нравятся кошки, волшебники, магия и успокаивающие переживания, эта игра для вас!

Я планирую выпустить игру для ПК и Nintendo Switch!

Если вы не хотите пропускать обновления, можете подписаться на нашу рассылку:

www.witcheryacademy.com