This module provides Animators (or anims for short) for Rabbyt.
Anims are little objects that can implement a movement function, primarily meant to animate sprites. The movement functions are all implemented in C, so your sprites can be animated without any python call overhead.
For example, to linearly interpolate a sprite from x=0 to x=100 over the next second, you can do this:
sprite.x = rabbyt.lerp(0, 100, dt=1)
Looks like magic?
It is! Sorta...
The Sprite class's x attribute is really a property. If you assign an anim to it, that anim will be called for it's value every time the sprite needs it's x position. Nearly all of Sprite's properties work like this.
Anims support various arithmatic opperations. If you add two together, or add one with a constant number, a new anim will be returned. Here is a rather contrived example of doing that:
sprite.x = rabbyt.lerp(0, 100, dt=1) + 20
(In this case, you would be better off interpolating from 20 to 120, but whatever.)
Here is a more useful example:
sprite2.x = sprite1.attrgetter('x') + 20
That will cause sprite2's x position to always be 20 more than sprite1's x position. (Sprite.attrgetter() returns an anim that gets an attribute.) This all happens in compiled C code, without any python call overhead. (That means you can have thousands of sprites doing this and it will still be fast.)
But sometimes you don't really need that much speed. You can use any python function as an anim as well. This example does the same as the last one:
sprite2.x = lambda: sprite1.x + 20
(Sprite.x will automatically wrap the function in an AnimPyFunc instance behind the scenes.)
You can use anims in your own class by subclassing from Animable and using the anim_slot descriptor. For example, a simple sprite class could start like this:
class MySprite(rabbyt.Animable): x = rabbyt.anim_slot() y = rabbyt.anim_slot() xy = rabbyt.swizzle('x', 'y')
The x, y, and xy attributes will behave the just like they do in rabbyt's Sprite class.
Sets the time that get_time() should return.
If you are using any time based animations, (such as lerp(),) you should call this function every frame.
For example, if you are using pygame you can do this:
Using this function should make it easier to implement a pause feature.
Note that rabbyt makes no assumption about the unit that the time is in. You can use milliseconds or seconds or even something else. It's up to you.
Gets the time that was last set by set_time()
Adds t to the ... time ... (Is it just me or does that sound dorky?)
This is really just a short cut that does this:
set_time(get_time() + t)
The new time is returned.
lerp(start, end, [startt,] [endt,] [dt,] [t,] [extend])
Linearly interpolates between start and end as time moves from startt to endt.
startt is the time to start.
To specify the ending time, use either endt, which is the absolute time, or dt, which is relative from startt.
For example, the following are equivalent:
lerp(0, 1, rabbyt.get_time(), endt=rabbyt.get_time()+1) lerp(0, 1, rabbyt.get_time(), dt=1)
extend is a string defining what to do before startt and after endt. Possible values are:
- The value will be locked between start and end. This is the default.
- After the value hits end it just keeps going!
- After the value hits end it will start over again at start.
- After the value hits end it will reverse, moving back to start.
Check out the extend_modes.py example to see all four side by side.
If any required values are omitted, lerp will return an IncompleteInterpolateAnim instance, which will have the missing values filled in when assigned to an anim slot. So instead of doing this:
# long way: sprite.x = lerp(start=sprite.x, end=10, startt=get_time(), dt=1)
... you could do this:
# shortcut with same result: sprite.x = lerp(end=10, dt=1)
Both start and startt are missing, so lerp returns an incomplete anim. When it is assigned to sprite.x, start is filled in with the previous value of sprite.x and startt is filled in with the current time.
start and end can either be numbers, or tuples of numbers. If they are tuples, a tuple of anims will be returned. For example, this line:
sprite.rgba = lerp((0,1,0,.5), (1,0,1,1), dt=1)
is equivalent to this:
sprite.red = lerp(0, 1, dt=1) sprite.green = lerp(1, 0, dt=1) sprite.blue = lerp(0, 1, dt=1) sprite.alpha = lerp(.5,1, dt=1)
TODO document t [startt and endt (mostly) ignored when used]
ease(start, end, [startt,] [endt,] [dt,] [t,] [extend,] [method,])
Interpolates between start and end, easing in and out of the transition.
method is the easing method to use. It defaults to "sine". See the "interpolation.py" example in the rabbyt source distribution for more.
TODO List the valid interpolation methods here (perhaps with descriptions.)
All other argments are identical to lerp.
ease_in(start, end, [startt,] [endt,] [dt,] [t,] [extend,] [method,])
Interpolates between start and end, easing into the transition. (So the movement starts out slow.)
See the docs for ease for more information.
ease_out(start, end, [startt,] [endt,] [dt,] [t,] [extend,] [method,])
Interpolates between start and end, easing out of the transition. (The movement starts fast and ends slow.)
See the docs for ease for more information.
chain provides a way to automatically run anims in a sequence. For example, you can move a sprite in a square like this:
now = get_time() sprite.xy = chain( lerp(( 0, 0), (10, 0), now, now+10), lerp((10, 0), (10,10), now+10, now+20), lerp((10,10), ( 0,10), now+20, now+30), lerp(( 0,10), ( 0, 0), now+30, now+40))
If you ommit the start and startt arguments of lerp, they will be filled in from end and endt of the the previous lerp. So this is a less verbose way to do the same thing as above:
sprite.xy = chain( lerp((0,0), (10, 0), dt=10), lerp(end=(10,10), dt=10), lerp(end=( 0,10), dt=10), lerp(end=( 0, 0), dt=10))
Currently, lerp, ease, ease_in, and ease_out are the only anims that can be used with chain.
wrap(bounds, parent, static=True) -> AnimWrap or tuple of AnimWraps
Wraps a parent Anim to fit within bounds. bounds should be an object that supports item access for at least bounds and bounds. (A list or tuple with a length of 2 would work great.)
If static is True, bounds is only read once and stored in C variables for fast access. This is much faster, but doesn't work if bounds is an object you wish to mutate.
If parent is a iterable, a tuple of anims will be returned instead of a single one. (This is similar to lerp().)