Skip to main content

A simple attribute-based approach to ECS.

Project description

punyecs

punyecs

GitHub Actions Workflow Status

punyecs is a tiny Entity Component System (ECS) inspired by tiny-ecs for Python. punyecs operates directly on class attributes as opposed to creating components along with querying mechanisms for fine grain control over which objects are operated on by systems similar to how tiny-ecs works on Lua tables. Decouple what an object can do from what it inherits.

Quick Install

If you use pip:

pip install punyecs

If you use uv:

uv add punyecs

What is it?

Instead of requiring inheritance, one can specify which attributes to operate on and any object (regardless of class) that has those attributes is operated on. That is, if a Player has an x and y attribute and an (unrelated) Enemy class has an x and y attribute you can have them both influenced by a World object. This avoids complicated inheritance hierarchies.

Here is a small example to illustrate the above:

from dataclasses import dataclass
from punyecs import World, requirements, Trait, give_traits

w = World()
Pos = Trait(x=0.0, y=0.0)

@dataclass
@give_traits(Pos)
class Player:
    pass

@dataclass
@give_traits(Pos)
class Enemy:
    pass

@requirements(w, Pos)
def move(e, dt):
    e.x += 0.1
    e.y += 0.1

player = Player(0.0, 0.0)
enemy = Enemy(1.0, 1.0)
w.add(player)
w.add(enemy)

w.update(1)
print(player.x)
# Prints 0.1
print(player.y)
# Prints 0.1

print(enemy.x)
# Prints 1.1
print(enemy.y)
# Prints 1.1

A Bit More Sophistication

We may also do exclusions for fine grain control. Returning to the example above, we may want various enemies to move like above but instead want to allow controller input for the player object. We can avoid influencing the player object by putting it in the excluded objects list. The function f becomes:

from punyecs import c

# ...

@requirements(w, Pos, subject_to=c.isnot(player))
def move(e, dt):
    e.x += 0.1
    e.y += 0.1

Then after every world.update(1), the player object will still remain at x=0.0, y=0.0.

Even More Sophistication!

It might be inconvenient to exclude individual objects if a large number of objects need to be excluded. punyecs provides a couple more filtering options. One way around this is to specify which attributes an object should not have.

For instance, we may have many different kinds of creatures. Most can follow the usual movement update function, but some creatures have a wiggle attribute. wiggle could be a Boolean, or even something more sophisticated like a function that describes how the creature wiggles.

To illustrate this consider:

from dataclasses import dataclass
from punyecs import World, requirements, Trait, give_traits, c, exattr

w = World()
Pos = Trait(x=0.0, y=0.0)

@dataclass
@give_traits(Pos)
class Player:
    pass

@dataclass
@give_traits(Pos)
class Enemy:
    pass

@dataclass
@give_traits(Pos)
class Wiggler:
    wiggle = lambda x: x + 2

@requirements(w, Pos, subject_to=exattr(c, "wiggle"))
def move(e, dt):
    e.x += 0.1
    e.y += 0.1

@requirements(w, Pos + Trait(wiggle=None))
def wiggle(e, dt):
    e.x = wiggle(e.x)
    e.y = wiggle(e.y)


player = Player(0.0, 0.0)
enemy = Enemy(1.0, 1.0)
wiggler = Wiggle(3.0, 3.0)
w.add(player)
w.add(enemy)
w.add(wiggler)

w.update(1)
print(player.x)
# Prints 0.1
print(player.y)
# Prints 0.1

print(enemy.x)
# Prints 1.1
print(enemy.y)
# Prints 1.1

print(wiggler.x)
# Prints 5.0
print(wiggler.y)
# Prints 5.0

Thus, move does not operate on wiggler but wiggle does.

Documentation

Even more filtering options are available. To learn more, see the readthedocs.

Contributing

Feel free to file an issue, make a pull request or, if you really like the project, donate. (No pressure though.)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

punyecs-0.4.0.tar.gz (4.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

punyecs-0.4.0-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

Details for the file punyecs-0.4.0.tar.gz.

File metadata

  • Download URL: punyecs-0.4.0.tar.gz
  • Upload date:
  • Size: 4.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for punyecs-0.4.0.tar.gz
Algorithm Hash digest
SHA256 a14a59922a78464cba5971b2b767b948f738a05064c00c106af1400e849dd881
MD5 96e0ede6c7a73187edc00c9df79e1dd0
BLAKE2b-256 9d0c377bdc69ad7165422932612794b6692ca72357aa7130e9ac1202c62a92f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for punyecs-0.4.0.tar.gz:

Publisher: python-publish.yml on Modular-Game-Components/punyecs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file punyecs-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: punyecs-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 5.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for punyecs-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 92d40e0ebb2e829d079bf7fa2c549a558d76e06f68a2ef3bc89ea801ceb31d40
MD5 d12e8bb86e12f4f9e951d2644f1714e9
BLAKE2b-256 960d3d19288a3ccd3ed70767e7b8f8b1d46386f92c5cc924b7af5a56f7244722

See more details on using hashes here.

Provenance

The following attestation bundles were made for punyecs-0.4.0-py3-none-any.whl:

Publisher: python-publish.yml on Modular-Game-Components/punyecs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page