I am trying to rotate an actor by 90-degree increments over time when the user presses a key. I have used QInterpConstantTo to do this, and it works fine in two axes, but on the third, I am getting what I think is gimbal lock as the interpolation never completes. I am using quaternions, so I don’t know what I am doing wrong? How can I prevent this when rotating an actor by 90 degrees in either of the 3 axes at one time? below is example code that causes the problem, when i press the key that binds to the 'ToggleRotateY function, the actor rotates twice then locks on the third attempt and no more input is accepted
Header File:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CubePawn.generated.h"
UCLASS()
class ROTATEMATCH_API ACubePawn : public APawn
{
GENERATED_BODY()
public:
ACubePawn();
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
void ToggleRotateY();
bool shouldRotate = false;
float RotationSpeed = 10.0f;
FQuat QuatTarget = FQuat(0.0f, 0.0f, 0.0f, 0.0f);
UPROPERTY(EditAnywhere)
UStaticMeshComponent* PawnMesh;
};
CPP File:
#include "CubePawn.h"
ACubePawn::ACubePawn(){
PawnMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Pawn Mesh"));
PawnMesh->SetupAttachment(RootComponent);
RootComponent = PawnMesh;
}
void ACubePawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent){
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAction("RotateY", IE_Pressed, this, &ACubePawn::ToggleRotateY);
}
void ACubePawn::Tick(float DeltaTime){
Super::Tick(DeltaTime);
if (shouldRotate) {
FQuat NewRotation = FMath::QInterpConstantTo(GetActorRotation().Quaternion(), QuatTarget, DeltaTime, RotationSpeed);
SetActorRotation(NewRotation.Rotator());
if (GetActorRotation().Equals(QuatTarget.Rotator(), 0.1f)) {
UE_LOG(LogTemp, Warning, TEXT("Reached Target"));
shouldRotate = false;
SetActorRotation(QuatTarget.Rotator());
}
}
}
void ACubePawn::ToggleRotateY() {
if (!shouldRotate) {
QuatTarget = GetActorRotation().Quaternion() * FRotator(90.0f, 0.0f, 0.0f).Quaternion();
shouldRotate = true;
}
}