Log In  


Cart #52680 | 2018-05-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
12

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

12


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.


@morningtoast

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

Works like a charm! Thanks for the hookup.


Thanks, @Felice :+1:


Send this animation at once to Paramount Pictures and tell them to use it for one of the screens in the new upcoming Star Trek movie.

Those panels on the bridge are always showing cool animated stuff. 👍



[Please log in to post a comment]