Hello guys, I'm working on a short article for fanzine #5, and I'm going to talk about game feel. So I wrote this tiny library that is super helpful and allows you to simply tween any value in your objects with some cool math functions. Here is a small example:

function _init() -- the object that has your value p={ x=32,y=32 } -- the tween function, takes args: -- p - your object -- table - table with the target values you want -- 1 (optional) - time (in seconds) in what your value should end with your target value, default is 1 -- "quad_in_out" - easing function, you can look up all defined functions in the tab 1, I've implemented a few examples from https://easings.net/ local v=tween(p,{x=96,y=96},1,"quad_in_out") -- you can also define a function that will run at the end of tweening v.onend=function() stop() end -- and you can even set the delay before tweening you object! v.delay=0.2 end function _update60() -- just update the library, if you use _update, update value to 1/30 tween_update(1/60) end function _draw() cls() -- draw our circle! circfill(p.x,p.y,4,8) end |

**The minimum source code ~340 tokens**

-- tween engine -- by @egordorichev local back=1.70158 -- feel free to remove unused functions to save up some space functions={ ["linear"]=function(t) return t end, ["quad_out"]=function(t) return -t*(t-2) end, ["quad_in"]=function(t) return t*t end, ["quad_in_out"]=function(t) t=t*2 if(t<1) return 0.5*t*t return -0.5*((t-1)*(t-3)-1) end, ["back_in"]=function(t) local s=back return t*t*((s+1)*t-s) end, ["back_out"]=function(t) local s=back t-=1 return t*t*((s+1)*t+s)+1 end, ["back_in_out"]=function(t) local s=back t*=2 if (t<1) s*=1.525 return 0.5*(t*t*((s+1)*t-s)) t-=2 s*=1.525 return 0.5*(t*t*((s+1)*t+s)+2) end } local tasks={} function tween(o,vl,t,fn) local task={ vl={}, rate=1/(t or 1), o=o, progress=0, delay=0, fn=functions[fn or "quad_out"] } for k,v in pairs(vl) do local x=o[k] task.vl[k]={start=x,diff=v-x} end add(tasks,task) return task end function tween_update(dt) for t in all(tasks) do if t.delay>0 then t.delay-=dt else t.progress+=dt local p=t.progress*t.rate local x=t.fn(p>=1 and 1 or p) for k,v in pairs(t.vl) do t.o[k]=v.start+v.diff*x end if p>=1 then del(tasks,t) if (t.onend) t.onend() end end end end |

*update, fixed tasks not looking onto t var

I have a lua tip. It's probably not really for you, Egor, since you already know your stuff, but this is a good place to note it or remind people of it:

table = { ["key"] = value } v = table["key"] |

Is functionally identical to:

table = { key = value } v = table.key |

I know you're actually intending for your `functions`

table to be keyed by strings for the sake of simplicity of API use, rather than to have syntactically-sugared members as with an object, but this could save tokens in declaring the table inside of your library.

Also handy is that, if you're using picotool, one could `require()`

this code and then, if so desired, refer to tween.functions.linear directly, rather than tween.functions["linear"]. The former feels a little more familiar/standard.

Nice functionality btw. :) I'm putting this on my little shelf of useful code.

Hmm, good point, btw. Thanks ;) If you need any other function implementations just tell me. But those 7 are the most used by myself, at least.

I've found this library extremely useful in trying to make some paths for my shooter. However, I can't figure out how to adjust the speed of an object moving between points.

I see the third parameter of tween() but no matter what I change it to, they always move at the same speed. Or am I misunderstanding the purpose of that param?

I thought that parameter was the time the object took to get from A to B. So 1 meant 1 second...2 means 2 seconds...and so on. But maybe not?

Thanks for putting this together. I understand it and so far can better integrate with what I'm trying to do better than some other tween code I've tried before.

Looks like egor missed multiplying `dt`

by the `t.rate`

attribute in the update

As an aside, I think it would be better to store the time argument and divide by that, rather than creating rate=1/time in the constructor, since I'm wary of precision issues with PICO-8's fixed-point number format.

Drop this in and try adjusting that param again:

function tween(o,vl,t,fn) local task={ vl={}, time=t or 1, -- <=== changed o=o, progress=0, delay=0, fn=functions[fn or "quad_out"] } for k,v in pairs(vl) do local x=o[k] task.vl[k]={start=x,diff=v-x} end add(tasks,task) return task end function tween_update(dt) for t in all(tasks) do if t.delay>0 then t.delay-=dt else t.progress+=dt/t.time -- <=== changed local p=t.progress local x=t.fn(p>=1 and 1 or p) for k,v in pairs(t.vl) do t.o[k]=v.start+v.diff*x end if p>=1 then del(tasks,t) if (t.onend) t.onend() end end end end |

[Please log in to post a comment]