Unreal Engine 5: Enhanced Input System

В данной статье разберем до косточек, что такое "новая" система ввода в UE5: Enhanced Input System
Настройка Enhanced Input System в Unreal Engine 5

Краткий Disclaimer:

В пятой версии Unreal Engine появилась новая система управления — Enhanced Input Sytem.
Cтарые системы привязок осей и действий (Axis and Action mappings) теперь считаются устаревшими.

Если мы зайдем в настройки проекта, то в категории Input мы увидим предупреждение об этом

Warning Axis Action Mapping Deprecated.jpg

Вместо старой системы теперь рекомендуется использовать новые Enhanced Input Actions и Input Mapping Contexts. Эти изменения предназначены для улучшения гибкости и управляемости системы ввода.

Что же это такое и как это всё понять? Давайте разбираться, что это значит и как перейти на новую систему.

Что такое Enhanced Input Actions и Input Mapping Contexts?

Enhanced Input Actions:

  • Это новый способ определения действий ввода. Он позволяет более гибко и удобно обрабатывать различные виды ввода (например, клавиатура, мышь, геймпад).
  • Enhanced Input Actions поддерживают сложные конфигурации, такие как комбинации клавиш и модификаторы.
  • Условно говоря, это настройка определенных действий (ходьба, прыжок, взаимодействие с объектами на сцене и т.д.)

Input Mapping Contexts:

  • Контексты привязок ввода позволяют организовывать и управлять различными схемами ввода.
  • Они позволяют включать и отключать определенные контексты привязок в зависимости от текущего состояния игры (например, режимы меню, игровой процесс и т.д.).
  • Грубо говоря, мы создаем определенный Context, например персонаж, который ходит по сцене, назначаем ему привязку кнопок к Action’ам, а потом создаем другой Context, где персонаж — это машина (например наш персонаж сел в машину и управляет ей) и там привязываем уже другие кнопки к другим действиям, а потом просто меняем контексты во время игры

Говоря проще, мы создаем различные Input Action’ы, которые что-либо возвращают. Привязываем эти Action’ы к конкретным кнопкам в Mapping Contexts. А дальше у персонажа уже ловим эти события и что-либо делаем.

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

Как перейти на новую систему?

Общая схема работы выглядит так:

  1. Создание Enhanced Input Actions:

    • В редакторе Unreal Engine нужно создать новые Enhanced Input Actions. Это делается через Content Browser: правой кнопкой мыши -> Input -> Enhanced Input Action.
    • Далее, следует задать имя для нового действия и настроить его параметры (например, тип ввода: цифровая ось, аналоговая ось, действие и т.д.).
  2. Создание Input Mapping Contexts:

    • Создается новый контекст привязок ввода: Content Browser -> правой кнопкой мыши -> Input -> Input Mapping Context.
    • Созданные ранее Enhanced Input Actions необходимо привязать в этот контекст и настроить привязки для различных устройств ввода (например, клавиатура, геймпад).
  3. Настройка и активация контекстов привязок ввода:

    • В классе персонажа необходимо настроить активацию контекстов привязок ввода.
    • Для этого нужно использовать систему Enhanced Input Subsystem, которая позволяет включать и отключать контексты привязок ввода.

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

Создание и настройка Enhanced Input Action

Создадим и настроим несколько Input Action для нашего персонажа. Для создания необходимо нажать правой кнопкой мыши и в контекстном меню выбрать Input -> Input Action:

Create InputAction

Создадим три Input Action: IA_Move, IA_Look, IA_Jump, которые соответственно будут отвечать за ходьбу (вперед-назад, вправо-влево), за поворот мышкой относительно персонажа и за прыжок.

IAction-jump-look-move.jpg

Откроем созданный IA_Move. Внутри мы видим множество настроек, которые первоначально могут сбивать с толку. Разберемся с ними, что они означают:

IA-details.jpg

Основные настройки Input Action

