Writing our own Tween easing (and looping?) functions

I just noticed on the wiki page for Codea’s Tween API that we can write our own easing functions for Tween.

This is the template from the wiki page:


-- t is the current time
-- d is the duration of the animation
-- b is the initial animated value
-- c is the change in the animated value by the end of the animation
function myEasing(t, b, c, d)
    local result
    ... -- Code to calculate result
    return result
end

It seems to be fairly close to this: https://github.com/kikito/tween.lua

What I wanted to ask is, would it also be possible to write a tween looping function in a similar way? Specifically I would like to write a pingpong.once function. If so, what would the template look like? (It’d be great if we could see the source for the existing pingpong function, assuming it is implemented in Lua)

i know it is not exactly what you ask for, but just in case you only need a pingpong once function, try this:

-- pingpongOnce

-- Use this function to perform your initial setup
function setup()
    a = {x=100,y=100,w=50,h=50}
    pingpongOnce(2, a, {x=300} )
    
end
function pingpongOnce(time, subject, target,...)
    local back = {}
    for k,v in pairs(target) do back[k] = subject[k] end
    tween(time, subject, target,...)
    local arg = arg or {}
    tween.delay(time,function() tween(time, subject, back,unpack(arg)) end)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    rect(a.x, a.y, a.w, a.h)
end


@Jmv38 Wow, that is very clever.

^:)^

Thank you!

This is easier for me to understand and does the same thing.


function setup()
    p1={x=50,y=50}
    p2={x=400,y=600}
    p3={x=50,y=50}
    rec={x=50,y=50,w=50,h=50}
    tween1()
end

function tween1()
    tween.path(5,rec,{p1,p2,p3})
end

function draw()
    background(40, 40, 50)
    fill(255)
    rect(rec.x,rec.y,rec.w,rec.h)
end

i agree

@Jmv38 Actually, it can be shortened by eliminating p3 and just reusing p1 in the tween.path since we’re going back to the starting point.


function setup()
    p1={x=50,y=50}
    p2={x=400,y=600}
    rec={x=50,y=50,w=50,h=50}
    tween1()
end

function tween1()
    tween.path(5,rec,{p1,p2,p1})
end

function draw()
    background(40, 40, 50)
    fill(255)
    rect(rec.x,rec.y,rec.w,rec.h)
end

@dave1707 I keep forgetting about tween.path… I’m experimenting with it now. Although maybe a tween.sequence might be closer to a pingpong.once as path adds a spline

This is slightly off-topic, but one thing that I think is odd about tweens is that when they’re called as part of a class, and you want the callback to be a function of that class, you have to wrap it in an anonymous function. ie:

tween(1, self, {pos=newpos}, tween.easing.SineInOut, self:myFunction()) --the function is called immediately, rather than after the tween
tween(1, self, {pos=newpos}, tween.easing.SineInOut, self.myFunction(self)) --ditto
tween(1, self, {pos=newpos}, tween.easing.SineInOut, self.myFunction) --function is called at the right time, but doesn't have access to self, returns an error if self is called
tween(1, self, {pos=newpos}, tween.easing.SineInOut, function() self:myFunction() end) --success! function must be wrapped in an anonymous function to execute properly

It just seems slightly wasteful, given that advice on optimising Lua recommends not repeatedly creating closures:

http://lua-users.org/wiki/OptimisationCodingTips

Or are repeated anonymous functions (ie you have lots of tweens firing at once) not such an issue performance wise? Am I worrying unnecessarily here?

@yojimbo2000 it’s necessary in order to bind self to the function. If you wrote your function as a static method (i.e., no access to self) then you could just pass the function name.

@Simeon and is it possible to add our own looping functions, like we can with easing?