SetupInputComponent in PlayerController

Hello,

I know there’s already a lot of threads explaining how to setup inputs in the playercontroller to move my pawn, but I tried to do so but I still can’t manage to make it work. I’ve made a new PlayerController class, called CampaignPlayerController and I’ve also made a new public function, which is virtual void SetupInputComponent() override. Here’s my .h file for my controller:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "CampaignPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class PRIMALWARS_API ACampaignPlayerController : public APlayerController
{
	GENERATED_BODY()

public:

	ACampaignPlayerController();
	
protected:



public:

	virtual void SetupInputComponent() override;
	
};

And here’s my .cpp file:

// Fill out your copyright notice in the Description page of Project Settings.

#include "Controllers/CampaignPlayerController.h"
#include "Characters/CharacterBase.h"



ACampaignPlayerController::ACampaignPlayerController()
{
	// Sets default values

}

void ACampaignPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	InputComponent->BindAxis("MoveForward", this, &ACharacterBase::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &ACharacterBase::MoveRight);

	InputComponent->BindAxis("LookUp", this, &ACharacterBase::AddControllerPitchInput);
	InputComponent->BindAxis("LookRight", this, &ACharacterBase::AddControllerYawInput);
}

Also, the functions MoveForward() and MoveRight() are defined in my Character-class. I’m simply trying to move my character using the player controller that I’ve made. How do I do this? The code above doesn’t work and gives me red underlines my super-call, and gives me an error saying:

FInputAxisBinding &UInputComponent::BindAxis(const FName)': cannot convert argument 3 
    from 'void (__cdecl ACharacterBase::* )(float)' to 'void (__cdecl ACampaignPlayerController::* )(float)

If anyone could help me it would be highly appreciated! Thanks in advance :slight_smile:

~Stefan

I think your issue may be that you’re trying to call up a function belonging to a different class. Usually, you provide the BindAxis macro with a function also belonging to your PlayerController class.

This explains the compile error you’re getting: the compiler is telling you it cannot cast (convert) ACharacterBase to ACampaignPlayerController. It’s expecting a function belonging to the ACampaignPlayerController class.

Here’s another way of thinking about it. The way you have it set up right now, your PlayerController does not know which instance of ACharacterBase to execute the move functions for. You’re telling it, “When move-forward input is provided, execute the MoveForward function on the APlayerBase class.” But which APlayerBase actor should the player controller call this function on? See what I mean?

Try making a pair of new functions in your ACampaignPlayerController class, also called MoveForward() and MoveRight() if you want, and direct your BindAxis macros to those functions instead.

Then, from within the new movement functions, call up the existing MoveForward() and MoveRight() functions on your APlayerBase class using a pointer to specify which specific APlayerBase actor you want to respond to the input.

That should get things moving for you. (See what I did there?)

Best of luck!

2 Likes

Also, I forgot to mention, the red squiggly underlines you’re seeing on your Super call are a known but harmless issue that started in UE 4.20. Starting with that version, Visual Studio seems to get confused by the many UE macros throughout the codebase and seems to think many publicly accessible members are suddenly not publicly accessible.

It’s annoying to ignore and work around, but I’m not aware of any fix. Luckily, it doesn’t actually interfere with compiling. Just Intellisense being weird.

Hello! I understand what you’re saying, but I’m struggling to implement this into code. First of all, I’ve made a new variable in my .h of my controller

ACharacterBase* PossessedPlayer;

and set it to the player that my controller is possessing using a cast in my controller’s construct:

// Sets default values
ACampaignPlayerController::ACampaignPlayerController()
{
	PossessedPlayer = Cast<ACharacterBase>(Player);
}

If you didn’t know, Player is the player that is possessed by the controller, I found this is the APlayerController API.

I’ve then tried to use my function MoveForward() to add movement input by calling AddMovementInput from my character, or the player that is controlled:

void ACampaignPlayerController::MoveForward(float Value)
{
if (PossessedPlayer)
{
PossessedPlayer->AddMovementInput(PossessedPlayer->GetActorForwardVector() * Value);
}
}
Anyways, this doesn’t work, and it has definetily got something to do with me trying to reference the respective controlled player of my controller. Adding mouse look/input works completely fine however, here’s the InputComponent function in my PlayerController:

void ACampaignPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();

InputComponent->BindAxis("MoveForward", this, &ACampaignPlayerController::MoveForward);
InputComponent->BindAxis("MoveRight", this, &ACampaignPlayerController::MoveRight);

InputComponent->BindAxis("LookUp", this, &ACampaignPlayerController::AddPitchInput);
InputComponent->BindAxis("LookRight", this, &ACampaignPlayerController::AddYawInput);

}

If you have any ideas, please let me know. Thanks for the great support, I really appreciate it! :slight_smile:

bump bump bump

If your character is responding to look input, that’s good — it means that your pointer to the controlled character is non-null (which would have been my first guess).