Trigger When Paused:

  • Описание: Опция, которая позволяет действию триггериться (выполняться) даже когда игра на паузе.
  • Применение: Это полезно для действий, которые должны работать независимо от состояния паузы игры, например, открытие/закрытие меню паузы. Т.е. на данный Input Action мы можем назначить кнопку (например Esc), которая будет работать независимо от того пауза сейчас в игре или нет

Reserve All Mappings:

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

Value Type:

  • Описание: Определяет тип значения, которое будет возвращаться действием.
    • Digital: Цифровой (булевый) тип, например, нажатие кнопки.
    • Axis1D: Одномерная ось, например, ось движения вперед-назад.
    • Axis2D: Двумерная ось, например, движение по плоскости X-Y.
    • Axis3D: Трехмерная ось, например, движение в пространстве XYZ.
  • Применение: Каждый Input Action что-либо возвращает (это мы увидим позже). Например — нажатие кнопки. Либо вектор, с координатами. Нужно выбрать подходящий тип значения в зависимости от типа ввода. Например, для движения вперед-назад использовать Axis1D, для движения по плоскости — Axis2D.

Triggers

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

Сразу разберем все возможные триггеры и что они означают:

  1. Chorded Action:

    • Описание: Этот триггер активируется только тогда, когда другое указанное действие также активно. Он полезен для реализации комбинации клавиш, где действие выполняется только при удерживании нескольких кнопок одновременно.
    • Пример использования: Необходимо это использовать для действий, требующих одновременного нажатия нескольких клавиш, например, бег при удержании клавиши Shift и нажатии клавиши W.
  2. Combo (Beta):

    • Описание: Этот триггер активируется при выполнении последовательности действий в определенном порядке.
    • Пример использования: Данный триггер стоит использовать для создания комбо-атак в боевых играх, где действия должны выполняться в определенном порядке для активации специального движения.
  3. Down:

    • Описание: Активируется в момент нажатия кнопки или активации оси.
    • Пример использования: Подходит для мгновенных действий, таких как стрельба или прыжок.
  4. Hold:

    • Описание: Активируется, когда кнопка удерживается в течение определенного времени. В данном триггере можно указать минимальное время удержания.
    • Пример использования: Используется для действий, требующих удержания, таких как зарядка выстрела или открытие двери. Либо, например, мы на уровне сделали шлюз, который можно открыть только если подойти к рычагу и удерживать кнопку в течении некоторого времени
  5. Hold and Release:

    • Описание: Срабатывает при отпускании кнопки после удержания её в течение определенного времени.
    • Пример использования: Подходит для действий, например, как мощный удар, который активируется только после удержания на некоторое время и отпускания кнопки.
  6. Pressed:

    • Описание: Срабатывает каждый раз при нажатии кнопки.
    • Пример использования: Используется для обычных действий, таких как стрельба, прыжок или атака.
  7. Pulse:

    • Описание: Срабатывает регулярно при удержании кнопки, через заданные интервалы времени.
    • Пример использования: Используется для автоматической стрельбы или постоянного использования способности (с заданными интервалами, которые мы сами настраиваем), пока удерживается кнопка.
  8. Released:

    • Описание: Активируется в момент отпускания кнопки.
    • Пример использования: Подходит для действий, которые должны выполняться при завершении нажатия, таких как перезарядка оружия или остановка движения.
  9. Tap:

    • Описание: Активируется при быстром нажатии и отпускании кнопки в течение короткого времени.
    • Пример использования: Подходит для коротких, быстрых действий, таких как прыжок или перекат.

Modifiers

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

