I realize that this thread is already quite old, but in case anyone else is searching for an answer about how to do this, I decided to post my solution anyways.
You cannot bind a delegate of the pawn function directly in AMyPlayerController::SetupInputComponents
because the Pawn will not yet be possessed when the function is called, so GetPawn()
will return nullptr
. Hence the error. My solution is to define a handler function in the PlayerController class itself, then delegate the actual implementation to the pawn during runtime.
TestPlayerController.cpp
void ATestPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAxis("MoveForward", this, &ATestPlayerController::MoveForward);
}
void ATestPlayerController::MoveForward(float Value)
{
auto pawn = Cast<ADefaultPawn>(this->GetPawn());
if (pawn)
{
pawn->MoveForward(Value);
}
}
It is important to include the Super::SetupInputComponent();
line, as otherwise the input component will not be set up properly (I believe this is what threw the OP in his last version).
Since my Pawn inherits from DefaultPawn, no custom implementation of MoveForward is necessary. No relevant code was added. You obviously have to add an axis called "MoveForward"
in the project settings. The solution was tested with engine version 4.7.5
In case anyone is wondering, here is my rationale for why I want to handle input in the PlayerController: As I understand it, the design intent behind the Pawn is to be the physical representation of a controlled object, while the PlayerController is intended to represent the Player’s will. From the PlayerController documentation:
A PlayerController is the interface between the Pawn and the human player controlling it. The PlayerController essentially represents the human player’s will.
One thing to consider when setting up your PlayerController is what functionality should be in the PlayerController, and what should be in your Pawn. It is possible to handle all input in the Pawn, especially for less complex cases. However, if you have more complex needs, like multiple players on one game client, or the ability to change characters dynamically at runtime, it might be better to handle input in the PlayerController. In this case, the PlayerController decides what to do and then issues commands to the Pawn (e.g. “start crouching”, “jump”).
Also, in some cases, putting input handling or other functionality into the PlayerController is necessary. The PlayerController persists throughout the game, while the Pawn can be transient. For example, in deathmatch style gameplay, you may die and respawn, so you would get a new Pawn but your PlayerController would be the same. In this example, if you kept your score on your Pawn, the score would reset, but if you kept your score on your PlayerController, it would not.
My take on this is the following: input deals with player intent, not physical motion, so I want to wrap the input handling in a PlayerController class while delegating the actual implementation of the result to the Pawn class. Let’s say the player presses W because he wants to move forward. This is a statement of intent and should be handled in PlayerController. Then, the PlayerController issues a command to the Pawn to physically move. The Pawn, being a physical class, then handles the nitty-gritty details like collision and actually changing the pawn’s position.
To me, handling input in the PlayerController is mostly preferable because of the neater encapsulation. I just don’t like to clutter a possibly AI-controlled Pawn with a lot of irrelevant human-centric code. The doc mentions some other good points.