Controlling Animations

So far we’ve seen how to create basic animations by modifying animatable attributes and using animated_function() s. But in all of these examples, the animations play for 1 second each, and take place one after the other. What if we want more control over how the animations should happen? Not to worry, Algan is specifically designed to make orchestrating complex animations easy, and to this end it provides AnimationContext s.

Animation Contexts

In Algan, you can control how animations should be played by placing them within an appropriate context. Let’s dive in with an example.

Example: CombiningSync

from algan import *

mob = Square().spawn()
with Sync():
    mob.move(RIGHT)
    mob.rotate(90, OUT)

render_to_file()
from algan import *

mob = Square().spawn()
with Sync():
    mob.move(RIGHT)
    mob.rotate(90, OUT)

render_to_file()

Here we use the Sync context (read as “with animations synchronized”) to specify the animations should be synchronized. All animations that take place within the with Sync(): clause will be played at the same time. In addition to Sync, Algan also provides the Seq (“with animations sequenced”), Lag (“with animations lagged”), and Off (“with animations off”) contexts.

Example: CombiningContextExamples

from algan import *

mob1 = Square().spawn()
mob2 = Circle().spawn()

with Sync():
    mob1.rotate(360, OUT)
    mob2.move(RIGHT)

with Seq():
    mob1.move(RIGHT)
    mob2.move(UP)

with Lag(0.5):
    mob1.move_to(ORIGIN)
    mob2.move_to(ORIGIN)

with Off():
    mob1.move(LEFT)
    mob2.move(RIGHT)

render_to_file()
from algan import *

mob1 = Square().spawn()
mob2 = Circle().spawn()

with Sync():
    mob1.rotate(360, OUT)
    mob2.move(RIGHT)

with Seq():
    mob1.move(RIGHT)
    mob2.move(UP)

with Lag(0.5):
    mob1.move_to(ORIGIN)
    mob2.move_to(ORIGIN)

with Off():
    mob1.move(LEFT)
    mob2.move(RIGHT)

render_to_file()

Seq() will play animations sequentially one after the other (note that this is the default behaviour when not in any context), Lag(lag_ratio=r) will play animations sequentially lagged by a factor of r. e.g. Lag(0.5) will begin the next animation once the current one is 50% finished.

Note

Lag(0) is equivalent to Sync() and Lag(1) is equivalent to Seq().

Finally Off() disables animations that take place within its context, all changes will be instant (1 frame). AnimationContext s can also be given a number of parameters to change their behaviour. Most notably, the length of animations that take place within a context can be controlled with run_time and run_time_unit.

Example: CombiningContextExamples

from algan import *

mob1 = Circle().spawn()

with Seq(run_time=1):
    mob1.move(LEFT)
    mob1.move(UP)
    mob1.move(RIGHT*2)
    mob1.move(DOWN)

with Seq(run_time_unit=5):
    mob1.rotate(360, UP)
    mob1.move_to(ORIGIN)

render_to_file()
from algan import *

mob1 = Circle().spawn()

with Seq(run_time=1):
    mob1.move(LEFT)
    mob1.move(UP)
    mob1.move(RIGHT*2)
    mob1.move(DOWN)

with Seq(run_time_unit=5):
    mob1.rotate(360, UP)
    mob1.move_to(ORIGIN)

render_to_file()

The run_time parameter specifies the total amount of time that the context should take place over, individual animations will be rescaled (sped up or slowed down) so that their total time is equal run_time. The run_time_unit parameter specifies how long each individual animation should be played for.

Note

If both parameters are set, run_time overrides run_time_unit.

Nesting Contexts

The real power of animation contexts is that they can be nested seamlessly. When one context is created within another, the sub-context will be treated as a single cohesive animation by the parent. This way, you can think of each context as combining the animations that take place within it into a single new animation. This makes specifying complex animations and designing modular animation code a breeze.

Example: CombiningContextExamples

from algan import *

mob1 = Circle().spawn()
mob2 = Square().spawn()

with Sync():
    with Seq():
        with Sync():
            mob1.move(LEFT*3)
            mob1.rotate(180, UP)
        with Sync():
            mob1.move(UP)
            mob1.color = YELLOW_A
        with Sync():
            mob1.move(RIGHT*3)
            mob1.glow = 0.5

    with Seq():
        with Sync():
            mob2.move(RIGHT*3)
            mob2.rotate(180, OUT)
        with Sync():
            mob2.move(DOWN)
            mob2.color = GREEN_E
        with Sync():
            mob2.move(LEFT*3)
            mob2.glow = 0.5

render_to_file()
from algan import *

mob1 = Circle().spawn()
mob2 = Square().spawn()

with Sync():
    with Seq():
        with Sync():
            mob1.move(LEFT*3)
            mob1.rotate(180, UP)
        with Sync():
            mob1.move(UP)
            mob1.color = YELLOW_A
        with Sync():
            mob1.move(RIGHT*3)
            mob1.glow = 0.5

    with Seq():
        with Sync():
            mob2.move(RIGHT*3)
            mob2.rotate(180, OUT)
        with Sync():
            mob2.move(DOWN)
            mob2.color = GREEN_E
        with Sync():
            mob2.move(LEFT*3)
            mob2.glow = 0.5

render_to_file()