Рассмотрим теперь все возможные модификаторы, которые существуют:

  1. Dead Zone:

    • Описание: Устанавливает мертвую зону для ввода, игнорируя небольшие изменения значений, которые могут быть вызваны дрожанием аналогового джойстика.
    • Применение: Полезно для аналоговых осей, чтобы избежать случайных срабатываний при малых отклонениях.
    • Пример: Для стика можно установить мертвую зону, чтобы игнорировать движения меньше 0.1.
  2. FOV Scaling:

    • Описание: Масштабирует значение ввода на основе текущего поля зрения (Field of View, FOV). Это полезно для корректировки чувствительности мыши в зависимости от FOV.
    • Применение: Удобно для игр от первого лица, где изменение FOV может повлиять на чувствительность ввода.
    • Пример: Можно изменить чувствительность поворота камеры в зависимости от текущего FOV.
  3. Negative:

    • Описание: Инвертирует значение ввода, делая положительные значения отрицательными и наоборот.
    • Применение: Используется, когда нужно инвертировать управление, например, для настройки инверсии оси Y в управлении камерой (при движении мыши)
    • Пример: Инвертирование оси Y для управления камерой. Либо инвертирование управления.
  4. Response Curve — Exponential:

    • Описание: Применяет экспоненциальную кривую к значению ввода, изменяя его отклик. Это позволяет более плавно управлять чувствительностью на разных уровнях.
    • Применение: Полезно для настройки чувствительности джойстиков и аналоговых осей.
    • Пример: Можно настроить экспоненциальную кривую для более точного управления на малых значениях и более резкого отклика на больших значениях.
  5. Response Curve — User Defined:

    • Описание: Позволяет пользователю определить свою собственную кривую отклика, изменяя, как значения ввода трансформируются в конечные значения.
    • Применение: Позволяет гибко настраивать поведение ввода для специфических нужд.
    • Пример: Можно создать свою собственную кривую для управления транспортным средством, где отклик ускорения меняется нелинейно. Данная настройка немного специфичная и пригодится далеко не всем.
  6. Scalar:

    • Описание: Масштабирует значение ввода на заданный коэффициент.
    • Применение: Используется для увеличения или уменьшения чувствительности ввода.
    • Пример: Можно удвоить скорость движения. Т.е. сделать триггер — нажатие двух кнопок (Shift + W) и установить данный модификатор, чтобы скорость движения увеличивалась.
  7. Scale by Delta Time:

    • Описание: Масштабирует значение ввода на основе времени, прошедшего с последнего кадра. Это полезно для создания значений, независимых от частоты кадров.
    • Применение: Удобно для движений, зависящих от времени, например, для создания плавного перемещения камеры.
    • Пример: Масштабирование поворота камеры на основе delta time для плавного движения.
  8. Smooth:

    • Описание: Применяет сглаживание к значению ввода, уменьшая резкие изменения и делая движение более плавным.
    • Применение: Полезно для сглаживания движений камеры или аналоговых осей.
    • Пример: Сглаживание значения ввода для плавного поворота камеры.
  9. Smooth Delta:

    • Описание: Похоже на Smooth, но применяет сглаживание с учетом delta time, что позволяет учитывать изменения частоты кадров.
    • Применение: Полезно для создания плавного ввода, зависимого от частоты кадров.
    • Пример: Сглаживание значения ввода, в зависимости от delta-time для плавного поворота камеры.
  10. Swizzle Input Axis Value:

    • Описание: Переключает значения осей ввода. Это позволяет менять местами оси X, Y, Z.
    • Применение: Удобно для случаев, когда нужно изменить направление ввода или изменить карту осей.
    • Пример: Поменять местами оси X и Y для инверсии управления. (К данному модификатору мы еще скоро вернемся)
  11. To World Space:

    • Описание: Преобразует локальные координаты ввода в мировые координаты. Это полезно для управления в пространстве игры, учитывая ориентацию камеры или персонажа.
    • Применение: Используется, когда нужно преобразовать ввод в координаты мирового пространства.
    • Пример: Преобразование ввода для перемещения персонажа в направлении камеры.

Если вы сейчас видите очень много информации — не переживайте. Когда я первый раз начал с этим всем разбираться, мне показалось, что это всё замороченно, странно и вообще зачем? Но потом я понял, насколько данная система гибкая, удобная и по сути несложная, если понять смысл. Поэтому к триггерам и модификаторам можно вернуться, уже дочитав до конца данную статью и поняв, как всё работает, на примере.
Настроим сейчас просто ходьбу персонажа. Для этого настроим наш Input Action «IA_Move» следующим образом:

