gale.ai.formation module
This file contains support for coordinated group movement: a FormationPattern gives each slot in a formation an offset relative to an anchor point (LineFormation, WedgeFormation, CircleFormation are fixed patterns; ScalableFormationPattern adapts one to however many members currently occupy it), SlotAssignment assigns characters to slots minimizing total movement, and FormationManager ties it all together as “two-level” steering: the anchor moves on its own (driven by whatever steering behavior you give it, e.g. Arrive at a destination), and each member is steered towards anchor.position + pattern.slot_offset(slot, member_count) – so members follow the anchor’s motion for free, without each one needing to know where the group as a whole is going.
Note that “emergent” formations (a flock/crowd that stays together without any explicit pattern) don’t need any of this: they fall out of combining Separation, a cohesion Seek towards the group’s centroid, and VelocityMatch (alignment) with BlendedSteering, all of which already exist in gale.ai.steering.
Author: Alejandro Mujica (aledrums@gmail.com)
- class gale.ai.formation.FormationPattern[source]
Bases:
objectBase class for a formation pattern: gives the offset, relative to the formation’s anchor, that a given slot should occupy.
- class gale.ai.formation.LineFormation(spacing=40)[source]
Bases:
FormationPatternSlots placed in a straight line, spaced spacing apart, centered on the anchor.
- Parameters:
spacing (float)
- class gale.ai.formation.WedgeFormation(spacing=40, depth=40)[source]
Bases:
FormationPatternSlots placed in a V shape opening behind the anchor (slot 0), two per following row, spreading out and back.
- Parameters:
spacing (float)
depth (float)
- class gale.ai.formation.CircleFormation(radius=60)[source]
Bases:
FormationPatternSlots placed evenly around a circle centered on the anchor.
- Parameters:
radius (float)
- class gale.ai.formation.ScalableFormationPattern(base_pattern, reference_count=4)[source]
Bases:
FormationPatternWraps another FormationPattern and scales its spacing so the whole formation’s footprint stays close to a target size regardless of how many members currently occupy it, instead of growing without bound as members are added.
- Parameters:
base_pattern (FormationPattern)
reference_count (int)
- class gale.ai.formation.SlotAssignment[source]
Bases:
objectAssigns characters to formation slots minimizing total movement, by greedily giving each character the closest still-available slot – not globally optimal, but cheap and good enough to avoid members crossing paths on every reassignment, and stable enough that a member usually keeps its slot across calls.
- static assign(characters, pattern, anchor)[source]
- Parameters:
characters (Sequence[Kinematic]) – The characters to assign to slots.
pattern (FormationPattern) – The formation pattern to assign slots from.
anchor (Vector2) – The formation’s current anchor position.
- Returns:
A mapping from slot index to the character assigned to it, for slots 0..len(characters) - 1.
- Return type:
Dict[int, Kinematic]
- class gale.ai.formation.FormationManager(anchor, pattern)[source]
Bases:
objectDrives a group of characters as a formation: an anchor Kinematic represents the group’s overall position/orientation (steer it yourself with any SteeringBehavior, e.g. Arrive at a destination), and each member gets a per-slot target Kinematic positioned at anchor.position + pattern.slot_offset(slot, member_count) for you to steer the member towards (e.g. with Arrive). Call update() once a frame after moving the anchor, and add_member/remove_member as the group’s membership changes – both trigger a fresh SlotAssignment so slots stay filled without gaps.
Usage example:
anchor = Kinematic(x=0, y=0) manager = FormationManager(anchor, WedgeFormation()) manager.add_member(soldier_1) manager.add_member(soldier_2)
# In the game loop, after steering the anchor with your own # behavior (e.g. anchor_arrive.get_steering() then anchor.update(…)): manager.update() for member in manager.members:
slot_target = manager.slot_kinematic(member) Arrive(member, slot_target).get_steering(dt)
- Parameters:
anchor (Kinematic)
pattern (FormationPattern)
- set_pattern(pattern)[source]
Switch to a different formation pattern (e.g. a different tactical “play”), reassigning slots on the next update().
- Parameters:
pattern (FormationPattern) – The new pattern to arrange members in.
- Return type:
None
- add_member(character, role=None)[source]
- Parameters:
character (Kinematic) – The character to add to the formation.
role (str | None) – An optional label for whichever slot this character ends up assigned to (e.g. “leader”, “flank”). The default value is None.
- Return type:
None
- remove_member(character)[source]
- Parameters:
character (Kinematic) – The character to remove from the formation.
- Return type:
None
- update()[source]
Reassign slots (via SlotAssignment) and refresh each member’s slot-target Kinematic position/orientation. Call this once a frame, after moving self.anchor.
- Return type:
None
- slot_kinematic(character)[source]
- Parameters:
character (Kinematic) – A member of this formation.
- Returns:
The Kinematic representing character’s current slot target, to be steered towards (e.g. with Arrive). Only valid after update() has been called at least once since character was added.
- Raises:
KeyError – If character has never been assigned a slot yet.
- Return type: