# Linear Interpolation (lerp)

##### February 15th, 2020

It’s super useful, and can be used for all sorts of things. With a higher constant, it’s a good way to smooth out jittery input from a mouse or joystick. With a low constant, it’s a nice way to smoothly animate a progress bar or a camera following a player. It will never overshoot the target value even if it’s changing, and it changes the speed based on how far away it is so it will always quickly converge on the target. Pretty good for a one liner!

He states the standard use as:

``````value = lerp(value, targetValue, 0.1);
``````

And then the improved version as:

Let’s replace the simple lerp constant with an exponential function that involves time, and see how it works.

``````// exp() works just as well, probably with little to no measurable performance difference.
value = lerp(target, value, exp2(-rate*deltaTime))
``````

In this version, rate controls how quickly the value converges on the target. With a rate of 1.0, the value will move halfway to the target each second. If you double a rate, the value will move in twice as fast. If you halve the rate, it will move in half as fast. Couldn’t be easier.

Even better, it’s framerate independent. If you lerp this way 60 times with a delta time of 1/60 s, it will be the same result as lerping 30 times with 1/30 s, or once with 1 s. No fixed time step required nor the jittery movement it causes. However, do keep in mind that if your target value is changing over time (such as one object following another) you won’t get the exact same behavior. It’s close enough for many uses though.

https://github.com/dclelland/Lerp/blob/master/Lerp.swift

But also recall easing functions from YUI as implemented in Lua for word game.

``````import('gamecore/timer/timer')
simpleClass = require 'loop.simple'

t_constants = {
types = {
ease_in_and_out,
ease_in,
ease_out,
linear,
}
}
game.transition = simpleClass.class{
type = t_constants.types.ease_in_and_out,
length = 1.0,
pause = false,
}

game.transition.constants = t_constants
t_constants = nil

function game.transition:__init( object)
if object.from == nil then error("Transition expected 'from' values") end
if object.to == nil then error("Transition expected 'to' values") end
object.easing = object.easing or game.transition.easing.easeBoth
object.bounce = object.bounce or false

local result = simpleClass.rawnew( self, object)
result.current = {}
for k, v in pairs( result.from) do
result.current[k] = result.from[k]
end
result.start_time = getTime()
result.now_time = result.start_time
result.end_time = result.start_time + result.length
result.percent_complete = 0 -- from 0 to 1.0
result.raw_percent_complete = 0
return result
end

if not self.done then
if not pause or not self.pause then
if forceComplete then
self.now_time = self.end_time
end
end
if self.now_time >= self.end_time then
self.done = true
self.raw_percent_complete = 1.0
--self.percent_complete = 1.0
self.percent_complete = self.easing( self.raw_percent_complete, 0, 1, 1)

if self.final == nil then self.final = self.to end
for k, v in pairs( self.from) do
self.current[k] = self.final[k]
end
else
self.raw_percent_complete = self.now_time - self.start_time
self.raw_percent_complete = self.raw_percent_complete / self.length
self.percent_complete = self.raw_percent_complete
self.percent_complete = self.easing( self.raw_percent_complete, 0, 1, 1)
for k, v in pairs( self.from) do
self.current[k] = self.from[k] + ((self.to[k] - self.from[k]) * self.percent_complete)
end
end
if self.updateFunction ~= nil then
self.updateFunction( self.object, self)
end
if self.done and self.completeFunction ~= nil then
self.completeFunction( self.object, self)
end
end
end

local newTransition = game.transition( object)
table.insert( game.timer.current, newTransition)
newTransition:update( 0)
end

game.transition.easing = {}
game.transition.easing.easeBoth = function( t, b, c, d)
local result
local tt = t / (d / 2)
if tt < 1 then
result = c/2*tt*tt+b
else
t = tt - 1
result = -c/2*(t*(t-2)-1) + b
end
return result
end

game.transition.easing.easeIn = function( t, b, c, d)
local tt = t / d
return c * (tt) * (tt) + b
end

game.transition.easing.easeOut = function( t, b, c, d)
local tt = t / d
return -c * (tt) * (tt-2) + b
end

game.transition.easing.easeBounce = function( t, b, c, d)
local result
if t < .5 then result = game.transition.easing.easeOut( t * 2, b, c, d)
else result = game.transition.easing.easeOut( 1 - ((t - .5) * 2), b, c, d)
end
return result
end

game.transition.easing.bounceOut = function( t, b, c, d)
local result
t = t / d
if ((t) < (1/2.75)) then
result =  c*(7.5625*t*t) + b;
elseif (t < (2/2.75)) then
t = t - (1.5/2.75)
result = c*(7.5625*(t)*t + .75) + b;
elseif (t < (2.5/2.75)) then
t = t - (2.25/2.75)
result = c*(7.5625*(t)*t + .9375) + b;
else
t = t -(2.625/2.75)
result = c*(7.5625*(t)*t + .984375) + b;
end
return result
end

game.transition.easing.bounceIn = function( t, b, c, d)
return c - game.transition.easing.bounceOut(d-t, 0, c, d) + b;
end

-- Backtracks slightly, then reverses direction and moves to end
game.transition.easing.backIn = function (t, b, c, d, s) -- s is optional; how far to overshoot
if (s == nil) then
s = 1.70158;
end
t = t / d
return c*(t)*t*((s+1)*t - s) + b;
end

game.transition.easing.backOut = function(t, b, c, d, s) -- s is optional; how far to overshoot
if (s == nil) then
s = 1.70158;
end
t = t / d - 1
return c*((t)*t*((s+1)*t + s) + 1) + b;
end
``````