Cookbook, Uncategorized, Unity3D

Unity3D Cookbook: Lerp

Let’s take a look at some common problems and anti-patterns when using lerp in Unity, and how to correct them.

Anti-pattern #1: lerping with Time.time

We want to move a GameObject to a target point over time, so we lerp between a starting point and a destination, using Time.time as the t value.

The Problem

As discussed previously, the lerp function produces a value that is some percentage of the distance between two known points, where that percentage is represented by a number in the range of 0 to 1 inclusive. Time.time represents the number of seconds since the start of the game, and quickly becomes greater than 1!

The Solution

Cache the time that the operation started, and use that and the desired duration of movement to calculate how far along you are.

Anti-pattern #2: lerping in place

This is a similar problem to #1, but can be even more subtle. We want to change some member property in our script from its current value to a target value, so we update the property in place. This is commonly coupled with using Time.deltaTime as the t value (see the next section).

The Problem

Unpredictable movement along the interpolated points; reaching the target position too quickly.

The Solution

Remember that linear interpolation operates predictably between known, fixed points. Calling lerp will always produce the same value when the same endpoints and t value are used. When you update one of the values in place, you’re effectively “sliding” one of the endpoints, which means that calling lerp with the same t value will produce a slightly different result. Done in a 60 fps loop, these errors can add up to produce noticeable effects on gameplay. The solution is, again, caching: in addition to caching when you started lerping, also store the initial value of whatever you’re lerping.

Anti-pattern #3: lerping with Time.deltaTime

Used along with lerping in place, we again want to move a given value toward a target over time, so we pass Time.deltaTime as our t value.

The Problem

This usage of lerp can produce questions about behavior such as “my object never reaches its destination,” or “my game object slows down as it nears its destination.” The accumulation of rounding errors can eventually cause the object to “cross the gap” and reach its destination, but there is no guarantee of that, especially if we are relying on exact comparisons (transform.position.Equals(targetPosition)) to determine if we should execute further game logic.

The Solution

Time.deltaTime produces small values representing the number of seconds it took the last game frame to run. When the game is running at 60 fps, this number is very small: typically around 1 / 60, or 0.016667 seconds. When passed to lerp as something like lerp(a, b, Time.deltaTime), we are essentially saying “give me the value that is ~1.6% of the distance between a and b“. If we weren’t updating our lerped value in place, we would see the results jittering ever so slightly near the starting point. The only reason it works at all is, again, because we are “sliding” the starting point gradually toward the destination point.

The solution is the same as previous: instead of using Time.deltaTime and updating in place, cache the starting value and timestamp, and calculate progress based on those. If, for whatever reason, you must use Time.deltaTime, you can accumulate it into a variable to accomplish nearly the same effect: