Grouping Mobs¶
So far we’ve been applying animations to individual mobs. But often it is more convenient to apply animations to Groups of mobs. Algan handles this defining a parent-child relation between two mobs. Once such a relationship is established, any animation applied to the parent will be propagated to its children (and those children will then propagate the animation to their children, recursively). As such, complex objects can be built up of many simple individual mob components, and animated as one entity.
The parent-child relation is established by calling
add_children(),
which attaches the parameter mob as a child of the calling mob.
Algan also provides the Group class which takes a collection of
mobs and attaches them to a new invisible parent Group mob. Group
also provides various layout helpers.
Let’s see an example.
Example: ChildMobsBasic ¶
from algan import *
center_square = Square(color=BLUE)
outer_squares = [Square(location=loc) for loc in [LEFT * 2.5, UP * 2.5, RIGHT * 2.5, DOWN * 2.5]]
center_square.add_children(outer_squares) # this is the crucial step
# Now any change to the parent propagates to the children,
# including spawning.
center_square.scale(0.75).spawn()
center_square.rotate(90, OUT)
center_square.move(RIGHT * 1)
with Seq(runtime=5):
center_square.rotate(360, OUT, about=ORIGIN)
center_square.wait()
# You can even animate the parent and a child at the same time.
with Sync(runtime=5):
center_square.rotate(90, OUT)
outer_squares[0].rotate(180, UP)
Scene.wait()
Scene.save_video()
How changes propagate¶
What “propagate” means depends on the attribute:
Change to the parent |
Effect on each child |
|---|---|
The child moves by the same displacement. |
|
The child’s basis is rotated or scaled the same way, and its position relative to the parent is preserved. |
|
The child gets the same change. |
|
The child spawns or despawns too. |
The upshot for geometry is that a child behaves as though bolted to the parent by a rigid pole: rotate the parent and the children swing around with it, keeping their orientation relative to the parent fixed.
Changes made directly to a child ignore the parent relationship entirely, so you can animate a child independently, as in the last block of the example above.
See also
Updaters – for a relation the parent-child rule cannot express, such as one mob following another without also taking its orientation.
Inspecting the hierarchy¶
Accessor |
Returns |
|---|---|
This Mob’s direct children. Read-only – always add through
|
|
Children, grandchildren and so on, plus this Mob. |
|
The Mobs whose changes this one follows – there can be several.
Read-only – always add through
|
|
Detach one link, from either side. Both drop it in both directions. |
|
Attach from the child’s side, or swap the whole child list. |
Groups¶
Group wraps a collection of Mobs so you can treat them as one. It
creates an empty Mob at the centre of the collection and adds everything in the collection as its
children, so all of the propagation rules above apply:
rotating the Group turns each member about the Group’s centre, and setting the
Group’s color sets every member’s.
Example: ChildMobsGroup ¶
from algan import *
group = Group([Square().scale(0.35).move(RIGHT * x) for x in (-1, 0, 1)])
group.spawn()
with Seq():
group.rotate(180, OUT) # the whole row turns about its centre
group.color = BLUE # every member changes
group.move(UP * 0.5)
Scene.wait()
Scene.save_video()
Arranging¶
arrange_in_line() spreads the members along a direction;
arrange_in_grid() lays them out in rows and columns. Both are
ordinary animations, so members slide into place rather than jumping.
Example: ChildMobsArrange ¶
from algan import *
group = Group([Square(color=BLUE).scale(0.3) for _ in range(9)]).spawn()
group.arrange_in_line(RIGHT) # a row
Scene.wait()
group.arrange_in_line(DOWN, buffer=0.15) # a tight column
Scene.wait()
group.arrange_in_grid(3) # 3 rows
Scene.wait()
group.arrange_in_grid(3, row_buffer=1.0) # 3 rows, generously spaced
Scene.wait()
Scene.save_video()
arrange_in_line also takes align_to to line the members up on
an edge rather than their centres, and equal_widths to space centres
evenly instead of leaving equal gaps. arrange_in_grid takes
row_direction / column_direction to control which way the grid fills.
See also
Positioning and Layout – the rest of the
positioning methods, including screen-relative placement and
fit_to_screen(),
which is what you usually want after arranging a group.
Indexing¶
Groups are indexable and iterable, so you can reach individual members without keeping a separate list:
Example: ChildMobsGroupIndexing ¶
from algan import *
group = Group([Circle(color=BLUE).scale(0.4) for _ in range(6)])
group.arrange_in_line(RIGHT, buffer=0.3).spawn()
with Lag(0.4):
for circle in group:
circle.color = YELLOW
group[0].move(UP)
group.arrange_in_grid()
Scene.wait()
Scene.save_video()