Выбираем только ValueType: Axis2D (Vector2D)

Axis2D

Т.е. данный action нам должен будет возвращать две координаты — по X и Y.

Создаем и привязываем Input Mapping Context

Теперь создадим Input Mapping Context. Для этого в Content Drawer нажмем правой кнопкой мыши и выберем Input -> Input Mapping Context:

Create Input Mapping Context

Зачем вообще нужен Mapping Context? Он позволяет создать привязки ввода для различных устройств (клавиатура, мышь, контроллер и так далее). При этом, мы можем создать сколько угодно привязок клавиш и менять их по ходу игры.

Когда мы открываем созданный Mapping Context мы видим окно, где можно настроить привязки клавиш.

MC-Details.jpg

Настроим их. Добавим привязку, выберем Input Action — IA_Move и добавим четыре кнопки W, S, A, D

Mappings Context Settings

А теперь привяжем данный Mapping Context к нашему персонажу. Для этого заходим в Event Graph персонажа, добавим событие Begin Play. Привязку будем делать в момент начала игры.

Event BeginPlay

Далее нам нужно получить контроллер персонажа и сделать каст на Player Controller. Зачем так сложно? Давайте разберемся.

Что такое контроллер? Контроллер — это объект, отвечающий за управление актором. И он может быть либо PlayerController (для игрока), либо AIController (для ИИ). Например, когда персонаж загружается в игру, то ему всегда назначается контроллер, который управляет его движениями и действиями.
Player Controller — это именно контроллер игрока (не бота, не еще кого-либо на сцене, а игрока, которым мы управляем в данный момент). Данный контроллер имеет специфичные функции и свойства. Например, обработка ввода, возможна только у Player Controller’а, но невозможна в AIController’е.
Т.е. Controller — общее понятие, а Player Controller — это уже более специфичный компонент движка.

Зачем это вообще всё придумали и так усложнили?
Это всё нужно для следующих целей:

  • Различие между игроком и AI: В игре могут быть как игроки, так и AI персонажи. Каст на Player Controller позволяет определить, управляется ли данный персонаж игроком или AI, и соответственно применить правильную логику.
  • Использование специфичных функций: PlayerController имеет множество функций и свойств, которые специфичны для управления игроком, таких как обработка ввода, управление камерой и др. Эти функции недоступны в AIController.
  • Безопасность и проверка типов: Приведение типов (casting) в Unreal Engine позволяет убедиться, что мы работаем с правильным типом объекта, предотвращая ошибки и падения (crashes) в игре.

Ок, с этим разобрались, получаем контроллер, с помощью ноды «Get Controller» и кастим его в Player Controller с помощью ноды Cast to Player Controller:

Cast To Player Controller

Теперь нам нужно обратиться к новой модели ввода, которую мы настраиваем. Для этого существует нода «Get EnhancedInputLocalPlayerSubsystem».

Enhanced Input System

Данная нода позволяет связать Player Controller, Enhanced Input Actions и Mapping Context (не конкретно наши, а в общем), тем самым обеспечить работу новой системы ввода.

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

IsValid

Нода IsValid в Unreal Engine используется для проверки, является ли указатель действительным (не равен nullptr). Это помогает предотвратить ошибки выполнения, связанные с обращением к недействительным объектам.

В контексте настройки Enhanced Input в Blueprint’ах, проверка IsValid перед вызовом AddMappingContext служит для того, чтобы убедиться, что подсистема Enhanced Input была успешно получена и действительна. Это является хорошей практикой, так как обеспечивает надежность и стабильность кода.

Соответственно, если всё ок, то используем ноду Add Mapping Context для привязки конкретного Mapping Context к нашему персонажу:

AddMappingContext

Выбираем в данной ноде Mapping Context, который мы настроили ранее.

Общая настройка выглядит так:

Input Settings

Ходьба

Настроим теперь ходьбу для нашего персонажа. В Event Graph’е нашего персонажа получаем событие от Input Action: IA_Move

