Hi,
Sorry in advance for the long post, but I’ve been struggling with this for a few days now. This is regarding player input and a custom pawn movement component. I intentionally avoid using the Character implementation of this.
I have the following pawns, input & movement setup:
class AMovementPawn : public ACustomPawn
{
public:
virtual void MoveForward(const float Axis) override;
virtual void MoveRight(const float Axis) override;
virtual FVector GetControlForwardVector() const override;
virtual FVector GetControlRightVector() const override;
protected:
UCustomMovementComponent* Movement;
};
This pawn enables movement with the “MoveForward” and “MoveRight” methods being called by the PlayerController through input axis mapping. Note that this one does not have a camera. Here’s the implementation:
void AMovementPawn::MoveForward(const float Axis)
{
Movement->AddInputVector(GetControlForwardVector().GetSafeNormal() * Axis);
}
void AMovementPawn::MoveRight(const float Axis)
{
Movement->AddInputVector(GetControlRightVector().GetSafeNormal() * Axis);
}
FVector AMovementPawn::GetControlForwardVector() const
{
return GetActorForwardVector();
}
FVector AMovementPawn::GetControlRightVector() const
{
return GetActorRightVector();
}
Now I have another pawn which derives from AMovementPawn:
class AThirdPersonPawn : public AMovementPawn
{
public:
virtual void PitchCamera(const float Axis) override;
virtual void YawCamera(const float Axis) override;
virtual FVector GetControlForwardVector() const override;
virtual FVector GetControlRightVector() const override;
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UThirdPersonSpringArmComponent* CameraSpringArm;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UCameraComponent* Camera;
};
It overrides “GetControlForwardVector” and “GetControlRightVector” to provide a vector based on the PlayerController control rotation (or the camera, if you will). This allows me to move forward and right in relation to my camera and not the pawn rotation. Here’s the implementation:
void AThirdPersonPawn::PitchCamera(const float Axis)
{
AddControllerPitchInput(Axis * GetWorld()->GetDeltaSeconds());
}
void AThirdPersonPawn::YawCamera(const float Axis)
{
AddControllerYawInput(Axis * GetWorld()->GetDeltaSeconds());
}
FVector AThirdPersonPawn::GetControlForwardVector() const
{
return FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
}
FVector AThirdPersonPawn::GetControlRightVector() const
{
return FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
}
Here’s the tough part:
I am consuming the input vector in my movement component TickComponent:
const FVector InputVector = ConsumeInputVector().GetClampedToMaxSize(1.0f);
const FVector DeltaVelocity = InputVector * MovementSpeed * DeltaTime;
if (!DeltaVelocity .IsNearlyZero())
{
FHitResult Hit;
SafeMoveUpdatedComponent(DeltaVelocity, InputVector.ToOrientationQuat(), true, Hit);
}
This input vector I am getting here is in relation to my camera’s rotation. Meaning it is also affected by my camera’s pitch, which makes my pawn fly around in whatever direction the camera is facing. I am trying to rotate my input vector’s pitch such that it always lies within the XY plane with its original yaw and magnitude.
I know I could simply project it onto XY, get a normal of that and multiply by the original input vector’s magnitude, but this is giving me issues when my camera has pitch close to 90 or -90 (e.g. a projection of Z axis vector onto XY is [0,0,0], similar problem here). So when my camera points down (pitch -90) and I press forward, my pawn does not move because the projection of my camera’s forward vector onto XY is pretty much [0,0,0].
Another solution would be to project the vector onto XY in the “GetControlForwardVector” method to get rid of the pitch all together, and that works! However, that would be functionally wrong since a derived movement component might care about the pitch of the input vector (for example swimming, flying movement etc.).
In short: How do I unrotate my input vector inside the movement component tick so that it aligns with the XY plane and keeps its original magnitude and yaw without projecting it? Or am I missing something simple here?
Thanks for taking the time to read.