Update, it seems that Pawn might actually do replicate, just that it’s own static mesh isn’t replicated by default.(And somehow StaticMesh replicate isn’t exposed in component)
Check this question and you can see there is a bStaticMeshReplicateMovement flag available when you blueprint a StaticMeshActor.(For something like physic enabled box/barrel/etc)
Warning, CODE block ahead, it should still be pretty easy to understand with any kind of scripting experience. Many keywords should be really familiar if you played Blueprint for a while
Also, here is how DefaultPawn setup it’s control, as I predicted, you add those input event binding in Pawn blueprint.(binds to a string you setup in editor)
These should be your basic setup if you create a new Pawn blueprint. (not from Custom Classes)
void ADefaultPawn::MoveRight(float Val)
{
if (Val != 0.f)
{
if (Controller)
{
FRotator const ControlSpaceRot = Controller->GetControlRotation();
// transform to world space and add it
AddMovementInput( FRotationMatrix(ControlSpaceRot).GetScaledAxis( EAxis::Y ), Val );
}
}
}
void ADefaultPawn::MoveForward(float Val)
{
if (Val != 0.f)
{
if (Controller)
{
FRotator const ControlSpaceRot = Controller->GetControlRotation();
// transform to world space and add it
AddMovementInput( FRotationMatrix(ControlSpaceRot).GetScaledAxis( EAxis::X ), Val );
}
}
}
void ADefaultPawn::MoveUp_World(float Val)
{
if (Val != 0.f)
{
AddMovementInput(FVector::UpVector, Val);
}
}
void ADefaultPawn::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
And rotation related are inherited from Pawn, note that even though it gets player controller to add rotation values,
but this is entirely inside Pawn.cpp. So in blueprint sense it should be in the event graph(ie, you might have different turn rate limit for different pawn)
void APawn::AddMovementInput(FVector WorldDirection, float ScaleValue)
{
UPawnMovementComponent* MovementComponent = GetMovementComponent();
if (MovementComponent)
{
MovementComponent->AddInputVector(WorldDirection * ScaleValue);
}
}
void APawn::AddControllerPitchInput(float Val)
{
if (Controller && Controller->IsLocalPlayerController())
{
APlayerController* const PC = CastChecked<APlayerController>(Controller);
PC->AddPitchInput(Val);
}
}
void APawn::AddControllerYawInput(float Val)
{
if (Controller && Controller->IsLocalPlayerController())
{
APlayerController* const PC = CastChecked<APlayerController>(Controller);
PC->AddYawInput(Val);
}
}
void APawn::AddControllerRollInput(float Val)
{
if (Controller && Controller->IsLocalPlayerController())
{
APlayerController* const PC = CastChecked<APlayerController>(Controller);
PC->AddRollInput(Val);
}
}
And here is the binding part(note these won’t be exposed in editor, thus we should probably avoid inherit DefaultPawn and use it as sort of debug Pawn. although you can also disable default binding and roll your own and get free movement component.)
void InitializeDefaultPawnInputBindings()
{
static bool bBindingsAdded = false;
if (!bBindingsAdded)
{
bBindingsAdded = true;
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::W, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::S, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Up, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Down, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Gamepad_LeftY, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::A, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::D, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::Gamepad_LeftX, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_LeftThumbstick, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_RightThumbstick, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_FaceButton_Bottom, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::LeftControl, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::SpaceBar, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::C, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::E, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Q, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Gamepad_RightX, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Left, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Right, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_Turn", EKeys::MouseX, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUp", EKeys::Gamepad_RightY, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUp", EKeys::MouseY, -1.f));
}
}
void ADefaultPawn::SetupPlayerInputComponent(UInputComponent* InputComponent)
{
check(InputComponent);
if (bAddDefaultMovementBindings)
{
InitializeDefaultPawnInputBindings();
InputComponent->BindAxis("DefaultPawn_MoveForward", this, &ADefaultPawn::MoveForward);
InputComponent->BindAxis("DefaultPawn_MoveRight", this, &ADefaultPawn::MoveRight);
InputComponent->BindAxis("DefaultPawn_MoveUp", this, &ADefaultPawn::MoveUp_World);
InputComponent->BindAxis("DefaultPawn_Turn", this, &ADefaultPawn::AddControllerYawInput);
InputComponent->BindAxis("DefaultPawn_TurnRate", this, &ADefaultPawn::TurnAtRate);
InputComponent->BindAxis("DefaultPawn_LookUp", this, &ADefaultPawn::AddControllerPitchInput);
}
}
So maybe there is a way to make a new Pawn class replicated properly.
I will keep you guys posted.