How-to for UE5.1, Enhanced Input System

Hi!

I am by no means an expert, so I’m sure there are improvements to be made to this, but I figured out one way to get it going with the Enhanced input system (as the old one is deprecated now).
I got the gist of it from here.

Here’s a step-by-step of how I did it:

  1. I started by deleting all the action and axis mappings that were already in Project Settings->Input, just to have a clean slate for the Enhanced input system.

  2. Add “EnhancedInput” to The PublicDependencyModuleNames.AddRange in ToonTanks.Build.cs, so you end up with something like PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput" });.

  3. Set up Input Mapping Context and Input Actions in the Unreal Editor. I made a folder called Input under Content in the Content Browser. Right-click in the content browser, select Input->Input Mapping Context to create a new one.
    image
    I named mine IMC_PlayerInput.
    To create the Input Actions, select Input->Input Action after right-clicking.
    My folder contents now look like this:
    image
    One Input Action for each action that Stephen has.
    Opening the Input Actions, one can set their Value Types. Axis1D (float) gives the equivalent of an Axis mapping, and Digital (bool) gies an Action mapping, in the old system terms. Two examples:



    The button mappings are set in the Input mapping Context;

    Note the Negate modifier on the S and A keys, as we want them to give a value of -1.

  4. We want our Tank C++ class to have acess to all of these. One way to do this is to make varaibles with UPROPERTY, that we can then input in the blueprint. Something like this:

	//Setting up inputs. Mapping context and Input Action variables, to be set in Blueprint
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Enhanced Input", meta = (AllowPrivateAccess = "true"))
    class UInputMappingContext * inputMapping;
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Enhanced Input", meta = (AllowPrivateAccess = "true"))
	class UInputAction * inputMoveForward;
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Enhanced Input", meta = (AllowPrivateAccess = "true"))
	class UInputAction * inputTurn;
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Enhanced Input", meta = (AllowPrivateAccess = "true"))
	class UInputAction * inputRotateTurret;
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Enhanced Input", meta = (AllowPrivateAccess = "true"))
	class UInputAction * inputFire;

I do forward declarations to keep things tidy, as suggested in the course. These are somewhat dangling pointers however, which I’m uncomfortable with, but hey ho… One could do nullptr checks later, if one fancies.

  1. Compile! Then we can add our input mapping context and input actions in our blueprint. As I gave them a tag, it’s easy to find in the Details panel;


    These start out saying None, but you can find your nice Input Actions in the dropdown lists.

  2. Now back to the code. Time for our ATank::SetupPlayerInputComponent, where we have to do things a little differently;

// Called to bind functionality to input
void ATank::SetupPlayerInputComponent(UInputComponent * PlayerInputComponent) {
	Super::SetupPlayerInputComponent(PlayerInputComponent); //Call the parent version

	// Get the player controller
    auto playerController = Cast<APlayerController>(GetController());
 
    // Get the local player enhanced input subsystem
    auto eiSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(playerController->GetLocalPlayer());
    //Add the input mapping context
    eiSubsystem->AddMappingContext(inputMapping, 0);
 
    // Get the EnhancedInputComponent
    auto playerEIcomponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);

	//Bind Move() to the mapping
	//BindAction for enhanced system takes Action, ETriggerEvent, object, and function
	//ETriggerEvent is an enum, where Triggered means "button is held down".
	playerEIcomponent->BindAction(inputMoveForward, ETriggerEvent::Triggered, this, &ATank::Move);
}

We have to get the UEnhancedInputLocalPlayerSubsystem, and then add our Input Mapping Context to it. This makes the mapping context active.
Then we want to cast the PlayerInputComponent to a UEnhancedInputComponent. Using this after the cast (in my case under the variable name playerEIcomponent), we can call BindAction(), which is like what BindAxis was in the old system, but more general.
You can read more about the ETriggerEvent options that are now needed here. The rest is very similar to what’s in the video.
We also have to add some includes, to get this compiling:

#include "InputMappingContext.h"
#include "InputAction.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
  1. Since things are more general, we also have to edit our Move() function. The argument is now not a float, but an FInputActionValue. I did it like this, in Tank.h:
void Move(const FInputActionValue & Value);

Note that we here need to add an extra include: #include "InputActionValue.h"
And in Tank.cpp:

