Easing and Tweening Scripts in GameMaker

Easing algorithms are something I know I will need in every single game I make. It could be for making items smoothly move onto the screen, make things bounce around in a natural way, highlighting buttons when they are selected etc etc.

GameMaker Easing and Tweening Functions

None of the images above have animated sprites, they are all static images that are moved with easing.

I’ve never found an easy way to explain what Easing and Tweening is but it’s basically gradually changing the speed something moves at rather than instantly changing its speed. However it doesn’t just have to be with movement, it could be with the angle or transparency etc. This video by Code Workshop explains easing far better than me.

If you are familiar with lerp() in GameMaker (linear interpolation) it’s like that, but rather than changing at a constant rate it changes with either an acceleration or deceleration.

I mostly use easing to smooth out animations so they don’t instantly start and stop but everything slides with a momentum.

Usage Example:

EaseInQuad(how far along the curve you want to find the value, the minimum output you want, the maximum output you want, what your maximum input could be)

EaseLinear (5,0,10,10) // output 5 because 50% of 10 is 5
EaseInCubic (5,0,10,10) // output 1.25 because 50% of the way up the curve is only 1.25 out of 10
Converting Linear Numbers Onto Curves with Easing:
GameMaker Easing Graph

At the very bottom of this document I will include some usage examples of how it can be used in animation.

If you want a GML script you can just import into your project you can download it here and it is identical to the code on this page with the option to either import as a tabbed script or multiple individual scripts.

Most of these functions were made by Robert Penner and I have converted them to run in GML so I have kept all of his original copyright messages in: http://robertpenner.com/easing/

The other resource I think is really important especially for new people or to help visualise this the easing is this website: http://easings.net/