IA-Move.jpg

У него есть множество выходов. Разберем их подробнее:

  • Triggered
    Это событие вызывается каждый раз, когда Input Action срабатывает. Это основное событие, которое происходит, когда действие действительно происходит (например, кнопка нажата или ось движется).
    Пример: Движение персонажа при каждом изменении направления.
  • Started
    Это событие вызывается в момент начала действия. Оно происходит один раз, когда Input Action начинает срабатывать (например, кнопка впервые нажата).
    Пример: Воспроизведение анимации начала прыжка.
  • Ongoing
    Это событие вызывается, пока действие продолжается. Оно полезно для отслеживания действий, которые происходят на протяжении некоторого времени (например, удержание кнопки или перемещение джойстика).
    Пример: Плавное движение камеры, пока джойстик перемещается.
  • Canceled
    Это событие вызывается, когда действие отменяется. Оно происходит, если Input Action прекращается не завершившись (например, кнопка была нажата, но не отпущена, а действие было отменено по какой-либо причине).
    Пример: Остановить перезарядку, если кнопка отпущена раньше времени.
  • Completed
    Это событие вызывается, когда действие завершается. Оно происходит после того, как Input Action полностью выполняется (например, кнопка нажата и затем отпущена).
    Пример: Анимация завершения прыжка после того, как персонаж приземлился.
  • Action Value
    Это выходное значение, которое возвращает текущий входной вектор или значение действия. Например, для движения это может быть вектор направления, а для кнопки — булево значение (нажата/не нажата).
    Пример: Использование значения для перемещения персонажа в нужном направлении.
  • Elapsed Seconds
    Это выходное значение показывает, сколько времени прошло с момента начала действия. Полезно для отслеживания продолжительности действия (например, сколько секунд удерживается кнопка).
    Пример: Проверка, сколько секунд удерживается кнопка спринта.
  • Triggered Seconds
    Это выходное значение показывает время, когда действие было запущено. Полезно для понимания временных меток и отслеживания последовательности действий.
    Пример: Логирование времени начала каждого прыжка персонажа.
  • Input Action
    Описание: Это само Input Action, которое вызвало событие. Полезно для определения, какое действие вызвало событие, если один обработчик используется для нескольких действий.
    Пример: Определение, какое именно действие вызвало этот вызов, если используются общие обработчики.

Понимаем, что в нашем случае нам необходимо использовать событие Triggered (когда мы держим кнопку, мы идём) и выходное значение Action Value.
Разделим данное значение на координаты и выведем на экран, что происходит при нажатии кнопок:

IA-Move-Print.jpg

IA-Move-CoordXY.jpg

При нажатии любой кнопки (W, A, S, D) у нас на экран выводится x: 1 y: 0. Т.е. по дефолту событие Input Action с типом Axis2D — возвращает x = 1 и y = 0.
Соответственно мы сами должны настроить значения по осям, которые будут соответствовать передвижению.

Предположим, что у нас ось Y смотрит вперед, а ось X смотрит вправо от оси Y

EIS-Axis.jpg

Давайте сделаем (как в шаблоне Third Person от самого Unreal), чтобы при нажатии каждой кнопки, мы получали такие значения по x и y:

  • W (x: 0, y: 1) — движение вперед, т.е. скольжение оси вдоль Y
  • S (x:0, y: -1) — движение назад, т.е. скольжение оси вдоль Y — в отрицательную сторону
  • A (x: -1; y: 0) — движение влево, т.е. скольжение оси вдоль X — в отрицательную сторону
  • D (x: 1; y: 0) — движение вправо, т.е. скольжение оси вдоль X

Для этого нам достаточно настроить модификаторы в Mapping Context (именно там, т.к. на каждую кнопку идет свой модификатор, а Input Action у нас один — IA_Move):

Для кнопки W мы меняем оси местами. Первой идёт Y, затем X, затем Z:

MC-SwizzleInputAxisValue.jpg