void ATank::Move(const FInputActionValue & Value) {
	//To bind to axis mapping: SetupPlayerInputComponent
	UE_LOG(LogTemp, Display, TEXT("Float value: %f"), Value.Get<float>());
}

Note that Value is more general now, so we have to use Value.Get<float>() to get the axis value out. The reason for this being a templated function is that we might have a bool instead, for an “Action mapping” (i.e. Digital (bool) in the new system), or an FVector2D if we do an Axis2D input action type, for example.

And with that, we’re caught up with the end of this video, using the Enhanced Input system!
image
The values change between 1 and -1, dependent on if I hold down W or S.
So, things seem to work! Hopefully there won’t be any big surprises coming up concerning the input, and then this should work for all our buttons, just using Value.Get() with the right type for the functions we call.

Kind regards,
Håkan

11 Likes

Thanks for your detail post. It is very well explained.
For those who like videos, there are also those mentioned in the previous chapter. This youtube playlist from Druid Mechanics (alias Stephen, alias Steve if I understood it well xD) contains 5 videos specifically on enhanced inputs and C++. They are really good.
But then again, your post explain it all very well, thanks :slight_smile:

1 Like

Hey there guys,

Great post but an important caveat - the current input system is being deprecated - it’s still entirely functional in UE5.1; and following the course should still work.

If you fear that EnhancedInput might interfere with your project you can turn it off under Edit>Plugins. There’s also legacy controller support inside it.

I found in respect to this course, these are great opportunities for extending learning; but if one is struggling or keeping pace, diverting off the course material can lead you to getting hopelessly lost; and this can be a bit of a gameender for some students. You don’t want to find yourself in a situation where you don’t know whether an error lies in your code from the coursework; the extension, or some fundamental imcompatibility between then.

As I understand it there are still some issues with EI and as it’s not fully deprecated, the standard input schema works fine. I think the key themes from this project are about setting up a controller then being able to grab the handle for it from functions in the various subclasses.

Not to detract from a great post by the OP, I’m on my second pass of the course and this great stuff - but to learners who are worried that they may have to do this because of the deprecated warning, you do not have to migrate to EnhancedInput as of 5.1 anyways. I know when I started out this kind of thing would stress me to no end.

Thanks to OP for the great write up - I was already starting to plan how to tackle migrating this; excellent work. :slight_smile:

1 Like

Hi!

Indeed, one can still use the old system, I just did this as an exercise for myself in learning the new system :slight_smile:
And since I found a way, I figured I’d post it for others as well, if they were curious. Having reached the end of this section now, I can also safely say that this carried me the whole way through, and there were no surprises coming up regarding input.

As a dicussion of semantics, the current system is deprecated. However, deprecated (in a programming context) normally means that features still work, but are not guraranteed to work in future updates. But, as you say, the old way is still fully functional in UE5.1, making it easy to follow along in the course using this version. And indeed, the point of this project is sort of unrelated to the finer points of the input system! So, no stress, one can just ignore the “deprecated” warning if you use 5.1

Thanks for this post! It helped me figure out what I was doing wrong.

One thing to add, if you want the delegate function to get called when the trigger is released, make sure to bind it to ETriggerEvent::Completed. So my binding looks like this:

		UE_LOG(LogTemp, Warning, TEXT("AGoKart::SetupPlayerInputComponent Binding Actions"));
		EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Triggered, this, &AGoKart::UpdateThrottle);
		EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Completed, this, &AGoKart::UpdateThrottle);
2 Likes

Thank you for this great informative post

Thanks for your great information its really straight forward but I have some questions:

  1. Why you declared the input actions in the character class while they already assigned in IMC, is it good to only declare IMC to safe your self from updating them manually if you add new input actions?
  2. Using Axis1D for movement lose the gain of using Axis2D in EIS which give you a benefit for using Gamepad (eg. left thumb stick). its only use modifiers to swizzle xyz axis to yxz for (W & S) .
  3. check for the pointer is it a fancy thing or default practice to safe game from get crashes.

Because I need to know what is the good practices for EIS

Great work on this! You saved me a few days wandering aimlessly through tutorial videos and documentation.

I tried using the Enhanced Input System but it didn’t work unless you have a movement component attached to the pawn. At this point, I am stuck and still researching about the movement component.

Privacy & Terms