How can I register a new PlayerController on a pawn during runtime?

I have a custom third person player class (CPlayer.h, CPlayer.cpp) which derives from ACharacter where I am defining my camera controls (left click and hold to free look, right click to rotate the character), and my movement controls (WASD movement). The functionality works just fine, but when I am trying to implement player respawn from the GameMode via:

CGameModeBase.cpp

void ACGameModeBase::OnActorKilled(AActor* VictimActor, AActor* KillerActor)
{
	ACPlayer* Player = Cast<ACPlayer>(VictimActor);

	if (Player) {
		FTimerHandle TimerHandle_RespawnDelay;

		FTimerDelegate Delegate;
		Delegate.BindUFunction(this, "RespawnPlayerElapsed", Player->GetController());

		float RespawnDelay = 2.0f;

		GetWorldTimerManager().SetTimer(TimerHandle_RespawnDelay, Delegate, RespawnDelay, false);
	}
}

void ACGameModeBase::RespawnPlayerElapsed(AController* Controller)
{
	if (ensure(Controller))
	{
		Controller->UnPossess();

		RestartPlayer(Controller);
	}
}

The newly spawned player character can move/jump/target/etc. The only thing that doesn’t work is the right click/left click functionality. As a matter of fact, it will crash the engine. I’ve drilled it down to this line:

CPlayer.cpp

PlayerController->GetMousePosition(tempVector.X, tempVector.Y); 

In the BeginPlay method of CPlayer.cpp, I’m defining PlayerController as PlayerController = Cast<APlayerController>(Controller);

Which I’m using to store the mouse position when moving the camera. This leads me to believe when my new player class is spawned in, the player controller is not correct. Any thoughts on how to register this player controller when the new player is respawned or am I missing the mark entirely?

tip: since I can’t tell if APlayer is a PlayerController or a Character by it’s name, or some other class, might want to rename that class to be more explicit as tow hat it is.

I’m guessing that ACPlayer is your Pawn/Character, and yes, you don’t have a PlayerController at BeginPlay. You could cache that in your OnPossessed() function in ACPlayer.

However, you should consider the architecture of Controller => Character, and actually handle the mouse inputs in your PlayerController, then translate that to actions that the Pawn/Character would take from there.

1 Like

Pass the player controller reference to the pawn in the onpossess event of the player controller, not the pawn’s begin play.

A few things.

First, the PlayerController is the “player” and hopefully doesn’t die. The Pawn (or Character as a subclass) is the “actor” being killed. After reviving, you have the option of:

  1. Reviving the killed actor, and teleporting it to the respawn location
  2. Destroying the killed actor, and spawn a new pawn, and possess that pawn

It may be that 1) is the better option, depending on how much work you have to do to customize these pawns.

Finally, input and UI should generally be handled in the controller, not in the pawn. In the controller, if there is a possessed pawn, and that pawn is not dead, then forward the input commands from the player controller to the possessed pawn movement component with AddInput(), either once for each control axis in the Tick() event, or in each of the “event input (axis)” events.

Yes, the standard characters in the template starters do all this in the character itself. No, that’s not a good idea in practice.

Finally, if you’re doing this in a networked game, the “controller” for a pawn will not be directly available when that pawn actor is first instantiated on the client, and the “on possess” event won’t even fire on the client, only on the server. In this case, you need an OnRep for one of the “I’m controlling this pawn now” properties instead, and use that as your signal to wire things up in the client.

1 Like

Thank you for the response, just a quick follow up here. Is there any “official” documentation on the distribution between Controller and Pawn(Character)? I have started porting the movement and camera control functionality to the controller class, but I’m starting to realize that there isn’t much left to my Pawn class.

The way to think about it is that the player controller does UI, and decoding “the will” of the player.
The Pawn does presentation, and “acting on the will.”
So, player controller decides “player wants to turn left.”
Pawn gets told “set left turning to 1” and then does the physics and animation bits necessary to make that action actually happen.

Much of this is documented in the Gameplay Framework section of the documentation:

(There’s a 5.0 version, but it’s not fully updated yet – it turns out, almost everything out of 4.27 is the same, anyway, so that document is fine.)

1 Like

If you happen to be familiar with non-game programming practices, particularly MVC, then PlayerController is your Controller, Pawn is your Model, and View is… roughly… your display.

:slight_smile:

1 Like