gale.ecs.world module

This file contains the implementation of the class World: a Data-Oriented Design (ECS) store of entities (plain integer ids) and the components (plain Python objects) attached to them, plus the queries a System needs to find every entity that has a given combination of components.

Author: Alejandro Mujica (aledrums@gmail.com)

class gale.ecs.world.World[source]

Bases: object

A Data-Oriented Design (ECS) store: entities are just integer ids, components are plain Python objects the game defines itself (a dataclass such as Position(x, y) or Fatigue(stamina)), and a System (see gale.ecs.system) is whatever code queries the world for a combination of components and does something with them every frame.

This is meant for scenarios where a lot of similar entities (the ball, every player on the pitch, every collider) need the same kind of processing (physics integration, fatigue decay, collision checks) applied to all of them in a batch, which a plain object-oriented “one class per entity with its own update method” design tends to make either rigid (every entity needs every behavior it could ever use) or entangled (behaviors reach into each other directly). Storing components by type instead of by entity keeps each system’s data ready to be iterated over in one pass, and keeps behaviors decoupled: a MovementSystem only needs to know about Position and Velocity, never about Fatigue or the ball at all.

Usage example:

from dataclasses import dataclass

@dataclass class Position:

x: float y: float

@dataclass class Velocity:

dx: float dy: float

world = World() player = world.create_entity() world.add_component(player, Position(0, 0)) world.add_component(player, Velocity(10, 0))

for entity, position, velocity in world.query(Position, Velocity):

position.x += velocity.dx position.y += velocity.dy

world.destroy_entity(player) # drops Position and Velocity too

create_entity()[source]
Returns:

A new entity id, unique for the lifetime of this world.

Return type:

int

destroy_entity(entity)[source]

Remove entity and every component attached to it. Does nothing if entity does not exist (or was already destroyed).

Parameters:

entity (int) – The entity to destroy.

Return type:

None

has_entity(entity)[source]
Parameters:

entity (int) – The entity to look for.

Returns:

Whether entity currently exists in this world.

Return type:

bool

add_component(entity, component)[source]

Attach component to entity, keyed by its type. Attaching another component of the same type replaces the previous one.

Parameters:
  • entity (int) – The entity to attach the component to.

  • component (Any) – The component instance to attach.

Raises:

KeyError – If entity does not exist.

Return type:

None

remove_component(entity, component_type)[source]

Detach the component of the given type from entity. Does nothing if entity has no component of that type.

Parameters:
  • entity (int) – The entity to detach the component from.

  • component_type (Type) – The type of the component to detach.

Return type:

None

get_component(entity, component_type)[source]
Parameters:
  • entity (int) – The entity to look up.

  • component_type (Type) – The type of the component to fetch.

Returns:

The component of that type attached to entity, or None if it has none.

Return type:

Any | None

has_component(entity, component_type)[source]
Parameters:
  • entity (int) – The entity to look up.

  • component_type (Type) – The type of the component to check for.

Returns:

Whether entity has a component of that type attached.

Return type:

bool

query(*component_types)[source]

Find every entity that has all of the given component types. This is the hot path a System calls every frame, so it iterates the smallest of the requested component stores (fewer candidate entities to check against the others) instead of every entity in the world.

Parameters:

component_types (Type) – One or more component types an entity must have all of.

Returns:

An iterator of tuples (entity, component1, component2, ...), one per matching entity, with the components in the same order as component_types.

Raises:

ValueError – If called with no component types.

Return type:

Iterator[Tuple[Any, …]]