# Adding acceleration / deceleration to RotateTowards.

I have an object tracking another object via RotateTowards, like so:

Simple enough:

``````    float turnSpeed = 90.0f;

Vector3 target = tracking.position - transform.position;
Vector3 result = Vector3.RotateTowards(transform.forward, target, Mathf.Deg2Rad * turnSpeed * Time.deltaTime, 360.0f);

transform.rotation = Quaternion.LookRotation(result);
``````

I’d like to add some “weight” to the rotation by adding an acceleration and deceleration force, to prevent the arrow in the example from turning on a dime as it does when the green box is quickly passing overhead.

Ideas?

I’d like to suggest that you don’t necessarily need acceleration/deceleration… all you need is limited speed.

To do that, you would calculate the target rotation as you’re doing now, but instead of directly assigning it to transform.rotation, you would move the transform rotation towards the target at some speed:

``````Quaternion targetRot = Quaternion.LookRotation(result);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, speed * Time.deltaTime);
``````

Appreciate the response Joe but I’m already limiting the turn speed via Vector3.RotateTowards(), which works similarly to Quaternion.RotateTowards().

The problem is that both those functions turn at a certain (max) speed. They don’t accelerate or decelerate so the object feels like it has no “weight” to it. In the example gif, when I quickly move the target from the left side of the screen to the right, the arrow immediately stops and begins rotating the opposite direction.

There has to be a clever way to play with the speed / turn rate to fake these forces but I haven’t been able to come up with it.

Oops, so you are! That’s what I get for reading too quickly. Sorry about that.

OK, so you really do want acceleration. In that case, I think what you can do is (1) normalize your ‘target’ vector, and (2) use Vector3.SmoothDamp instead of Vector3.RotateTowards. That of course requires keeping around an extra velocity vector, which is what gives it the feeling of weight.

Of course SmoothDamp is directly tracking the target instead of rotating toward it… but I think that won’t matter, since you’re passing the result to Quaternion.LookRotation anyway.

That’s definitely a step in the right direction, here’s what it looks like (painfully slow for emphasis):

There’s just one issue: if the tracked target is exactly 180 degrees from the rotating object, it doesn’t move.

``````     Vector3 target = (tracking.position - transform.position).normalized;
Vector3 result = Vector3.SmoothDamp(transform.forward, target, ref velocity, 0.5f);

transform.rotation = Quaternion.LookRotation(result);
``````

Thanks for the help so far Joe.

Hmm. I guess in this case we’re essentially trying to move our .forward axis directly back on itself, which of course it can’t do.

Is this by any chance an essentially 2D problem? That is, are your arrow and target always in a plane? In that case we could just be working with (scalar) angles, and life might be easier.

I might be able to fudge it a bit with camera angles to make it seem that way, definitely. What’d you have in mind?

Well, in that case you can represent the position of the arrow as a single number (the angle), and its velocity as another number (clockwise degrees/sec). So, on each frame, you compute the angle to the target, with something like this:

``````    /// <summary>
/// Returns the signed angle between this 2D vector and another.
/// (This is unlike Vector2.Angle, which always returns the
/// absolute value of the angle.)
/// </summary>
/// <returns>The signed angle, in degrees, from A to B.</returns>
/// <param name="a">Vector this was called on.</param>
/// <param name="b">Vector to measure the angle to.</param>
public static float SignedAngleTo(this Vector2 a, Vector2 b) {
return Mathf.Atan2( a.x*b.y - a.y*b.x, a.x*b.x + a.y*b.y ) * Mathf.Rad2Deg;
}
``````

…then figure out which is the shortest way from your current angle to that target angle. And then you’ll just add a bit of that direction to your velocity.

Trouble is, I think you’re going to overshoot, and wobble around the target. So you’ll need some damping (just reduce the velocity by some small percentage on each frame).

It all seems stupidly complex, but it’s the best idea I can think of at the moment!

It’s working great now Joe – I used this code to calculate the delta angle:

``````    Quaternion lookRotation = Quaternion.LookRotation(target.position - transform.position);

Quaternion a = transform.rotation;
Quaternion b = lookRotation;

Vector3 vectorA = a * Vector3.forward;
Vector3 vectorB = b * Vector3.forward;

float angleA = Mathf.Atan2(vectorA.x, vectorA.z) * Mathf.Rad2Deg;
float angleB = Mathf.Atan2(vectorB.x, vectorB.z) * Mathf.Rad2Deg;

float delta = Mathf.DeltaAngle(angleA, angleB);
``````

And then apply some acceleration / deceleration forces and everything is working swimmingly.

I’ll try your function and see if I can optimize it a bit.