Skip to main content

ecs-entity

License: CC0 1.0 Universal

A minimal Entity type for the entity-component-system (ECS) pattern. It is common in game development, but useful wherever a value is a bag of typed parts.

Unity users will recognize GameObject/MonoBehavior: entity.find(Transform) is GetComponent<Transform>(), entity.has(Transform) is TryGetComponent, and entity.get(Transform).

I think it is helpful to reimagine the Entity type in more generalized settings too:

  • An Entity is a poor man's Haskell Data.Dependent.Map.
  • An Entity can be used as a service locator, like python-injector but without the automatic dependency injection part.
  • An Entity is a dictionary of components with type-safe access.

The library is minimal. There is no built-in entity ID logic, no entity manager, no game-world engine, or anything like it. You can build your own game architecture and use this library's Entity as a supporting type.

Install

uv add ecs-entity
# or
pip install ecs-entity

You may also directly copy src/ecs/entity.py into your project.

Library Usage

Read the code documentation in src/ecs/entity.py. It is under 200 lines.

Here is a Minecraft example:

from dataclasses import dataclass

from ecs import Entity

Vec3 = tuple[float, float, float]
Quat = tuple[float, float, float, float]

MinecraftEntity = Entity  # a player, a cow, a dropped item: all just component bags


@dataclass
class Transform:
  """Where the entity is, and which way it faces."""

  position: Vec3
  rotation: Quat


@dataclass
class Physics:
  """How the entity moves next tick."""

  velocity: Vec3
  acceleration: Vec3


@dataclass
class InventoryData:
  items: tuple[str, ...]


@dataclass
class LivingBase:
  """A health bar."""

  health: float
  max_health: float


@dataclass
class PlayerBase:
  """Only players carry these."""

  client_ip: str
  gamemode: str
  is_admin: bool


steve = MinecraftEntity.of(
  Transform(position=(0.5, 64.0, 0.5), rotation=(0.0, 0.0, 0.0, 1.0)),
  Physics(velocity=(0.0, 0.0, 0.0), acceleration=(0.0, -0.08, 0.0)),
  LivingBase(health=20.0, max_health=20.0),
  InventoryData(items=("diamond_sword", "bread")),
  PlayerBase(client_ip="203.0.113.7", gamemode="survival", is_admin=False),
)

cow = MinecraftEntity.of(
  Transform(position=(3.0, 64.0, 1.5), rotation=(0.0, 0.0, 0.0, 1.0)),
  Physics(velocity=(0.0, 0.0, 0.0), acceleration=(0.0, -0.08, 0.0)),
  LivingBase(health=10.0, max_health=10.0),
)

def is_player(entity: MinecraftEntity) -> bool:
  """A player is an entity that carries PlayerBase."""
  return entity.has(PlayerBase)


assert is_player(steve)  # true because steve carries PlayerBase
assert not is_player(cow)
assert steve.get(Transform).position == (0.5, 64.0, 0.5)
assert cow.find(InventoryData) is None


def tick(entity: MinecraftEntity) -> None:
  """One physics step: acceleration moves velocity, velocity moves position."""
  physics = entity.find(Physics)
  transform = entity.find(Transform)
  if physics is None or transform is None:
    raise RuntimeError("Input entity does not support physics!")

  vx, vy, vz = physics.velocity
  ax, ay, az = physics.acceleration
  px, py, pz = transform.position

  velocity = (vx + ax, vy + ay, vz + az)
  position = (px + velocity[0], py + velocity[1], pz + velocity[2])

  physics.velocity = velocity
  transform.position = position


tick(cow)
assert cow.get(Physics).velocity == (0.0, -0.08, 0.0)
assert cow.get(Transform).position == (3.0, 63.92, 1.5)


def damage(entity: MinecraftEntity, amount: float) -> None:
  """Anything with a health bar can be hurt; this never asks what kind of entity it is."""
  bar = entity.find(LivingBase)
  if bar is None:
    raise RuntimeError("Input entity does not support damage!")

  bar.health = max(bar.health - amount, 0.0)


damage(cow, 4.0)
assert cow.get(LivingBase).health == 6.0
assert cow.get(LivingBase).max_health == 10.0

For the rest of the API, read src/ecs/entity.py.

Metadata

Release files for ecs-entity 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ecs-entity 1.0.0
File Size Uploaded Provenance
ecs_entity-1.0.0.tar.gz 7.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ecs-entity 1.0.0
File Interpreter ABI Platform
ecs_entity-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 15.8 kB

Release files / ecs_entity-1.0.0.tar.gz

Download URL ecs_entity-1.0.0.tar.gz
Size 7.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f7e5d94ade3bccb91a8b907c83e25af5ea0578afed345879916a422dc10e1a44
BLAKE2b-256 checksum
How to use checksums
d1ec30e24b35649d651bd8c473c7e9f362b89553db1dc7f9a7f84fe8c5d9c420
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / ecs_entity-1.0.0-py3-none-any.whl

Download URL ecs_entity-1.0.0-py3-none-any.whl
Size 8.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fae738e7ada63652c615dd4b69de291adc793b196a5963b1f4b3f875f9de0c16
BLAKE2b-256 checksum
How to use checksums
fa63baabb36530376809f16abab112a05269568a4b6d997a0329c6f6fc752d55
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Security for ecs-entity 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page