Теперь при нажатии кнопки W, мы будем получать x:0, y: 1. Проверим это:

EIS-X0Y1.jpg

Для кнопки S мы делаем тоже самое, но используем модификатор Negative:

MC-S-SwizzleInput.jpg

Проверяем:

EIS-X0Y_1.jpg

Теперь настраиваем кнопки A и D:

EIS-WalkRightLeft.jpg

Т.е. A мы просто разворачиваем, а D оставляем по дефолту.

В итоге при нажатии на A мы получаем координаты x: -1 y: -0:

EIS-X1-Y0.jpg

А при нажатии на D:

EIS-X1Y0.jpg

Всё, нужные координаты мы теперь получаем при нажатии каждой кнопки. Вопрос в том, что с ними делать.

Для перемещения нам нужно использовать ноду: Add Movement Input

Add-Movement-Input

В нее необходимо передать направление, в котором персонаж должен двигаться и величину. Если задаем 1, то персонаж двигается в указанном направлении, если -1, то направление инвертируется.

Осталось дело за малым — определиться с направлением движения.

Направление персонажа мы можем получить из его контроллера.

Controller представляет собой специальный объект, который управляет входом от игрока (т.е. от нас с вами) и управляет поведением персонажа или другого актора в игре. Контроллер действует как посредник между игроком и объектом, который он управляет.

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

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

Разберем подробнее, как работает синхронизация между контроллером и персонажем:

  1. Инициализация контроллера и персонажа:

    • При запуске игры или когда персонаж появляется на сцене, контроллер привязывается к персонажу. Это означает, что контроллер будет управлять персонажем, и все действия контроллера будут применяться к персонажу.
  2. Контроллер и поворот персонажа:

    • Controller Rotation: При использовании ноды Get Control Rotation, мы получаем текущий угол поворота контроллера. Этот угол определяет, в каком направлении смотрит контроллер, и, следовательно, в каком направлении будет двигаться персонаж.
    • Персонаж: Поворот персонажа при запуске игры будет соответствовать углу поворота контроллера. То есть, если контроллер повёрнут на 90 градусов вправо, то персонаж также будет ориентирован на 90 градусов вправо относительно его начального положения.
  3. Синхронизация:

    • Синхронизация при запуске: В момент инициализации, когда игра запускается или персонаж появляется, контроллер и персонаж инициализируются таким образом, что направление взгляда и ориентация персонажа синхронизируются с контроллером.
    • Получение Rotation: Если получить углы поворота контроллера в любой момент времени, они будут совпадать с направлением, в котором персонаж смотрит, так как контроллер управляет этим направлением.

Другими словами, когда мы запускаем игру и на сцену спавнится персонаж, то направление контроллера в точности совпадает с тем, куда у нас смотрит камера.

UE5 ControllerView

Собственно, это нам и нужно. Реализуем теперь движение вперед и назад. Для этого мы должны получить куда направлен контроллер (его поворот), затем получить из данного поворота Forward-вектор (т.е. вектор по прямой, относительно текущего поворота по оси Z (Yaw)) и отправить в ноду Add Movement Input:

UE5 GetForwardVector

Почему именно так? Потому что нам неважно как и куда повернут персонаж вдоль осей X и Y. Нам нужно обеспечить его движение вперед и назад. А для этого мы должны понять — куда смотрит персонаж, относительно оси Z. Иначе говоря, в каком направлении он повернут на сцене.

Также мы используем Action Value только по Y, т.к. ранее мы условились, что движение вперед и назад — это скольжение вдоль оси Y (ось Y смотрит прямо, ось X смотрит направо).

Теперь при запуске игры персонаж ходит вперед и назад. Если он ходит назад спиной, то необходимо поставить галочку «Orient Rotation to Movement» в компоненте Character Movement. Тогда движок будет сам его разворачивать по направлению движения.

EIS-Orient-Rotation-To-Movement.jpg

Для визуализации данного направления, можно вывести Debug Line в Event Tick:

EIS-Debug-Rotation.jpg

