Skip to main content

ecs_pattern 🚀

Implementation of the ECS pattern (Entity Component System) for creating games.

Make a game instead of architecture for a game.

Документация на Русском.

https://img.shields.io/pypi/dm/ecs_pattern.svg?style=social

Python version

3.3+

License

Apache-2.0

PyPI

https://pypi.python.org/pypi/ecs_pattern/

Dependencies

dataclasses before 3.7, typing before 3.5

Repo mirror

https://gitflic.ru/project/ikvk/ecs-pattern

Intro

ECS - Entity-Component-System - it is an architectural pattern created for game development.

It is great for describing a dynamic virtual world.

Basic principles of ECS:

  • Composition over inheritance

  • Data separated from logic (Data Oriented Design)

Component - Property with object data
Entity - Container for properties
System - Data processing logic
EntityManager - Entity database
SystemManager - Container for systems

Installation

$ pip install ecs-pattern

Guide

The library provides you with 5 tools:

from ecs_pattern import component, entity, EntityManager, System, SystemManager
  • Describe components - component

  • Describe entities based on components - entity

  • Distribute the responsibility of processing entities by systems - System

  • Store entities in entity manager - EntityManager

  • Manage your systems with SystemManager

Component

Property with object data. Contains only data, no logic.
Use the ecs_pattern.component decorator to create components.
Technically this is python dataclass.
Use components as mixins for entities.
@component
class ComPosition:
    x: int = 0
    y: int = 0

@component
class ComPerson:
    name: str
    health: int

Entity

Container for properties. Consists of components only.
It is forbidden to add attributes to an entity dynamically.
Use the ecs_pattern.entity decorator to create entities.
Technically this is python dataclass with slots=True.
Use EntityManager to store entities.
@entity
class Player(ComPosition, ComPerson):
    pass

@entity
class Ball(ComPosition):
    pass

System

Entity processing logic.
Does not contain data about entities and components.
Use the ecs_pattern.System abstract class to create concrete systems:
system.start - Initialize the system. It is called once before the main system update cycle.
system.update - Update the system status. Called in the main loop.
system.stop - Stops the system. It is called once after the completion of the main loop.
Use SystemManager to manage systems.
class SysInit(System):
    def __init__(self, entities: EntityManager):
        self.entities = entities

    def start(self):
        self.entities.init(
            TeamScoredGoalEvent(Team.LEFT),
            Spark(spark_sprite(pygame.display.Info()), 0, 0, 0, 0)
        )
        self.entities.add(
            GameStateInfo(play=True, pause=False),
            WaitForBallMoveEvent(1000),
        )

class SysGravitation(System):
    def __init__(self, entities: EntityManager):
        self.entities = entities

    def update(self):
        for entity_with_pos in self.entities.get_with_component(ComPosition):
            if entity_with_pos.y > 0:
                entity_with_pos.y -= 1

EntityManager

Container for entities.
Use class ecs_pattern.EntityManager for creating an entity manager.
Time complexity of get_by_class and get_with_component - like a dict
entities.add - Add entities.
entities.delete - Delete entities.
entities.delete_buffer_add - Save entities to the delete buffer to delete later.
entities.delete_buffer_purge - Delete all entities in the deletion buffer and clear the buffer.
entities.init - Let manager know about entities. KeyError are raising on access to unknown entities.
entities.get_by_class - Get all entities of the specified classes. Respects the order of entities.
entities.get_with_component - Get all entities with the specified components.
entities = EntityManager()
entities.add(
    Player('Ivan', 20, 1, 2),
    Player('Vladimir', 30, 3, 4),
    Ball(0, 7)
)
for entity_with_pos in entities.get_with_component(ComPosition):
    print(entity_with_pos.x, entity_with_pos.y)
for player_entity in entities.get_by_class(Player):
    print(player_entity.name)
    entities.delete_buffer_add(player_entity)
entities.delete_buffer_purge()
entities.delete(*tuple(entities.get_by_class(Ball)))  # one line del

SystemManager

