7 Lerping tricks you need to know as a Game Developer

Linear Interpolation or lerping is a mathematical function which interpolates between two values. The interpolation amount is varied by passing a weight factor along with the start and end values. Linear interpolation is used in many areas of game development for movement, rotation, scale and everywhere you can think of. This article is about 7 lerping tricks you need to know as a game developer.

Value between two numbers

This is the core implementation of interpolation where we get a value between two numbers according to the weight factor. Take a look at the lerping function.

float lerp(float v0, float v1, float t) {
    return (1 - t) * v0 + t * v1;

Nice little one, right? Yeah and this is responsible for most of the movement and animations in a game.

It is so simple that if we pass two numbers, let’s say 100 and 200, and the weight factor(t) of 0.5, we get the number 150. As the weight factor, 0 represents the minimum and 1 represents the maximum number. So 0.5 is the middle of the two.

lerp(0.0, 1.0, 0.5)   ===>  0.5

lerp(100, 300, 0.1) ===> 120

lerp(10, -20, 0.9) ===>  -17

Game engines already provide the API to lerp between various types of values. The basic lerp between numbers in different game engines is shown below.

How to lerp in Unity

Mathf.Lerp(10f, 50f, 0.8f);

How to lerp in Godot

lerp(10, 20, 0.3)

How to lerp in Phaser

Phaser.Math.linearInterpolation([0, 100], 0.6)

Position between two positions

This is similar to the previous one but the data type is a Vector. A position is represented as a vector and the lerp function will also return a vector. If the vector is a 2D vector, then the result will be on the same 2D plane. If it is 3D, then the result will be in 3D space.

Also Read:   Godot Engine - Movement and Rotation basics


Vector3 midPoint = Vector3.Lerp(startPoint, endPoint, 0.5f);


var mid_point = start_point.linear_interpolate(end_point, 0.5)

Direction vector between two vectors

We know that a vector can represent directions. So what if we lerp two direction vectors? Yes, it will return a direction vector between given two vectors.  So the next time when you want to get a top right diagonal direction, lerp between forward and right direction vectors.


Vector3 topRightDir = Vector3.Lerp(transform.forward,transform.right,0.5f);


var forward_dir = get_transform().basis.z
var left_dir = get_transform().basis.x
var mid_forward_left_dir = forward_dir.linear_interpolate(left_dir, 0.5)

Animated lerping

When we call the lerp method, it is static which means we only get a single value. Call it on every frame by changing the weight value and it will be animated. So when we want to move an object from A to B, we can change the weight gradually from 0 to 1 and the object will move from A to B. In the place of A, if we put the current value, and make the weight constant, the animation will end in a smooth curve.

Let us consider this example,

current_pos = lerp(current_pos, end_pos, 0.5)

When we call the above one, the object will move half way between the two positions. Then on the next frame, the start position is now in the middle and it moves the half way between the middle and the end point. This calculation continues and the object arrives smoothly.

Also Read:   Decouple game objects using Godot signals

This type of lerp animation is used when we don’t require any precise timing. Examples are UI and button appear tweens, score value tweens etc.

Lerping with precise timing

Let us see if we can animate with precise timing. For that we need to calculate the weight value according to the passed time.

weight = currentTime/totalTime

And update the currentTime every frame like this,

currentTime += delta

Done, we have lerp with timing. The delta is delta time between current and previous frames. In Unity, it is Time.deltaTime and in Godot, it is delta (only available inside _update() callback).

Lerping tricks every game developer should learn Click To Tweet

Let us look at some examples.

float currentTime = 0f;
float totalTime = 3f;

float startValue = 0f;
float targetValue = 500f;
// Update is called once per frame
void Update () {
    float amt = currentTime/totalTime;
    amt = Mathf.Clamp01(amt);
    currentTime += Time.deltaTime;
    float value = Mathf.Lerp(startValue,targetValue,amt);
var current_time = 0
var total_time = 3

var start_pos
var end_pos

func _ready():
    start_pos = get_translation()
    end_pos = get_translation() + Vector3(0,0,5)

func _process(delta):
    var amt = current_time/total_time
    current_time += delta
    amt = clamp(amt,0,1)
    var pos = start_pos.linear_interpolate(end_pos,amt)

Smoothing the weight

What if we could tweak the weight value before feeding into the lerp function? Here come some formulae to try.

w = w * w

w = 3 * (w * w) - 2 * (w * w * w)

Know more about these smoothing functions here.

Also Read:   Fix CSS caching on Wordpress

Lerp inside tween updates

Another nice use for the lerp is to interpolate between multiple values according to a single weight value. We know that most of the engines have tweening systems – either built-in or from a third party. We could put a built-in or custom tween from 0 to 1 and inside the tween’s update, we will use the current value to lerp multiple things at once. We can use the value for tweening movement while changing its alpha and scale. Or tween the rotation while scaling down, the possibilities are only limited to our imagination. Let’s see some examples.

//Pseudo code

//Start tween from 0 to 1 and complete in 5 seconds
tween.start(0,1,5,on_tween_update);  //Also added an on_tween_update callback

on_tween_update(current_value){ //current_value changes from 0 to 1 within 5 seconds
    lerp(start_scale, end_scale, current_value);
    lerp(start_alpha, end_alpha, current_value);
    lerp(start_pos, end_pos, current_value);

So what are you waiting for? Implement these tricks on your game, move the UI, fade in the panels, roll the scores and make the whole game really juicy and attractive. See you next time.

[Total: 4    Average: 4.5/5]