Groups

New in version 1.4.

Groups make it easy to transform a collection of primitives, possibly in different layers, as one unit.

For example, we could compose multiple sprites to make up the player’s ship. This lets us transform the ship together but apply effects such as changing the ship’s exhaust colour without affecting the fuselage:

ship = wasabi2d.Group([
    scene.layers[0].add_sprite('ship'),
    scene.layers[1].add_sprite('ship_exhaust', pos=(-10, 0))
])

ship.pos = 500, 300
ship.scale = 2

When an object is in a group, you can still update its properties individually:

# make the exhaust colour transparent
ship[1].color = (1.0, 1.0, 1.0, 0.5)

# make the exhaust flame move backwards
animate(ship[1], pos=(-20, 0))

…but the transformation properties apply relative to the group itself. So the animation above will play even as the ship moves around - perhaps under player control.

Essentially, a group is a separate local coordinate system for the objects it contains.

Constructing a Group

class wasabi2d.Group(transformables: List[wasabi2d.primitives.base.Transformable], *, pos: Tuple[float, float] = 0.0, 0.0, angle: float = 0.0, scale: float = 1.0)

Construct a group by giving it a list of the primitives it should contain.

The list may be empty.

Each primitive may be at most one group. Often a primitive will be associated with a group for its whole life. Deleting a group with delete() deletes all the objects it contains.

Group coordinates

A group has its local coordinate system. It’s handy to be able to convert positions between group coordinates and world coordinates:

Group.local_to_world(point: Tuple[float, float]) → Tuple[float, float]

Get the world position for the given local point.

Group.world_to_local(point: Tuple[float, float]) → Tuple[float, float]

Get the world position for the given local point.

Sometimes you just want to transform a vector, such as a velocity, rather than a position. The transformation is slightly different because it doesn’t take into account the position of the group - only its scale/angle:

Group.localvec_to_worldvec(vec: Tuple[float, float]) → Tuple[float, float]

Get the world vector for the given local vector.

Group.worldvec_to_localvec(vec: Tuple[float, float]) → Tuple[float, float]

Get the world vector for the given local vector.

For example, we could get the velocity of a bullet shot by a ship:

SHOOT_VELOCITY = 200, 0
bullet_velocity = ship.localvec_to_worldvec(SHOOT_VELOCITY)

Moving things in and out of Groups

There are two ways of moving objects in and out of groups, and you might need both of them. Assuming the group is already transformed, the two ways are:

  1. Keep the object’s angle, scale, pos values, exactly as they are, but reinterpret them as relative to the group. This means that the object moves.

  2. Keep the object where it is, but update angle, scale and pos. This means that the object doesn’t move.

When items are added in the constructor, or extend(), append(), they are directly specified in the group’s local coordinate system - this is method 1 above.

For method 2 - to keep the object where it is - Wasabi2D provides a separate set of methods. You can move one object in and out of a group, move out all of the objects, or build a group by moving in objects already in the scene.

Group.pop(index: int) → wasabi2d.primitives.base.Transformable

Extract a primitive from the group, leaving it in the scene.

The primitive will have (approximately) the same world transformation it had within the group.

Group.capture(*objects: Tuple[wasabi2d.primitives.base.Transformable])

Capture the given objects into the group.

The objects will have the same transformation they had outside of the group.

Group.explode() → List[wasabi2d.primitives.base.Transformable]

Extract and return primitives from the group.

This preserves the transformation for the primitives and leaves them in the scene.

This group becomes empty after this operation.

classmethod Group.from_objects(objects: List[wasabi2d.primitives.base.Transformable], **kwargs) → wasabi2d.primitives.group.Group

Build a group by capturing the given objects.

Keyword arguments can be used to set the initial transform for the group prior to capturing the objects.

Note

In Wasabi2D we don’t support skew for primitives, which means that if the group has a different value for scale_x and scale_y, then the primitive will appear differently after this operation. It should still have the same position, angle, and scale, but it will acquire/lose skew.

Groups as a list of objects

To work with the items in a group you can simply treat the group like a list of objects:

group = Group([
    scene.layers[0].add_sprite('ship'),
    scene.layers[1].add_sprite('ship_exhaust', pos=(-10, 0))
])

print(len(group))  # count the items in a group
ship, exhaust = group  # iterate over the items

ship = group[0]  # get an item
group[1] = scene.layers[1].add_sprite('ship_boost')  # replace
del group[0]  # delete an item

You can add items to the group. Note that the transformation that you give for the items is in group-local coordinates:

# Add additional items to the group
group.extend([
    scene.layers[0].add_sprite('mega_gun', pos=(-5, -10)),
    scene.layers[0].add_sprite('mega_gun', pos=(-5, 10)),
])
Group.append(transformable: wasabi2d.primitives.base.Transformable)

Add one transformable to the group.

Group.extend(transformables: List[wasabi2d.primitives.base.Transformable])

Add transformables to the group.

Finally you can delete or clear the group, which removes all objects in the group from the scene:

Group.delete()

Remove all primitives in the group.

Group.clear()

Alias for delete to match interface of a list

(To keep the objects in the scene, use explode().)