Search code examples
c++unreal-engine5

How to use input mapping context in UE5 (without blueprint)


I am a beginner in UE5 (I started learning yesterday), and I am now working on a simple task. It takes the WSAD and mouse to do simple movement and camera operations using input mapping context.

However, after my self-learning, I end up with this:

UCLASS()
class ASSIGNMENT1_API AFirstPersonCharactor : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AFirstPersonCharactor();
    UPROPERTY(EditAnywhere, Category = "Components|Camera")
    UCameraComponent* camera;


    UPROPERTY(EditAnywhere, Category = "Input|Actions")
    UInputAction *IA_KB_CM_InOut;
    UPROPERTY(EditAnywhere, Category = "Input|Actions")
    UInputAction* IA_KB_CM_LeftRight;
    UPROPERTY(EditAnywhere, Category = "Input|Actions")
    UInputAction* IA_KB_CL_UpDown;
    UPROPERTY(EditAnywhere, Category = "Input|Actions")
    UInputAction* IA_KB_CL_LeftRight;



    UPROPERTY(EditAnywhere, Category = "Input|Actions")
    TSoftObjectPtr<UInputMappingContext> IMCControls;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    void KB_CM_InOut(const FInputActionInstance& Instance);

    void KB_CM_LeftRight(const FInputActionInstance& Instance);

    void KB_CL_UpDown(const FInputActionInstance& Instance);

    void KB_CL_LeftRight(const FInputActionInstance& Instance);

};

and this is my cpp file:

// Sets default values
AFirstPersonCharactor::AFirstPersonCharactor()
{
    PrimaryActorTick.bCanEverTick = true;

    camera = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    camera->SetupAttachment(RootComponent);
    camera->SetRelativeLocation(FVector(0));

}

void AFirstPersonCharactor::BeginPlay()
{
    Super::BeginPlay();
}

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

}

// Called to bind functionality to input
void AFirstPersonCharactor::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);
    if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(GetController()))
    {   
        
        if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
        {
            InputSystem->AddMappingContext(IMCControls.LoadSynchronous(),10);
        }
    }
    
    UEnhancedInputComponent* input = Cast<UEnhancedInputComponent>(PlayerInputComponent);

    if (IA_KB_CM_InOut) {
        input->BindAction(IA_KB_CM_InOut, ETriggerEvent::Started, this, &AFirstPersonCharactor::KB_CM_InOut);
    }
    if (IA_KB_CM_LeftRight) {
        input->BindAction(IA_KB_CM_LeftRight, ETriggerEvent::Started, this, &AFirstPersonCharactor::KB_CM_LeftRight);
    }
    if (IA_KB_CL_UpDown) {
        input->BindAction(IA_KB_CL_UpDown, ETriggerEvent::Started, this, &AFirstPersonCharactor::KB_CL_UpDown);
    }
    if (IA_KB_CL_LeftRight) {
        input->BindAction(IA_KB_CL_LeftRight, ETriggerEvent::Started, this, &AFirstPersonCharactor::KB_CL_LeftRight);
    }
}

void AFirstPersonCharactor::KB_CM_InOut(const FInputActionInstance &Instance)
{
    printf("a");
    float FloatValue = Instance.GetValue().Get<float>();
    if (FloatValue != 0) {
        AddMovementInput(GetActorForwardVector(),FloatValue);
    }
}

void AFirstPersonCharactor::KB_CM_LeftRight(const FInputActionInstance& Instance)
{
    float FloatValue = Instance.GetValue().Get<float>();
    if (FloatValue != 0) {
        AddMovementInput(GetActorRightVector(), FloatValue);
    }

}

void AFirstPersonCharactor::KB_CL_LeftRight(const FInputActionInstance& Instance)
{
    float FloatValue = Instance.GetValue().Get<float>();
    if (FloatValue != 0) {
        AddControllerYawInput(FloatValue);
    }
}

void AFirstPersonCharactor::KB_CL_UpDown(const FInputActionInstance& Instance)
{
    float FloatValue = Instance.GetValue().Get<float>();
    if (FloatValue != 0) {
        AddControllerPitchInput(FloatValue);
    }
}

This ends with no bug, and I have the inputAction and inputMappingContext assets set in the outliner. But no matter which key I press, there are always no behaviours I can observe.

EDIT: after I add GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("haha")); to debug, I found that my SetupPlayerInputComponent is working, but

if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(GetController()))

probably not.


Solution

  • You shouldn't be trying to cast your controller to local player, and also you'd rather setup MappingContext in BeginPlay() rather than in SetupInputComponent(...). So instead of doing that cast and then trying to add mapping context do this:

    if (auto PlayerController = Cast<APlayerController>(Controller))
    {
        if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
        {
            Subsystem->AddMappingContext(DefaultMappingContext, 0);
        }
    }