How to gradually rotate a rigidbody towards a target without slowing down as it gets closer to the target?

I’ve been trying to solve this problem for a while now and I’m out of ideas. All solutions I find either don’t work or experience slow down as they get closer to the target angle (even if they say they don’t). I want the rotation to happen at a constant speed regardless of how much distance there is between the current angle and target angle.

Here is the code I have for the rotation now:

Quaternion target = Quaternion.LookRotation(currentInput.direction.normalized, Vector3.forward);

// Offset target to line it up with player's visual facing direction
target *= Quaternion.Euler(0f, 0f, FacingLeft ? 90f : -90f);

Body.MoveRotation(Quaternion.RotateTowards(transform.rotation, target, turnSpeed * Time.fixedDeltaTime));

EDIT: Doing this with a transform seems to work fine (except for rotation axis begin wrong):

Quaternion target = Quaternion.LookRotation(currentInput.direction.normalized, Vector3.forward);

// Offset target to line it up with player's visual facing direction
target *= Quaternion.Euler(0f, 0f, FacingLeft ? 90f : -90f);

transform.rotation = Quaternion.RotateTowards(transform.rotation, target, turnSpeed * Time.fixedDeltaTime);

Why does this particular aspect work fine with a transform but not with a rigidbody?

1 Like

The issue you’re facing is because Quaternion.RotateTowards inherently slows down as the current rotation gets closer to the target rotation. This happens because it calculates the shortest rotation path and applies a linear interpolation, which reduces the angular velocity as the difference decreases.

If you want a constant speed rotation regardless of the difference between the current and target rotations, you need to manually compute the angular velocity and apply it directly.

1 Like

Try this One.
void FixedUpdate()
{
Quaternion target = Quaternion.LookRotation(currentInput.direction.normalized, Vector3.forward);
target *= Quaternion.Euler(0f, 0f, FacingLeft ? 90f : -90f);

float step = turnSpeed * Time.fixedDeltaTime;
transform.rotation = RotateAtConstantSpeed(transform.rotation, target, step);

}

Quaternion RotateAtConstantSpeed(Quaternion current, Quaternion target, float step)
{
float angleDifference = Quaternion.Angle(current, target);

if (angleDifference > 0f)
{
    float t = Mathf.Min(1f, step / angleDifference);
    return Quaternion.Slerp(current, target, t);
}

return target;

}