I recently came up with a nice, flexible, mini-framework for dealing with on-the-fly animations in Unity. It was birthed out of a need to create quick lerp animations, by means of coroutines, that are framerate-independent and easy to work with. I’ll give the complete implementation in this multi-part post.

Background

Coroutines

Coroutines are an entire post in themselves, so I won’t go into them here. I will say that they are about as close as you can get to multi-threaded coding in Unity, without actually being multi-threaded. This post will assume basic knowledge of them, so if you don’t know what they are, I suggest you brush up on them before continuing (here is a good starting point).

Lerp

“Lerp” is short for “linear interpolation.” It’s a simple way to compute an intermediate value between two endpoints. Mathematically, it looks like this, for endpoints a and b and a fractional value of t between 0 and 1, inclusive:

You can see that when t = 0, the function will evaluate to a. When t = 1, the function will evaluate to b. And when t = 0.5, the function will evaluate to the midpoint between a and b ((a + b) / 2). You get the idea.

This general formula is used to lerp between values for a variety of types in Unity, including float, Vector2, Vector3, and Color (click here for a more exhaustive list).

A common misconception about the Lerp variants in Unity is that they will perform animation. This is not the case, as a lerp function merely computes a value between a and b – that’s it. To animate using a lerp, it must be combined with the powers of a coroutine:

IEnumerator LerpForTenSeconds()
{
    Vector3 start = Vector3.zero;
    Vector3 end = new Vector3(0f, 5f, 3f);
    float duration = 10f;
    float startTime = Time.time;
    float endTime = startTime + duration;

    while (Time.time <= endTime)
    {
        float t = (Time.time - startTime) / duration;

        transform.position = Vector3.Lerp(start, end, t);

        yield return null;
    }
}

Note that this is framerate-independent – that is, the animation will always take 10 seconds, no matter what. Unfortunately, there are a lot of examples out there (including in some Unity tutorials) that tell you to lerp with coroutines like this:

IEnumerator MoveToTarget()
{
    Vector3 targetPosition = new Vector3(2f, 10f, 6f);
    float someSpeedFactor = 1f;

    while ((transform.position - targetPosition).magnitude > 0.01f)
    {
        transform.position = Vector3.Lerp(transform.position, targetPosition, someSpeedFactor * Time.deltaTime)

        yield return null;
    }
}

Unfortunately, this is neither “linear” interpolation nor is it truly framerate-independent, despite using Lerp and Time.deltaTime. Because the current position, which is changing, is used as the start value in the lerp, the interpolation becomes more like an exponential interpolation.

Now, how about that framerate-dependence? If you don’t believe me (it’s OK if you don’t – it took me a while to join the dark side too), imagine that your framerate were always very low, say 2 frames per second. Then, after 1 second, the object would have only 25% of its original journey left (half the distance would be traveled with each iteration, so 0.52 = 0.25). Now, what if your framerate were 4 frames per second? After 1 second, the object would still have 32% of its original journey left (a quarter of the distance would be traveled with each iteration, so 0.754 = 0.3164). Because the object would be in different positions after 1 second, solely due to framerate differences, this implementation is framerate-dependent. For the mathematically inclined, refer to this plot, which represents the fraction of distance traveled after 1 second, as a function of framerate f, and note that it is clearly not constant.

Coming up

Now that we’re on the same page, what if we wanted to do many animations similar to LerpForTenSeconds() in our project but wanted to eliminate the need for writing all that boiler-plate code for looping and computing t? The next post will reveal a flexible implementation of a helper class to do just that.


unity animation coroutine lerp
PREV NEXT