My only remaining guess right now for why movement input isn’t working is: does your ACharacterBase class derive from either the ADefaultPawn or ACharacter built-in classes? It needs to if you want AddMovementInput() to work automatically. Check out the UE documentation page for AddMovementInput(…) to see this note at the top about using those two classes versus implementing your own behavior to handle movement:

Base Pawn classes won’t automatically apply movement, it’s up to the user to do so in a Tick event. Subclasses such as Character and DefaultPawn automatically handle this input and move.

If the name of your character class is any indication, though, it seems you’re probably already deriving from ACharacter, in which case I’m not sure why it’s not working. Just thought I’d check.

My ACharacterBase is derived from ACharacter, yes. And the mouse look is all handled in my player controller with AddPitchInput and AddYawInput, in which I won’t need to reference my character in any way.

In fact, I recently found out my controlled character is null, and just don’t know how to set it. From there, I should be fine figuring things out. So, any clues?

Again, thank you so much for your help :slight_smile:

Sure. Here’s one way I’ve used in the past.

You can override the APawn::PossessedBy function to know when your pawn has been possessed by your player controller.

In your ACharacterBase.h file, you can override this function function like so:

// Called whenever this character is possessed by a controller
virtual void PossessedBy(AController* inController) override;

Also in ACharacterBase.h, you might also want to define a pointer to store the player controller that possesses the pawn:

// A pointer to the campaign player controller that has possessed this character:
ACampaignPlayerController* CampaignPlayerController;

Now in your ACharacterBase.cpp file, define PossessedBy using something like:

void ACharacterBase::PossessedBy(AController* inController)
{
    ACampaignPlayerController* CPC = Cast<ACampaignPlayerController>(inController);
    if (CPC)
    {
        // Store a pointer to the campaign player controller for convenience:
        CampaignPlayerController = CPC;

        // Now call up OnPossess on the campaign player controller, providing it a
        //  pointer to this character so the controller can later access it easily:
        CPC->OnPossess(this);
    }
}

Next, in ACampaignPlayerController.h, define a pointer to the ACharacterBase actor that will be possessed, so the controller always has a way to access the controlled pawn:

// A pointer to the controlled pawn so it can be easily accessed once possessed:
ACharacterBase* ControlledCharacter;

Finally, you can define your OnPossess function in ACampaignPlayerController.cpp like so:

void ACampaignPlayerController::OnPossess(ACharacterBase* inCharacter)
{
    // Just possessed a pawn. Store the pointer to it for later use:
    ControlledCharacter = inCharacter;
}

That’s it! Your controller will now always have a pointer to the controlled pawn, even if the controller switches from pawn to pawn.

Hope this helps!

Follow up: I’m very dumb. I just realized there’s a GetPawn() function on the AController class.

So, instead of all that work above, just try calling GetPawn(). You can call this and cast it once, for example in your BeginPlay() function, and from then on you’ll have a pointer to your ACharacterBase actor that you can use for all of your movement inputs.

Can’t believe I overlooked that. Oh well. Now we know!

1 Like

Actually, when I think about it, I tried to set my PossessedPlayer in my constructor, whereas the possessed pawn isn’t even set before begin play! Dunno what I was thinking, but
anyways, your solution works fluidly, I’m so glad right now :3

Thank you so much, the_batch! :slight_smile:

I don’t know if this is the right place to ask this question, but I was implementing a custom controller to my character and following this thread I managed to get it working. Now I wonder switch possessed characters through C++? I found a documentation about the topic but only for blueprints (this one) but nothing about implementing it in C++. My biggest problem is that current I don’t know which character will be possessed once the game starts (I used GetPawn() in the controller setup) and neither how to change to another character using using Possess()/UnPossess() because I don’t know how to declare the next character.

In case you wonder how I setted everything up here is my MainPlayerController.cpp

   #include "MainPlayerController.h"
     
     AMainPlayerController::AMainPlayerController()
     {
     
     }
     
     void AMainPlayerController::BeginPlay()
     {
         Character = Cast<ABaseCharacter>(GetPawn());
     }
     
     void AMainPlayerController::SetupInputComponent()
     {
         Super::SetupInputComponent();
     
         InputComponent->BindAxis("MoveForward", this, &AMainPlayerController::MoveForward);
         InputComponent->BindAxis("MoveRight", this, &AMainPlayerController::MoveRight);
     }
     
     void AMainPlayerController::MoveForward(float AxisValue)
     {
         FVector Direction = FRotationMatrix(GetControlRotation()).GetScaledAxis(EAxis::X);
     
         Character->AddMovementInput(Direction, AxisValue);
     }
     
     void AMainPlayerController::MoveRight(float AxisValue)
     {
         FVector Direction = FRotationMatrix(GetControlRotation()).GetScaledAxis(EAxis::Y);
     
         Character->AddMovementInput(Direction, AxisValue);
     }