Мы берем данный вектор направления, умножаем на 500 (т.к. Get Forward Vector — это единичный вектор, значит мы его просто не увидим, поэтому удлиняем его) и выводим его из текущей позиции персонажа на сцене:

При старте сцены контроллер (и персонаж) ориентированы смотреть вперед. Мы видим, что красная линия смотрит строго вперед:

EIS-ForwardVector.jpg

Теперь повернем камеру на 90 градусов влево:

EIS-ForwardVector-Left.jpg

Наша красная линия повернулась также влево на 90 градусов. Теперь если мы нажмем кнопку «Вперед», то персонаж пойдет вдоль данной красной линии, а т.к. мы включили поворот персонажа по ходу движения, то он повернется в эту сторону.

EIS-RotateCharacterToFV.jpg

Если добавить еще получение вектора направления по Pitch, то у нас вектор направления будет ориентирован еще на то, куда мы смотрим — вверх или вниз:

EIS-AddPitch.jpg

Например, установим позицию контроллера таким образом:

EIS-ControllerViewPitch.jpg

Вылетим из персонажа и посмотрим куда смотрит вектор:

EIS-ForwardVectorUp.jpg

Вектор смотрит вперед и наверх.
Но т.к. нам неважно куда смотрит персонаж — наверх или вниз и нам в любом случае нужно двигаться вперед, то мы игнорируем вращение контроллера вдоль оси Y. Поэтому берем только значение Z (Yaw).

Теперь сделаем движение вправо-влево. Для этого мы опять берем Get Control Rotation, но из него получаем Get Right Vector, т.е. вектор, перпендикулярный направлению, куда смотрит наш персонаж. Опять используем ноду Add Movement Input, но туда уже передаем в Scale Value — полученное значение из Action Value для X:

UE5 GetRightVector

UE5 Character Movement

Готово, теперь при запуске игры персонаж бегает вперед-назад и вправо-влево, причем автоматически разворачиваясь в нужную сторону.

Визуализируем Vector Right зеленым цветом:

EIS-DebugRightVector.jpg

Как видим, он строго перпендикулярен ForwarVector:

EIS-Perpendicular-Vectors.jpg

Управление мышью

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

Для этого в IA_Look в ValueType просто устанавливаем Axis2D:

IA-Look-Axis2D.jpg

В ContextMapping добавляем обработку движений мышкой:

IA-Look-MouseLook-Negative.jpg

Выбираем обработку движения Mouse XY — т.е. движения по осям X и Y мышкой и модификатор — отразить наоборот:

IA-Look-Negative-Modifier.jpg

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

Теперь выведем в сообщения, что происходит при данном событии:

IA_Look-Debug.jpg

Провожу мышкой влево и получаю следующие координаты (по y должно быть 0, но т.к. я все равно немного дергаю ее наверх, то там не всегда нулевая координата):

IA_Look-Debug-GoLeft.jpg

Теперь веду вправо:

IA_Look-Debug-GoRight.jpg

Теперь наверх:

IA_Look-Debug-GoUp.jpg

И соответственно вниз:

IA_Look-Debug-GoDown.jpg

Какой можно сделать из этого вывод:

  • Когда ведем мышку влево, то получаем координаты вида (-1, 0) — т.е. меняется только X, при этом чем быстрее двигаю мышь, тем больше цифра
  • Когда двигаем мышку вправо, получаем координаты вида (1, 0)
  • Когда двигаем наверх, то координаты вида (0, -1)
  • Вниз — (0, 1)

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

UE5 Mouse View Around

Нода «Add Controller Yaw Input» — позволяет изменить координаты того, куда смотрит контроллер по Z-оси (т.е. поворачивать его направо или налево)
Нода «Add Controller Pitch Input» — позволяет изменить координаты контроллера по Y-оси (вверх или вниз)

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

Запускаем игру и видим, что теперь мы можем спокойно вращаться камерой вокруг игрока:

IA_Look-Around-Character.jpg

Реализация прыжка

Теперь реализуем прыжок персонажем. Для этого в IA_Jump пропишем нужное действие:

