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=1000)
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=1000) + 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.)
set_time(t)
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:
rabbyt.set_time(pygame.time.get_ticks())
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.
get_time()
Gets the time that was last set by set_time()
add_time(t)
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,] [extend])
Linearly interpolates between start and end as time moves from startt to endt.
startt is the time to start. It defaults to rabbyt.get_time().
To specify the ending time, use either endt, which is the absolute time, or dt, which is relative from startt.
For example, all of the following are equivalent:
lerp(0, 1, rabbyt.get_time(), rabbyt.get_time()+1000) lerp(0, 1, rabbyt.get_time(), dt=1000) lerp(0, 1, dt=1000)
extend is a string defining what to do before startt and after endt. Possible values are:
- "constant"
- The value will be locked between start and end. This is the default.
- "extrapolate"
- After the value hits end it just keeps going!
- "repeat"
- After the value hits end it will start over again at start.
- "reverse"
- 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.
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=1000)
is equivalent to this:
sprite.red = lerp(0, 1, dt=1000) sprite.green = lerp(1, 0, dt=1000) sprite.blue = lerp(0, 1, dt=1000) sprite.alpha = lerp(.5,1, dt=1000)
exponential(start, end, [startt,] [endt,] [dt,] [extend])
Exponentially interpolates between start and end as time moves from startt to endt, using a cosine function.
All arguments work the same as in lerp().
The function looks like this:
(e**t-1) / (e-1)
If you want to use another base besides e, drop me an email explaining why and I'll implement it. (YAGNI)
cosine(start, end, [startt,] [endt,] [dt,] [extend])
Cosinely [1] interpolates between start and end as time moves from startt to endt.
All arguments work the same as in lerp().
The function looks like this:
1-cos(t * pi/2)
And if math makes your head hurt, that means that your sprite will start out slow and speed up as it nears end.
[1] | Ok, so 'cosinely' isn't a word :) |
sine(start, end, [startt,] [endt,] [dt,] [extend])
Sinely [1] interpolates between start and end as time moves from startt to endt.
All arguments work the same as in lerp().
The function looks like this:
sin(t * pi/2)
And if math still makes your head hurt, you should give up game development.
Ok, ok, I give! Your sprite will start out fast and slow down by the time it reaches end. (Just the opposite of cosinely interpolating.)
[1] | Oh, you say 'sinely' isn't a word either? That must be a bug. Give me your dictionary and a pen and I'll fix it. |
bezier3(p0, p1, p2, p3, [startt,] [endt,] [dt,] [extend])
Interpolates along a cubic bezier curve as defined by p0, p1, p2, and p3.
startt, endt, dt, and extend work as in lerp().
p0, p1, p2, and p3 can be tuples, but they must all be the same length.
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[0] and bounds[1]. (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().)
to_Anim(value) -> Anim subclass instance
This is a convenience function to get Anim for a value.
If value is already an Anim, it is returned directly.
If value is callable, it is wrapped in an AnimPyFunc.
Otherwise, value is wrapped in an AnimConst.