# Calculate smooth transition between local space angles

I'm trying to calculate direction of moving character (to rotate it's animation). I have something like this:

Character can have 4 cardinal directions. The rotation is calculated from the current cardinal direction. So for example For north we have -90 degrees from N to W and 90 degrees from N to E. From E to N we have -90 degrees and from E to S we have 90 degrees.

The problem occurs when character is switching directions.It happens at about half the distance between cardinal directions. At this point current rotation is switching from negative to positive number (or other way around), and there is noticeable hitch. When for example going from E to N, it switches to N direction but it was at about -45 degrees which in N space it places for a frame or two between N and W directions.

Why do I calculate angles in cardinal direction space ? Animations are prepared for strafing or moving backward (or any other angle) and I need to assume that the direction of animation is 0 degrees and calculate from here.

Is there way to smoothly change angle between cardinal directions ?

For now I tried to lerping between them when switching (which improved overall look but is far from smooth transition), tried to track from which direction the switch is coming, but it didn't really improved anything.

FVector Right = Character->GetActorRightVector();
FVector Forward = Character->GetActorForwardVector();
FTransform Transform = Character->GetTransform();
FVector CurrentAcceleration = CMC->GetCurrentAcceleration();
FVector CurrentVelocity = CMC->Velocity;

FVector AccelerationDirection = CurrentAcceleration.GetSafeNormal2D();
FVector VelocityDirection = CurrentVelocity.GetSafeNormal2D();

FVector LocalAcceleration = Transform.InverseTransformVectorNoScale(AccelerationDirection);
FVector LocalVelocity = Transform.InverseTransformVectorNoScale(VelocityDirection);

float DeltaTime = Output.AnimInstanceProxy->GetDeltaSeconds();

float Atan2Angle = FMath::Atan2(LocalVelocity.Y, LocalVelocity.X);
const int32 ChildIndex = FMath::RoundToInt((Atan2Angle * 2 / PI) + 4) % 4;

float OldOrient = CurrentOrient;

EFCardinalDirection Dir = static_cast<EFCardinalDirection>(ChildIndex);
EFCardinalDirection OldDir = static_cast<EFCardinalDirection>(OldDirection);

float DirDot = 0;
//main switch wihin which I determine from where calculate angle.
switch (Dir)
{
case EFCardinalDirection::N:
{
FQuat ForwardQuat = FQuat::FindBetween(Forward, CurrentVelocity);
float OrientN = FRotator(ForwardQuat).Yaw;
CurrentOrient = OrientN;// FMath::FInterpConstantTo(OldOrient, OrientN, DeltaTime, 300.0f);
break;
}
case EFCardinalDirection::E:
{
FQuat LeftQuat = FQuat::FindBetween(Right, CurrentVelocity);
float OrientE = FRotator(LeftQuat).Yaw;
CurrentOrient = OrientE;// FMath::FInterpConstantTo(OldOrient, OrientE, DeltaTime, 300.0f);
break;
}
case EFCardinalDirection::S:
{
FQuat BackQuat = FQuat::FindBetween(Forward*(-1), CurrentVelocity);
float OrientS = FRotator(BackQuat).Yaw;
CurrentOrient = OrientS;
break;
}
case EFCardinalDirection::W:
{
FQuat RightQuat = FQuat::FindBetween(Right*(-1), CurrentVelocity);
float OrientW = FRotator(RightQuat).Yaw;
CurrentOrient = OrientW;// FMath::FInterpConstantTo(OldOrient, OrientW, DeltaTime, 300.0f);
break;
}
default:
break;
}

• It sounds like the issue here is in the coordination of your code that changes the cardinal direction and the code that changes the angle within it. Can you show us the relevant snippet of this code so we can give you feedback on it? – DMGregory Mar 4 '18 at 12:01
• I added code (at it's most base state). – Łukasz Baran Mar 4 '18 at 12:47