Container for systems.
Works with systems in a given order.
Use the ecs_pattern.SystemManager class to manage systems.
system_manager.start_systems - Initialize systems. Call once before the main systems update cycle.
system_manager.update_systems - Update systems status. Call in the main loop.
system_manager.stop_systems - Stop systems. Call once after the main loop completes.
entities = EntityManager()
entities.add(
    Player('Ivan', 20, 1, 2),
    Player('Vladimir', 30, 3, 4),
    Ball(0, 7)
)
system_manager = SystemManager([
    SysPersonHealthRegeneration(entities),
    SysGravitation(entities)
])
system_manager.start_systems()
while play:
    system_manager.update_systems()
    clock.tick(24)  # *pygame clock
system_manager.stop_systems()

Examples

  • Pong: game - pygame + ecs_pattern

  • Snow day: scene - pygame + ecs_pattern

  • Trig fall: commercial game - pygame + ecs_pattern + numpy

Advantages

  • Memory efficient - Component and Entity use dataclass

  • Convenient search for objects - by entity class and by entity components

  • Flexibility - loose coupling in the code allows you to quickly expand the project

  • Modularity - the code is easy to test, analyze performance, and reuse

  • Execution control - systems work strictly one after another

  • Following the principles of the pattern helps to write quality code

  • Convenient to parallelize processing

  • Compact implementation

Difficulties

  • It can take a lot of practice to learn how to cook ECS properly

  • Data is available from anywhere - hard to find errors

Newbie mistakes

  • Inheritance of components, entities, systems

  • Ignoring the principles of ECS, such as storing data in the system

  • Raising ECS to the absolute, no one cancels the OOP

  • Adaptation of the existing project code under ECS “as is”

  • Use of recursive or reactive logic in systems

  • Using EntityManager.delete in get_by_class, get_with_component loops

Good Practices

  • Use “Singleton” components with data and flags

  • Minimize component change locations

  • Do not create methods in components and entities

  • Divide the project into scenes, a scene can be considered a cycle for the SystemManager with its EntityManager

  • Use packages to separate scenes

Project tree example:

/common_tools
    __init__.py
    resources.py
    i18n.py
    gui.py
    consts.py
    components.py
    math.py
/menu_scene
    __init__.py
    entities.py
    main_loop.py
    surfaces.py
    systems.py
/game_scene
    __init__.py
    entities.py
    main_loop.py
    surfaces.py
    systems.py
main.py

Releases

History of important changes: release_notes.rst

Help the project

  • Found a bug or have a suggestion - issue / merge request 🎯

  • There is nothing to help this project with - help another open project that you are using ✋

  • Nowhere to put the money - spend it on family, friends, loved ones or people around you 💰

  • Star the project ⭐

Metadata

Release files for ecs-pattern 1.4.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-pattern 1.4.0
File Size Uploaded
ecs_pattern-1.4.0.tar.gz 7.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ecs-pattern 1.4.0
File Interpreter ABI Platform
ecs_pattern-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.3 kB

Release files / ecs_pattern-1.4.0.tar.gz

Download URL ecs_pattern-1.4.0.tar.gz
Size 7.9 kB
Tags Source
SHA-256 checksum
How to use checksums
3dc62eeaf57d797d21012916d9493c294dce54d83f6e4dfd0b8b4c046c777f6c
BLAKE2b-256 checksum
How to use checksums
3291dbdb9e09a79e711858febaa532f06256f675bf6390eab66783d440bb1c56
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.10.2

Release files / ecs_pattern-1.4.0-py3-none-any.whl

Download URL ecs_pattern-1.4.0-py3-none-any.whl
Size 6.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9fa43db1e6c0e00ff5a171eeab145be178acfd38fa00a697e6b1d661e5f9240f
BLAKE2b-256 checksum
How to use checksums
beec8455d899268531f332c38c737f858c4c97e1b412e9363972037e2054b26d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.10.2

Release history Release notifications | RSS feed

This release

1.4.0 This release

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

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