rabbyt.anims - Rabbyt Reference

Documentation Index

# rabbyt.anims

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.)

# Using anims in your own classes

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.

## Classes

- Anim
- AnimConst
- AnimPyFunc
- AnimProxy

## Functions

### set_time

`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

`get_time()`

Gets the time that was last set by `set_time()`

### add_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

`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:

> `"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.

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

`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

`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

`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

`chain(...)`

`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

`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()`.)