IA_Jump_Value.jpg

Здесь нам нужно только получать значение — нажата кнопка или нет, поэтому возвращать данный Input Action должен только true или false.

Теперь привяжем данный Input Action к пробелу через Mapping Context:

MC-IA_Jump.jpg

Видим, что значение, возвращаемое событием имеет тип Boolean:

IA_Jump-ActionValue.jpg

Выведем его на экран. Если мы также привяжемся к Triggered, то при нажатии на пробел нам будет выводиться значение «true» всё время, что мы держим пробел:

IA_Jump-Debug.jpg

IA_Jump-DebugView.jpg

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

Вспомним еще раз:

  • Started — вызывается в момент начала действия и происходит один раз, когда срабатывает Input Action
  • Completed — вызывается, когда действие завершается (например, когда отпущена кнопка)

У Character’а есть методы: Jump и Stop Jumping. Привяжем данные события к Input Action:

StartJumping-StopJumping.jpg

UE5 Jump Character

Запускаем игру. Теперь при нажатии пробела персонаж прыгает, если нажать пробел и держать, то прыгает один раз. Если отпустить пробел и нажать еще раз — персонаж прыгает еще раз:

IA_Jump-Character.jpg

Открытие двери с таймаутом

Итак, мы реализовали все базовые движения персонажа — ходьба, прыжок, управление камерой.

Реализуем теперь какую-либо интересную логику. Например, у меня на сцене есть дверь с триггер-боксом. Когда в данный бокс входит персонаж, то дверь сразу же открывается.
Сделаем, например, так, чтобы, когда персонаж заходил в триггер-бокс, то для открытия двери необходимо нажать кнопку E на 4 секунды и продержать данное время. Но если отпустить кнопку раньше времени, то дверь должна оставаться закрытой.

Сделаем InputAction IA_OpenTheDoor

IA_OpenTheDoor.jpg

Пропишем там Value Type = Digital, укажем триггер Hold и установим время 4 секунды

IA_OpenTheDoor-Settings.jpg

Далее, в Mapping Context привяжем данный IA к кнопке E:

IA_OpenTheDoor_MC.jpg

И у персонажа добавим обработку Event’а:

IA_OpenTheDoor-OpenTheDoor.jpg

При нажатии кнопки E — данное событие вызовется. Если мы держим кнопку 4 секунды, то сработает Triggered, и тогда мы вызываем функцию Open The Door, которая открывает дверь.
Все время, пока мы держим кнопку E (начиная с самой первой секунды), мы выводим на экран сколько прошло времени.

Проверим это:

Персонаж заходит в триггер, ему выводится надпись, что он может открыть дверь (это уже реализовано в BluePrint’е у бокса):

BoxOverlap.jpg

Нажимаем кнопку E, пошел отсчет:

Start-Counter.jpg

Отпускаем кнопку E — отсчет прекращается

Stop-Counter.jpg

Теперь продержим кнопку 4 секунды:

Open the door

Дверь открылась при достижении данного времени. При этом счетчик остановился на значении 3.991591. Если мы продолжаем удерживать нажатой кнопку E уже после открытия двери, то ничего не происходит, т.к. уже сработало событие Triggered. (однако, счетчик запустится повторно, если опять зажать кнопку E)

Итоги

В заключении, могу сказать, что Enhanced Input System в Unreal Engine 5 — это очень удобный и настраиваемый инструмент, который помогает очень сильно облегчить настройку управления персонажем.
Проблема здесь только лишь в том, что необходимо понять, как это всё работает, что означают всякие триггеры, модификаторы и мэппинги.
Но если научиться, настроить и понять, то у нас в руках оказывается очень полезный инструмент, который работает прямо из движка, без необходимости установки дополнительных плагинов. И я очень надеюсь, что данная статья хотя бы кому-то поможет пролить свет на то, как это всё работает.

Успехов и удачи в GameDev!

Понравилась статья? Поделиться с друзьями:
Kostegs.Name
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: