Unity Lerp with Coroutines and Animation Curves

Unity lerp with coroutines
News / Tips

Unity Lerp with Coroutines and Animation Curves

 

Unity Lerp with coroutines is one of the common ways to provide steps of a transition and calculated over time can convey the virtual movements of an object for each consecutive frame. In this article, we will provide a step by step guide to get familiar with the right way of their usage. For more information or other articles from Rubicom check out our blog.

To move objects along multiple axes, rotate around axes, or scale along axes, we simply use interpolation of multiple properties. Unity provides methods to achieve this. Mathf.Lerp() for any single floating point number or axis interpolation, Vector2.Lerp()/Vector3.Lerp() for two- and three-axis interpolation, and Quaternion.Lerp() for rotational interpolation.

Unity lerp with coroutines -isolating animation

Using coroutines within Unity allows components to trigger functions that will run for every following frame, very much like the Update() which can be seen in all MonoBehaviour scripts.  To create a coroutine we would need to use an IEnumetator.

Example:

IEnumerator  UpdateAnimationPosition(){

while (true)  {   yield return null;  }}

The function of yield return null, in this case, is to simply tell Unity to continue from this line onto the next frame. To benefit from continuous iteration it is common to use yield methods within loops. In the current example above we are not providing functionality in the loop, as well as the current loop will run forever since true will always be true.

IEnumerator UpdateAnimationPosition (float time){

float journey = 0f;

while (true)

{

journey = journey + Time.deltaTime;

Debug.Log(Mathf.Clamp01(journey / time));

yield return null;

}

}

Adding time value we now can tell the destination for the animation. In each frame, we increment the journey value with Time.deltaTime to represent the current progression.  Printing a division of the two provides us with the percentage through the animation’s journey in each frame.

The current coroutine enumerator would still run endlessly, printing the output of 1 once the clamped journey reaches and exceeds the total time.

IEnumerator UpdateAnimationPosition(float time){

float journey = 0f;

while (journey <= time)  {

journey = journey + Time.deltaTime;

float percent = Mathf.Clamp01(journey / time);

yield return null;  }}

The clamped value can be assigned to percent and we can observe that the comparison of the two source values is possible to be used to determine if the loop has any more frames left.

The condition journey <= time can be a replacement for our already existing while(true) placeholder and the loop will now exit on the right time.

However, the coroutine still doesn’t do anything.

IEnumerator UpdateAnimationPosition(Vector3 origin, Vector3 target, float time)

{

float journey = 0f;

while (journey <= time)

{

journey = journey + Time.deltaTime;

float percent = Mathf.Clamp01(journey / time);

transform.position = Vector3.Lerp(origin, target, percent);

yield return null;

}

}

We now have 2 parameters defined which we provide to the Vector3.Lerp with percent to interpolate between the 2 points. We should be able to execute this as a coroutine such as:

void MoveTo(Vector3 target, float duration)

{

StartCoroutine(AnimateMove(transform.position, target, duration));

}

Now what we have is a flexible and isolated animation method for an object’s position. The reusable flow of journey and percent make time-based animation consistent and precise for coroutines.

Non-linear interpolation

Libraries, such as DOTween and Mathfx, are excellent in assisting with common animation curves. Alternatively, we can use Inspector-friendly AnimationCurve to visually define our animation flow throughout the time:

public AnimationCurve animationCurve;

IEnumerator AnimateMove(Vector3 origin, Vector3 target, float duration)

{

// …

float curvePercent = animationCurve.Evaluate(percent);

transform.position = Vector3.LerpUnclamped(origin, target, curvePercent);

// …

}

By defining curvePercent, against a public AnimationCurve in our component, we make it possible to use the curve to show the variation of the interpolation for faster take off, intermittent jitters, tapered slow down or anything else.

When editing an Animation Curve, be sure the start and end points go from (0,0) to (1,1). The linear preset is a perfect template to begin adding and modifying keys

Best of all, all curves will adapt to the time provided by your coroutine argument, adding even more flexibility and re-usability.

Serialised curves

Along with saving libraries of curves for reuse or to package with a project, Unity’s visual editor is sufficient to design curves, but our scripts can also define curve defaults or presents directly.

public AnimationCurve linearCurve = new AnimationCurve(

new Keyframe(0, 0, 1, 1),

new Keyframe(1, 1, 1, 1)

);

public AnimationCurve easingInOutCurve = new AnimationCurve(

new Keyframe(0, 0),

new Keyframe(1, 1)

);

Curves can be instantiated with any amount of keyframes to represent the path.

 

Source: 

Leave your thought here

Your email address will not be published.

10 + six =