All Easing Functions:
#define Default_Ease_Algorithms
/*
* TERMS OF USE - EASING EQUATIONS
* Open source under the BSD License.
* Copyright (c)2001 Robert Penner
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

ease-linear #define EaseLinear
/// EaseLinear(inputvalue,outputmin,outputmax,inputmax)
return argument2 * argument0 / argument3 + argument1;

ease-inquad #define EaseInQuad
/// EaseInQuad(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3;
return argument2 * argument0 * argument0 + argument1;

ease-outquad #define EaseOutQuad
/// EaseOutQuad(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3;
return -argument2 * argument0 * (argument0 - 2) + argument1;

ease-inoutquad #define EaseInOutQuad
/// EaseInOutQuad(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1)
{
    return argument2 * 0.5 * argument0 * argument0 + argument1;
}

return argument2 * -0.5 * (--argument0 * (argument0 - 2) - 1) + argument1;

ease-incubic #define EaseInCubic
/// EaseInCubic(inputvalue,outputmin,outputmax,inputmax)
return argument2 * power(argument0/argument3, 3) + argument1;

ease-outcubic #define EaseOutCubic
/// EaseOutCubic(inputvalue,outputmin,outputmax,inputmax)
return argument2 * (power(argument0/argument3 - 1, 3) + 1) + argument1;

ease-inoutcubic #define EaseInOutCubic
/// EaseInOutCubic(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1)
{
   return argument2 * 0.5 * power(argument0, 3) + argument1;
}

return argument2 * 0.5 * (power(argument0 - 2, 3) + 2) + argument1;

ease-inquart #define EaseInQuart
/// EaseInQuart(inputvalue,outputmin,outputmax,inputmax)
return argument2 * power(argument0 / argument3, 4) + argument1;

ease-outquart #define EaseOutQuart
/// EaseOutQuart(inputvalue,outputmin,outputmax,inputmax)
return -argument2 * (power(argument0 / argument3 - 1, 4) - 1) + argument1;

ease-inoutquart #define EaseInOutQuart
/// EaseInOutQuart(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1) 
{
    return argument2 * 0.5 * power(argument0, 4) + argument1;
}

return argument2 * -0.5 * (power(argument0 - 2, 4) - 2) + argument1;

ease-inquint #define EaseInQuint
/// EaseInQuint(inputvalue,outputmin,outputmax,inputmax)
return argument2 * power(argument0 / argument3, 5) + argument1;

ease-outquint #define EaseOutQuint
/// EaseOutQuint(inputvalue,outputmin,outputmax,inputmax)
return argument2 * (power(argument0 / argument3 - 1, 5) + 1) + argument1;

ease-inoutquint #define EaseInOutQuint
/// EaseInOutQuint(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1)
{
    return argument2 * 0.5 * power(argument0, 5) + argument1;
}

return argument2 * 0.5 * (power(argument0 - 2, 5) + 2) + argument1;

ease-insine #define EaseInSine
/// EaseInSine(inputvalue,outputmin,outputmax,inputmax)
return argument2 * (1 - cos(argument0 / argument3 * (pi / 2))) + argument1;

ease-outsine #define EaseOutSine
/// EaseOutSine(inputvalue,outputmin,outputmax,inputmax)
return argument2 * sin(argument0 / argument3 * (pi / 2)) + argument1;

ease-inoutsine #define EaseInOutSine
/// EaseInOutSine(inputvalue,outputmin,outputmax,inputmax)
return argument2 * 0.5 * (1 - cos(pi * argument0 / argument3)) + argument1;

ease-incirc #define EaseInCirc
/// EaseInCirc(inputvalue,outputmin,outputmax,inputmax)
// This is a really radical curve... haha hidden programmer joke.
argument0 /= argument3;
return argument2 * (1 - sqrt(1 - argument0 * argument0)) + argument1;

ease-outcirc #define EaseOutCirc
/// EaseOutCirc(inputvalue,outputmin,outputmax,inputmax)
argument0 = argument0 / argument3 - 1;
return argument2 * sqrt(1 - argument0 * argument0) + argument1;

ease-inoutcirc #define EaseInOutCirc
/// EaseInOutCirc(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1)
{
    return argument2 * 0.5 * (1 - sqrt(1 - argument0 * argument0)) + argument1;
}

argument0 -= 2;
return argument2 * 0.5 * (sqrt(1 - argument0 * argument0) + 1) + argument1;

ease-inexpo #define EaseInExpo
/// EaseInExpo(inputvalue,outputmin,outputmax,inputmax)
return argument2 * power(2, 10 * (argument0 / argument3 - 1)) + argument1;

ease-outexpo #define EaseOutExpo
/// EaseOutExpo(inputvalue,outputmin,outputmax,inputmax)
return argument2 * (-power(2, -10 * argument0 / argument3) + 1) + argument1;

ease-inoutexpo #define EaseInOutExpo
/// EaseInOutExpo(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3 * 0.5;

if (argument0 < 1) 
{
    return argument2 * 0.5 * power(2, 10 * --argument0) + argument1;
}

return argument2 * 0.5 * (-power(2, -10 * --argument0) + 2) + argument1;

ease-inelastic #define EaseInElastic
/// EaseInElastic(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;
var _p = 0;
var _a = argument2;

if (argument0 == 0 || _a == 0) 
{
    return argument1; 
}

argument0 /= argument3;

if (argument0 == 1) 
{
    return argument1+argument2; 
}

if (_p == 0) 
{
    _p = argument3*0.3;
}

if (_a < abs(argument2)) 
{ 
    _a = argument2; 
    _s = _p*0.25; 
}
else
{
    _s = _p / (2 * pi) * arcsin (argument2 / _a);
}

return -(_a * power(2,10 * (--argument0)) * sin((argument0 * argument3 - _s) * (2 * pi) / _p)) + argument1;

ease-outelastic #define EaseOutElastic
/// EaseOutElastic(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;
var _p = 0;
var _a = argument2;

if (argument0 == 0 || _a == 0)
{
    return argument1;
}

argument0 /= argument3;

if (argument0 == 1)
{
    return argument1 + argument2;
}

if (_p == 0)
{
    _p = argument3 * 0.3;
}

if (_a < abs(argument2)) 
{ 
    _a = argument2;
    _s = _p * 0.25; 
}
else 
{
    _s = _p / (2 * pi) * arcsin (argument2 / _a);
}

return _a * power(2, -10 * argument0) * sin((argument0 * argument3 - _s) * (2 * pi) / _p ) + argument2 + argument1;

ease-inoutelastic #define EaseInOutElastic
/// EaseInOutElastic(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;
var _p = 0;
var _a = argument2;

if (argument0 == 0 || _a == 0)
{
    return argument1;
}

argument0 /= argument3*0.5;

if (argument0 == 2)
{
    return argument1+argument2; 
}

if (_p == 0)
{
    _p = argument3 * (0.3 * 1.5);
}

if (_a < abs(argument2)) 
{ 
    _a = argument2; 
    _s = _p * 0.25; 
}
else
{
    _s = _p / (2 * pi) * arcsin (argument2 / _a);
}

if (argument0 < 1)
{
    return -0.5 * (_a * power(2, 10 * (--argument0)) * sin((argument0 * argument3 - _s) * (2 * pi) / _p)) + argument1;
}

return _a * power(2, -10 * (--argument0)) * sin((argument0 * argument3 - _s) * (2 * pi) / _p) * 0.5 + argument2 + argument1;

ease-inback #define EaseInBack
/// EaseInBack(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;

argument0 /= argument3;
return argument2 * argument0 * argument0 * ((_s + 1) * argument0 - _s) + argument1;

ease-outback #define EaseOutBack
/// EaseOutBack(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;

argument0 = argument0/argument3 - 1;
return argument2 * (argument0 * argument0 * ((_s + 1) * argument0 + _s) + 1) + argument1;

ease-inoutback #define EaseInOutBack
/// EaseInOutBack(inputvalue,outputmin,outputmax,inputmax)
var _s = 1.70158;

argument0 = argument0/argument3*2

if (argument0 < 1)
{
    _s *= 1.525;
    return argument2 * 0.5 * (argument0 * argument0 * ((_s + 1) * argument0 - _s)) + argument1;
}

argument0 -= 2;
_s *= 1.525

return argument2 * 0.5 * (argument0 * argument0 * ((_s + 1) * argument0 + _s) + 2) + argument1;

ease-inbounce #define EaseInBounce
/// EaseInBounce(inputvalue,outputmin,outputmax,inputmax)
return argument2 - EaseOutBounce(argument3 - argument0, 0, argument2, argument3) + argument1

ease-outbounce #define EaseOutBounce
/// EaseOutBounce(inputvalue,outputmin,outputmax,inputmax)
argument0 /= argument3;

if (argument0 < 1/2.75)
{
    return argument2 * 7.5625 * argument0 * argument0 + argument1;
}
else
if (argument0 < 2/2.75)
{
    argument0 -= 1.5/2.75;
    return argument2 * (7.5625 * argument0 * argument0 + 0.75) + argument1;
}
else
if (argument0 < 2.5/2.75)
{
    argument0 -= 2.25/2.75;
    return argument2 * (7.5625 * argument0 * argument0 + 0.9375) + argument1;
}
else
{
    argument0 -= 2.625/2.75;
    return argument2 * (7.5625 * argument0 * argument0 + 0.984375) + argument1;
}


ease-inoutbounce #define EaseInOutBounce
/// EaseInOutBounce(inputvalue,outputmin,outputmax,inputmax)
if (argument0 < argument3*0.5) 
{
    return (EaseInBounce(argument0*2, 0, argument2, argument3)*0.5 + argument1);
}

return (EaseOutBounce(argument0*2 - argument3, 0, argument2, argument3)*0.5 + argument2*0.5 + argument1);




Easing Animation Example:

That’s the end of all the easing functions I have. Let’s look at how you can use that in an example.

This is the code to animate this button bounce.

GameMaker Easing Animation
CREATE:
/// animation engine 

buttonwidth = 120 
buttonheight = 26

frame = 0 
framesmax[1] = 20 // heading towards the button
framesmax[2] = 20 // squishing against the button 
framesmax[3] = 20 // going back 
framesmax[4] = 20 // bouncing out

part = 1 // what part of the animation we are on 

distancebounce = 30
strechamountx = 0.4
strechamounty = 1.0

STEP:

frame++

if (frame >= framesmax[part]) { // this part of the animation has finished move onto the next one
    part++
    frame = 0
    
    if (part >= array_length_1d(framesmax)) { // the whole animation has finished so reset the whole thing
        part = 1
    }
}

DRAW:

switch (part)
{
    case 1: 
        var distance = distancebounce-EaseInCubic(frame, 0, distancebounce, framesmax[part])
        draw_sprite_ext(spr_buttonselect, 0,x-distance,y,1,1,0,c_white,1)
    break;
    case 2: 
        var strechh = 1-(EaseOutCubic(frame,1,100,framesmax[part])/100)*strechamountx
        var strechv = EaseOutCubic(frame,1,strechamounty/2,framesmax[part])
        draw_sprite_ext(spr_buttonselect, 0,x,y,strechh,strechv,0,c_white,1)
    break;
    case 3: 
        var strechh = (1-(EaseOutCubic(framesmax[part]-frame,1,100,framesmax[part])/100)*strechamountx)
        var strechv = EaseOutCubic(framesmax[part]-frame,1,strechamounty/2,framesmax[part])
        draw_sprite_ext(spr_buttonselect, 0,x,y,strechh,strechv,0,c_white,1)
    break;
    case 4: 
        var distance = EaseOutCubic(frame, 0, distancebounce, framesmax[part])
        draw_sprite_ext(spr_buttonselect, 0,x-distance,y,1,1,0,c_white,1)
    break;
}
Easing Dave
About the Article:
Easy Difficulty
GameMaker
By David Strachan