How does PlayerController class work?

Hello community,

I just started a project in UE5 using C++. For now my idea is just to create a character and make some easy mechanics.

I started creating the character class and implementing the functionality and input binding in that class but I saw that if I want to make my project multiplayer (local or online) I should use PlayerController class.

So my question here is:

  • Should I create the functionality of the player in a PlayerController class? Because the character class has the components so I have to be referencing my character class all the time and checking that mycharacter != nullptr.

  • Should I make the input bindings inside PlayerController class and delete them from the character class? I will try to copy some code to be more clear.

RoboPlayer.h
class FIRSTPROJECT_API ARoboPlayer : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ARoboPlayer();

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

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	UCameraComponent* Camera;

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

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

	UFUNCTION()
	void MoveForward(float value);

};
RoboPlayer.cpp
ARoboPlayer::ARoboPlayer()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	SpringArm = CreateDefaultSubobject<USpringArmComponent>("SpringArm");
	Camera = CreateDefaultSubobject<UCameraComponent>("Camera");

	SpringArm->SetupAttachment(RootComponent);
	Camera->SetupAttachment(SpringArm);
}

// Called when the game starts or when spawned
void ARoboPlayer::BeginPlay()
{
	Super::BeginPlay();
	
}

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

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

}

void ARoboPlayer::MoveForward(float value)
{
	// SOME MOVEMENT LOGIC
}
MyPlayerController.h
UCLASS()
class FIRSTPROJECT_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()
protected:
	UPROPERTY(BlueprintReadOnly)
	ARoboPlayer* RoboPlayer;

public:
	AMyPlayerController();
	virtual void Tick(float DeltaSeconds) override;
	virtual void SetupInputComponent() override;
};
MyPlayerController.cpp
#include "MyPlayerController.h"

AMyPlayerController::AMyPlayerController()
{
	PrimaryActorTick.bCanEverTick = true;
}


void AMyPlayerController::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
	//AMyPlayerController::GetPawn()->AddMovementInput(FVector(1.0,0.0,0.0), 1, false);
}

void AMyPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();
	RoboPlayer = Cast<ARoboPlayer>(GetCharacter());
	if (RoboPlayer)
	{
		InputComponent->BindAxis("Move Forward", RoboPlayer, &ARoboPlayer::MoveForward);
	}
}

Btw sorry if I mispell something English is not my main language :S.

2 Likes

at least in blueprint the player controller is the one that handles all the inputs, it will always have priority over the character input, so almost all the code of the character goes in the player controller

1 Like

Thank you for the answer.
Is quite weird because I was checking the new UE5 projects like Lyra and it looks like they dont use a APlayerController, so I should be missunderstanding something.

I will keep doing some research until I find how to manage the input to move a character from a APlayerController class in C++.

As I said, Thank you :slight_smile: