1

I'm using the Enhanced Input system for an Unreal Engine 5.1.1 first person shooter project.

The input mapping context Move input action

Unlike the recently depreciated old input system, holding down two opposite directional keys (e.g. keyboard [W] and [S]) will not cancel each other out, rather the last listed key set up in the Input Mapping Context will take priority and move the character in that direction - in this case the character moves backwards when [W] and [S] are held at the same time.

showdebug enhancedinput

Is there a way for multiple key presses for the same Input Action to be processed before it returns a value for use in code? Essentially, I want the FVector2D value to be (0, 0) when all four directional keys are pressed and should cancel each other out.

I tried adding values on top of each other for each call of the move callback, however this doesn't seems to work as the callback only seems to be called once for the last listed key as mentioned earlier.

What is especially strange is that the returned FVector2D contains axial values in both X ([W] & [S]) and Y ([A] & [D]) so multiple keys are clearly being processed, yet for the same axis it seems like the last listed key overwrites the value.

...
// Called every frame
void AShooterCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    // Handle movement:
    
    // Prevent speed increase on diagonals
    CurrentMovementInput = CurrentMovementInput.GetSafeNormal();
    
    // Forward movement (X)
    AddMovementInput(GetActorForwardVector() * CurrentMovementInput.X);
    // Strafing movement (Y)
    AddMovementInput(GetActorRightVector() * CurrentMovementInput.Y);

    // Reset current movement input ready for next frame
    CurrentMovementInput = FVector2d::ZeroVector;
}

// Called to bind functionality to input
void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up input mapping context
    if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(GetLocalViewingPlayerController()->GetLocalPlayer()))
    {
        if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
        {
            if (!ShooterInputMappingContext.IsNull())
            {
                InputSystem->AddMappingContext(ShooterInputMappingContext.LoadSynchronous(), 1);
            }
        }
    }

    // Action bindings
    UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PlayerInputComponent);

    Input->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AShooterCharacter::MoveCallback);
    Input->BindAction(LookAction, ETriggerEvent::Triggered, this, &AShooterCharacter::LookCallback);
}

void AShooterCharacter::MoveCallback(const FInputActionInstance& Instance)
{
    FVector2D AxisValues = Instance.GetValue().Get<FVector2D>();

    // Add onto current movement input so that opposite inputs cancel each other?
    CurrentMovementInput += AxisValues;
}
...
Joe Bevis
  • 31
  • 1
  • 6

1 Answers1

0

I think something like this would work:

void AShooterCharacter::MoveCallback(const FInputActionValue& Value, const FName& ActionName)
{
    float XInput = 0.0f;
    float YInput = 0.0f;

    // Check which keys are currently pressed for each axis
    if (Value.GetAxisValue("MoveForward") > 0.0f) {
        XInput += 1.0f;
    }
    if (Value.GetAxisValue("MoveForward") < 0.0f) {
        XInput -= 1.0f;
    }
    if (Value.GetAxisValue("MoveRight") > 0.0f) {
        YInput += 1.0f;
    }
    if (Value.GetAxisValue("MoveRight") < 0.0f) {
        YInput -= 1.0f;
    }

    // Combine the pressed keys for each axis to form the final movement input
    CurrentMovementInput = FVector2D(XInput, YInput);
}