In order to let an actor transition from one rotator to another smoothly, function FMath::RInterpConstantTo()
should be used. The official documentation on this function is too brief to be helpful. This article aims to clear up the confusion.
Add member function and variable declaration
First off, in the actor class declaration, add the following functions and variables. PerformRotationInterpWithDelay(Delay)
is the public interface to be called outside the class. Its purpose is to halt for a duration of Delay, then let the actor rotate smoothly until the target rotator is reached, which in our example is simply FRotator::ZeroRotator
.
UCLASS()
class QL_API AMyActor : public AActor
{
GENERATED_BODY()
public:
...
//------------------------------------------------------------
// After Delay seconds, perform PerformRotationInterpCallback()
// which sets bStartRotationInterp to true, and performs rotation interpolation
// in Tick() until the rotation becomes FRotator::ZeroRotator
//------------------------------------------------------------
UFUNCTION(BlueprintCallable, Category = "C++Function")
void PerformRotationInterpWithDelay(const float Delay);
protected:
...
//------------------------------------------------------------
//------------------------------------------------------------
UFUNCTION()
void PerformRotationInterpCallback();
//------------------------------------------------------------
//------------------------------------------------------------
bool bStartRotationInterp;
}
Define the functions
Implementation detail of PerformRotationInterpWithDelay(Delay)
is shown below. After Delay, function PerformRotationInterpCallback()
is called, which simply sets the flag bStartRotationInterp
, making the actor rotate in the next Tick()
call.
For the static function FMath::RInterpConstantTo()
, the first argument is the current actor rotator GetActorRotation()
, not the initial actor rotator. The second argument is the target actor rotator, which is set to FRotator::ZeroRotator
in this example. The third argument is the duration in second between two frames DeltaTime
. The last argument is the interpolation speed not adequately explained in the documentation. Here is what it actually represents: For each call of FMath::RInterpConstantTo()
, the pitch, yaw, roll of the actor are uniformly incremented by a value of k. k is first set to the difference between target rotator and current rotator, but then clamped by [-m, m], where m is equal to DeltaTime
times the interpolation speed. An interpolation speed of S indicates a change in pitch, yaw, roll by S degree per second. FMath::RInterpConstantTo()
returns the new rotator to be applied to the actor per Tick()
. To take into account the finite precision of floating point arithmetic, currentRotation.Equals(targetRotation)
is subsequently performed. If it evaluates to true, the flag bStartRotationInterp
is unset, and the rotation stops.
//------------------------------------------------------------
//------------------------------------------------------------
void AMyActor::PerformRotationInterpWithDelay(const float Delay)
{
GetWorldTimerManager().SetTimer(StartRotationDelayTimerHandle,
this,
&AMyActor::PerformRotationInterpCallback,
1.0f, // time interval in second
false, // loop
Delay); // delay in second
}
//------------------------------------------------------------
//------------------------------------------------------------
void AMyActor::PerformRotationInterpCallback()
{
bStartRotationInterp = true;
}
//------------------------------------------------------------
//------------------------------------------------------------
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
...
// interp rotation
if (bStartRotationInterp)
{
FRotator NewRotation = FMath::RInterpConstantTo(GetActorRotation(), FRotator::ZeroRotator, DeltaTime, 100.0f);
SetActorRotation(NewRotation);
if (GetActorRotation().Equals(FRotator::ZeroRotator))
{
bStartRotationInterp = false;
}
}
}