Why do my Input Actions not translate to my charactor actor movement code?

I have a blank UE5.4 project where i created a basic scene and a ACharacter actor class (C++) and a Blueprint class derived from it. Initially, I tried to create the setup from scratch myself but the character didnt move in PIE. So I ended up literally just replicating what the ThirdPerson Template does, and I have the exact same problem still. The charact appears in game, and I seem to be in possession of it because I get it’s third person camera view, but it doesnt move despite the showdebug EnhancedInput command showing that the inputs are being fired according to my Input Actions. Here is the deal:

  • I have a ACharacter actor class which defines a capsule component as the RootComponent, a CameraBoom and a FollowCamera, sets up CharacterMovement and implements the necessary methods for binding and handling input (exactly as the C++ source code in the ThirdPerson template).
#include "Characters/PlayerCharacter.h"
#include "Engine/LocalPlayer.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/Controller.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputActionValue.h"
#include "InputMappingContext.h"

DEFINE_LOG_CATEGORY(LogPlayerCharacter);

APlayerCharacter::APlayerCharacter()
{
	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
		
	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 700.f;
	GetCharacterMovement()->AirControl = 0.35f;
	GetCharacterMovement()->MaxWalkSpeed = 500.f;
	GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
	GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
	GetCharacterMovement()->BrakingDecelerationFalling = 1500.0f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
	AutoPossessPlayer = EAutoReceiveInput::Player0;
}

void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	UE_LOG(LogTemp, Warning, TEXT("SetupPlayerInputComponent called for %s"), *GetName());

	// Add Input Mapping Context
	if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(DefaultMappingContext, 0);
			UE_LOG(LogTemp, Warning, TEXT("Mapping Context added: %s"), *DefaultMappingContext->GetName());
		}
		else
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to add Mapping Context for %s"), *GetName());
		}
	}
	
	// Set up action bindings
	if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
		
		// Jumping
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);

		// Moving
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Move);

		// Looking
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Look);
	}
	else
	{
		UE_LOG(LogPlayerCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));
	}
}

void APlayerCharacter::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogTemp, Warning, TEXT("C++ BeginPlay called for %s"), *GetName());

}

void APlayerCharacter::Move(const FInputActionValue& Value)
{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("MOVE FIRING"));
	UE_LOG(LogTemp, Warning, TEXT("MOVE FIRING"));

	// input is a Vector2D
	FVector2D MovementVector = Value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	
		// get right vector 
		const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

		// add movement 
		AddMovementInput(ForwardDirection, MovementVector.Y);
		AddMovementInput(RightDirection, MovementVector.X);
	}
}

void APlayerCharacter::Look(const FInputActionValue& Value)
{
	// input is a Vector2D
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		// add yaw and pitch input to controller
		AddControllerYawInput(LookAxisVector.X);
		AddControllerPitchInput(LookAxisVector.Y);
	}
}
  • Next, I created Input Actions and an Input Mapping Context (both exactly as in the ThirdPerson template)
  • Next, I mapped that InputMappingContext in my character Blueprint as the “Default Mapping Context”
  • I even tried setting Auto Possession to Player0, but that didn’t make a difference. There is no other Pawns or Characters in the scene.
  • I am not overwriting the behaviour or input mapping in the character blueprint. Its all set up in C++. The Character BP Event Graph is empty. In the Details Panel for the corresponding components, the mappings and default values all appear as set in the C++ code.

When I drag my Character BP in the scene for an instance of it in the game, it appears, and when i hit PIE i have its camera third person view, but cant move despite my input actions being registered as shown by the EnhancedInput debug command. The debug log shows that my constructor, SetupPlayerInputComponent and BeginPlay method is called and that the InputMappingContext was successfully added, BUT the logs in the Move methods etc. do not appear when I press the corresponding keys (e.g. WASD).

LogTemp: Warning: SetupPlayerInputComponent called for BP_PlayerCharacter_C_0

LogTemp: Warning: Mapping Context added: IMC_Default

LogTemp: Warning: SetupPlayerInputComponent called for BP_PlayerCharacter_C_0

LogTemp: Warning: Mapping Context added: IMC_Default

LogTemp: Warning: C++ BeginPlay called for BP_PlayerCharacter_C_0

So my C++ methods are not being executed when the Input Actions register. Why? Also, I don’t know why the setup method seems to be called twice.

Hello,

Maybe you forget to assign input actions in character blueprint ?

you still need to add the mapping somewhere other than SetupInput

//Add Input Mapping Context
if (UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
	InputSubsystem->AddMappingContext(DefaultMappingContext, 0);
}

I do it in BeginPlay I believe the Sample projects also do it in BeginPlay

Thanks for the response, but unfortunately those seem to be mapped already in my character blueprint.

Thank you for your response. The input mapping context is being mapped in the SetupPlayerInputComponent function:

// Add Input Mapping Context
	if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(DefaultMappingContext, 0);
			UE_LOG(LogTemp, Warning, TEXT("Mapping Context added: %s"), *DefaultMappingContext->GetName());
		}
		else
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to add Mapping Context for %s"), *GetName());
		}
	}

This is how it was done in a freshly created 5.4 ThirdPerson C++ Template project (minus the LOG messages, which I added for debugging purposes).