I think I follow.
Let's say we have a canvas named "char" and some buttons that are meant to animate that canvas to their position.
We can give each button an identical script calling a helper function we will write called "seek" which takes three parameters: a thing to move (them), a widget giving a destination (there), and the number of frames the animation should take (steps):
on click do seek[char me 30] end
(Remember: "me" in this case will be each button itself!)
On the card (or possibly the Deck-level script), we'll define seek[] thusly:
on seek them there steps do a:them.pos b:(there.pos+.5*there.size)-.5*them.size each t in (range steps)/(steps-1) them.pos:a+t*b-a sleep[1] end end
The variables "a" and "b" store the initial position and the final position of "them", respectively. The expression:
there.pos+.5*there.size
Is the position of the destination plus half its size, which is to say its centerpoint. By subtracting half the size of "them" from the centerpoint of "there", we'll get the position which will center "them" on "there".
To tween the object smoothly from "a" to "b", we need to compute a series of uniform steps from 0 to 1. Consider the following examples:
(range 3)/2 # (0,0.5,1) (range 5)/4 # (0,0.25,0.5,0.75,1) (range 8)/7 # (0,0.142857,0.285714,0.428571,0.571429,0.714286,0.857143,1)
Given a time "t" between 0 and 1, we can linearly interpolate between "a" and "b" with:
a+(t*(b-a))
Which in Lil can be written more concisely as
a+t*b-a
Since arithmetic expressions have uniform precedence.
For extra fun, we could replace that linear interpolation with an easing function from Ease like "ease.inOutBack[]"
on seek them there steps do a:them.pos b:(there.pos+.5*there.size)-.5*them.size each t in (range steps)/(steps-1) them.pos:ease.inOutBack[t a b] sleep[1] end end
How's that?