Static Casting in Unreal?

I’m creating a game where the player could potentially play 100s of different pawns, each with their own collisions, meshes, animations, etc(All defined in Blueprints in the end). However they all share the same underlying inputs & functions. So as a result I’ve handled the movement inputs in the PlayerController which passes on the inputs to functions in a custom pawn class. Or in code:
[SPOILER]
Player Controller.ccp



//The *** mean A S S (My Game Name is Abbreviated to SS & Actor Classes are prefixed with A so... A S S is my prefix for actor classes XD)
void ***_MP_PlayerController_Master::SetupInputComponent()
{
 Super::SetupInputComponent();
 check(InputComponent);
 if (InputComponent)
 {
  UE_LOG(LogTemp, Error, TEXT("InputComponent working!"));
  //Movement Controls
  InputComponent->BindAxis("MoveForward", this, &***_MP_PlayerController_Master::MoveForward);
} //This is a virtual void function btw
 



void ***_MP_PlayerController_Master::MoveForward(float AxisValue)
{
 if (!PPawn && AxisValue == 0.f) {return;}
 else
 {
  PPawn->MoveForward(AxisValue);
 }
}


[/SPOILER]

Basically I plan to create the following

Master_Pawn
Master_Character

[INDENT=2] (These will be in Blueprints)
[/INDENT]
[INDENT=2] Lion
Sheep
Robot
Robot_Dog
Human
Alien
etc
etc
etc
[/INDENT]
Spectator_Pawn
Menu_Pawn

I Currently Cast to the Master Pawn. Now from my understanding of child actors(I'm rather new to C++ so I might be wrong, please correct me if I am) the virtual void function will be called on the child no matter if its overridden. So that way I can define input in the Master_Pawn Class and Character classes that will then be inherited on the Lion, Sheep, etc classes unless its overridden. This way I don't have to define the same inputs 100 times over. 

[SPOILER]



//This is called whenever a Pawn is Possessed from my understanding
void ***_MP_PlayerController_Master::BeginPlayingState()
{
 Super::BeginPlayingState();
 PPawn = Cast<***_MP_Pawn_Master>(GetPawn());
 if (!PPawn)
 {
  UE_LOG(LogTemp, Error, TEXT("Player Controller Failed to Cast to Player Pawn. Make sure Player Pawn is of type ***_MP_Pawn_Master!"));
  return;
 }
}


[/SPOILER]
However this currently means that the cast will fail for all of the children using the current method so I can’t call the input functions on the sheep for example . I would use static_cast(Which I believe lets me go down), but from what I’ve read Unreal doesn’t support that C++ type. So what’s the correct way of implementing the above system in Unreal? Is their a different casting function I could use that uses static casting?

EDIT: Should I be creating a custom C++ component, on the pawn, which I then cast to that sets up the default input functions instead of the Pawn itself? Would that be the correct way to implement this code?

Take it from me - do it in the Pawn, and put the inputs in your master pawn (Master_Character). The problem with doing it in the Player Controller is that you lose flexibility later and have to redesign everything.

Managing the input stack by yourself like this is a pain. SetPawn() is a more reliable place to change bindings, if you really have to.

UE4 uses a RTTI-esque system. So to do a cast, you simply do “Cast<MyChildClass>(MyBaseClass)” - It boils down to a simple static cast.You’ll find that paradigm everywhere in the engine if you search through the code.

Thanks for the help guys!

@TheJamsh
I’d love to handle it all on the Pawn, but I want to change characters dynamically at runtime in the Unreal Engine, and have support for Multiplayer(Respawn) as well (At least down the line). For such use cases Epic recommends using the PlayerController over the Pawn to handle player input. (https://docs.unrealengine.com/en-US/…ayerController)

So that’s what i’m doing. However is that no longer the case and is the document out of date?

@ExtraLifeMatt
Just for future reference do I have to specify the ChildClass specifically, eg. Sheep? Or is there a generic name I could use to cast to all child classes of a Base Class?

Also a quick update I’ve changed how i’m sending the input to the pawn. What I’m now doing is casting to the possessed pawn and using the GetComponentByClass function which is called on the AActor that contains the component(In this case the player pawn). The component is automatically created on any child actor and because i’m not casting specifically to the pawn it works with any child.
[SPOILER]
Player Controller.C file



//Called when a pawn is possessed
void ***_MP_PlayerController_Master::BeginPlayingState()
{
 Super::BeginPlayingState();

 //Cast to the InputRecciver on the Default Pawn.
 InputRecciver = Cast<UAC_InputRecciver>(GetPawn()->GetComponentByClass(UAC_InputRecciver::StaticClass()));
//Checks for Cast Failed and if it has returns an error to log
 if (!InputRecciver)
 {
  UE_LOG(LogTemp, Error, TEXT("Player Controller Failed to Cast to Input Recciver. Make sure Player Pawn Possesses Input Recciver Component!"));
  return;
 }
 if (InputRecciver)
 {
  if (IsDebugTrue) { UE_LOG(LogTemp, Warning, TEXT("Player Controller Cast to Input Recciver!")); }
 }
}


[/SPOILER]

If you want to change characters dynamically at runtime you have to possess them anyway, and the pawns input get’s added/removed automatically form the player controllers stack.

Despite it coming from Epic, that documentation seems like poor advice to me to be honest. For example, I have vehicles in my game. Both Vehicles and Characters are pawns, but vehicles handle input very differently to characters and therefore can’t share functionality.

You would need to know the name specifically if you are trying to cast to a child class. However, you could use a ClassIterator to find all the child classes of a base class using TSubClassOf<MyBaseClass>. Again, check the code and you’ll find lots of examples.

Except if parent and chill class bind different functions to same input… in that case both will be called… and i think @Mfgcasa](https://forums.unrealengine.com/member/52491-mfgcasa) want to do this… i mean implement base input functionality in parent class like basic movement, but override input if needed without old bind…
anyway ue4 can handle both way… but… seems you try to overengineer this with a custom component.

@Mfgcasa

  1. Use -> FInputBinding ( FInputBinding | Unreal Engine 5.2 Documentation ) when you bind the function, so you are able to turn on bConsumeInput.
    if bConsumeInput is true and you bind anything to same inputname old function wouldnt called.

  2. You have the power to remove / add bindings runtime. Here is some old code im used in a hero based shooter game…


void AAHBaseCharacter::DeleteAxisBind(FName BindName)
{
 for (int it = 0; it < InputComponent->AxisBindings.Num(); it++)
 {
  FInputAxisBinding curr = InputComponent->AxisBindings[it];
  if (curr.AxisName == BindName)
  {
   InputComponent->AxisBindings[it].AxisValue = 0;
   InputComponent->AxisBindings[it].AxisDelegate.Unbind();
   InputComponent->AxisBindings.RemoveAt(it);
  }
 }
}

void AAHBaseCharacter::DeleteActionBind(FName BindName)
{
 for (int it = 0; it < InputComponent->AxisBindings.Num(); it++)
 {
  if (InputComponent->GetActionBinding(it).ActionName == BindName)
  {
   InputComponent->RemoveActionBinding(it);
  }
 }
}

Just an FYI, I’ve shipped 3 projects where the player can possess can multiple pawns at will. We handled it similarly as the OP outlined:

  • all key bindings take place in the player controller (makes sense because it represents the player’s will)
  • all pawns handle (or ignore) a set of commands passed into them by the player controller

So when the player holds down the TurnLeft() keybind:

PlayerController->TurnLeft()->CurrentlyPossessedPawn->TurnLeft()

Works well. Really nice having all binds in one spot. Your controllable pawns can either be a class hierarchy or implement a “Controllable” interface. Either way works. :cool:

It’s up to you guys, but seems like poor design to me. It adds an artificial dependency between the pawn and the controller, and adds unnecessary layers of function calls and additional checks that need to be done.

What do you do in the case where you have a ‘FireWeapon’ command for example. Characters might implement that, but Spectators likely won’t. Now in the player controller you have to add more code paths depending on what the player is possessing. This can quickly get messy.

I stand by my advice - handle pawn-specific bindings in the pawn itself inside APawn::SetupPlayerInputComponent(). That gives the most flexibility, requires the least code, and as you switch between pawns, the bindings are automatically handled for you. There’s a reason that function exists. If you need subclasses to change input behaviour then make the bindings virtual.

2 Likes