Михаил Ли

Михаил Ли 

Художник-Мультипликатор

64subscribers

204posts

goals1
$16.09 of $1 688 raised
На Azure Kinect

Unreal Engine - Разработка ч.45 - Продвинутое управление (Enhanced Inputs) - Конвертируем проект ч.2

Продолжаем!
Мы остановились на моменте когда связали EIS и инпут через BP - удаляем всё что понаделали и заходим в VS чтобы провести ревизию старого кода:

По старому мы сначала вызывали функцию которая принимает float для того чтобы позже добавить её в AxisMapping. Чтобы сделать то что нам нужно мы будем следовать флоу документации. Для начала создав переменную которая будет указателем на IMC:

Сейчас она будет подсвечена красным так как мы ещё не добавили кое чего в #include, поэтому пока что мы просто используем предварительное объявление класса и позже добавим то что нам нужно:
Я хочу чтобы этот контекст был доступен из под BP поэтому сделаю его доступным с помощью макроса UPROPERTY:

Я поставил флаги так чтобы мы могли редактировать значение из под BP, и  могли читать значение из евентграф (но не редактировать), а так же  назначил категорию Input.Теперь мы можем добавить наш контекст точно в таком же порядке как мы это сделали в BP:

Сначала нам нужно будет получить контроллер, потом сделать в плеер контроллер, вызвать EILPS и добавить контекст подав в него значение нашего контекста и приоритет. Давайте сделаем это.Мы это сделаем так же BeginPlay как и в BP. В .cpp файле идем в BeginPlay и первое что мы можем сделать это получить контроллер:

Для начала я создам переменную которая будет хранить в себе значение контроллера. Она будет указателем типа APlayerController, далее я присвоил ей имя и значение равное касту значения в тип APlayerController с использованием шаблона функции для каста в котором мы вызываем функцию GetController(). По большому счёты мы могли бы написать и просто Controller вместо GetController и были бы правы так как переменная Controller, все ещё доступна в паблик секции класса которому принадлежит, но тенденция такова что эпики завозят всё больше и больше функций чтобы получать значение а прямой доступ к переменным пропадает так как они их  переносят в protected секцию.

Каст это приведение на С++ терминологии. Если вы не знаете что это такое, или подзабыли, почитайте тут.

Далее, если это приведение будет успешным мы получим валидный указатель на контроллер который мы можем использовать для того чтобы подать его в EILPS.
По хорошему надо проверять успешен ли каст или нет. Эпики в своём
темплейт проекте показывают как можно организовать проверку так чтобы не плодить лишние переменные и избавляться от них сразу после того как они себя отработали:
Начиная использовать оператор if, мы создаем зону видимости, покидая которую переменные сразу исчезают из "скоупа". Это удобно и оптимально.

Теперь нам нужно подать значение переменной PlayerController в EILPS:

Для начала, как и раньше я создам указатель типа UEnhancedInputLocalPlayerSubsystem присвою ему имя и значение равное вызову шаблона функции класса ULocalPlayer::GetSubsystem в который мы подадим тип UEnhancedInputLocalPlayerSubsystem и значение нашего контроллера. Звучит как какое то заклинание, но на самом деле мы делаем то же самое что и в BP т.е следуем инструкции. Пока что UEnhancedInputLocalPlayerSubsystem подкаршена как ошибка - всё верно я ещё не добавил нужный мне #include. Мы можем решить эту проблему путём предварительного объявление этого класса в .h чтобы избавиться от ошибки:

Так же нам, наконец, нужно добавить в .cpp нужный нам #include. Нужный на #include звучит так и чтобы отрыть его в документации нужно пройти целый круг ада:

Его мы и добавим в наш .cpp файл. В нём будет содержаться оба класса которые мы предварительно объявили.
Теперь нам осталось лишь указать IMC и его приоритет:

Сделаем мы это с помощью доступа к переменной Subsystem и вызова функции AddMappingContext с последующей подачей нашей переменной-указателя контекста. Важно! До этого мы создали просто указатель для переменной PaarotMappingContext, то есть по сути она сейчас является "висячим" указателем. Поэтому нам нужно будет указать её значение из под BP:

И тогда наш указатель будет показывать на что то то а не торчать в пустоте.
Теперь осталось добавить какую то функцию к IA_Move чтобы окончательно связать ввод и логику. В БП это сделать проще так как эвент для IA_Move генерируется автоматически, в случае с С++ - нужно будет сделать чуть чуть по другому.

IA
- в UEшном С++ имеет свой собственный тип данных UInputAction, и мы можем, как и раньше создать указатель на этот тип данных. Делать мы это будем в protected части нашего .h файла:
Я создал переменную и так же как и контекст добавил её для работы в БП. Теперь нам нужно создать эвент. Он в С++ делается мануально в отличии от БП:
На самом деле мы создаем не эвент а функцию, которая будет принимать в себя значение адреса типа FInputActionValue. После в .cpp мы можем уже полностью описать нашу функцию-эвент:

Вверху лежат остатки старого способа делания того же самого. Кстати нужно не забыть добавить предварительную декларацию UInputAction так как наш .h всё ещё не знает что это за класс такой:

Так же нам нужно сделать что то с FInputActionValue, наш .h файл так же не знает что это такое:

У этого типа данных - тип struct. Этот тип данных обычно очень маленький и делать прямой #include его заголовочного - обычно безопасно. К слову в дефолтом проекте от эпиков, где они демонстрируют EIS, сделано ровно то же самое:

#include "InputActionValue.h" я поставил выше #include "Parrot.generated.h", если первое будет ниже второго - ничего не заработает.

К слову если вы не понимаете почему я так заворачиваюсь с #include и предварительным объявлением - почитайте предыдущий материал, этот момент на самом деле важный.
Теперь нам нужно как то получить ввода и что то с ним сделать:
Возвращаемся в наш .cpp файл и работаем с FInputActionValue:
Подаваемая в функцию перемененная Value имеет тип данных FInputActionValue, поэтому законно будет получить доступ к этому enumчерез . оператор, в нём мы можем выбрать шаблон для функции Get в который мы можем подать любой нужный нам тип данных IA. Мы знаем что наш IA_Move
- это bool и поэтому мы подаем в шаблон bool. Само собой законно будет
создать переменную из этого запроса и привязать какую то логику. Я
сделал логику вывода на экран.

Осталось последнее сделать наконец то связку между логикой и инпутом. Она делается ровно так же как и "по старому" но с ипользованием EIS:

Как и остальные компоненты UEnhancedInputComponent имеет свой .h файл который нужно добавить в .cpp чтобы с ним работать:

Я использую тот же трюк что и раньше для того чтобы не плодить лишних переменных делая каст CastChecked,UEnhancedInputComponent на PlayerInputComponent. Хоть мы уже знаем что UEnhancedInputComponent наследуется от PlayerInputComponent и "обратно совместим" этот каст нужен для того чтобы система работала а CastChecked это особенный вид шаблона функции который в случае неудачного каста крашнет нам проект. В данном случае это хорошо, так как мы точно не хотим чтобы игра работала скастив контроллер черти куда.

Далее я получаю доступ через -> оператор к функции BindAction которая требует различных типов данных. Первым что она потребует это переменную IA:
Далее функция запрашивает тип эвента активации:
ETriggerEvent это enum и если мы получим доступ к его содержимому
через :: мы сможем выбрать нужный нам вариант активации - в нашем случае это Triggered:
Далее нам нужно уточнить а на каком UObject эта активация будет происходить, тут мы пишем this так как будем использовать на нашем pawn:

И последним будет функция которую мы хотим исполнить, в нашем случае это будет Move. Её нам нужно подать через адрес оператора с полным описанием:
Компилим проект хот релодом. Осталось только выбрать в BP нашего Pawn нужный нам IA для того чтобы наш ранее созданный указатель на IA куда то показывал:
Нажимаем плей - смотрим результат в логе:
Как видим текст выводится. А значение равно нулю так как я скопипастил из строчку из "старого" кода:
А так как это буль - мы значения не получаем поэтому и ноль. Поздравляю.
Subscription levels2
Subscription Spots Are Limited

Малая открывашка

$14.1 per month
Дает доступ ко всему контенту, но дешевле

Большая открывашка

$28.2 per month
Открывает доступ к блогу и всем его постам + помощь в решении ваших задач пару раз в месяц
Go up