ecs-pattern


Nameecs-pattern JSON
Version 1.2.0 PyPI version JSON
download
home_pagehttps://github.com/ikvk/ecs_pattern
SummaryImplementation of the ECS pattern for creating games
upload_time2023-11-08 11:38:49
maintainer
docs_urlNone
authorVladimir Kaukin
requires_python
licenseApache-2.0
keywords python3 python ecs pattern architecture games gamedev
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            .. http://docutils.sourceforge.net/docs/user/rst/quickref.html

========================================================================================================================
ecs_pattern 🚀
========================================================================================================================

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

Make a game instead of architecture for a game.

`Документация на Русском <https://github.com/ikvk/ecs_pattern/blob/master/_docs/README_RUS.rst#ecs_pattern->`_.

.. image:: 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
===============  ==========================================

.. contents::

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
========================================================================================================================

.. code-block:: python

    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.

    | The component is used as a mixin in entities.

    | Use the ecs_pattern.component decorator to create components.

    | Technically this is python dataclass.

    .. code-block:: python

        @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.

    .. code-block:: python

        @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:

    .. code-block:: python

        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 the ecs_pattern class.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.

    .. code-block:: python

        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.

    .. code-block:: python

        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 <https://github.com/ikvk/ecs_pattern/tree/master/examples/pong#pong---classic-game>`_: game - pygame + ecs_pattern
* `Snow day <https://github.com/ikvk/ecs_pattern/tree/master/examples/snow_day#snow-day---scene>`_: scene - pygame + ecs_pattern
* `Trig fall <https://github.com/ikvk/ecs_pattern/tree/master/examples/trig#trig-fall---game>`_: 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 <https://github.com/ikvk/ecs_pattern/blob/master/_docs/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 ⭐

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ikvk/ecs_pattern",
    "name": "ecs-pattern",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "python3,python,ecs,pattern,architecture,games,gamedev",
    "author": "Vladimir Kaukin",
    "author_email": "KaukinVK@ya.ru",
    "download_url": "https://files.pythonhosted.org/packages/50/6c/4abb75e4c12247ac078f0b05d1e7b7ace9d6b5dec8e00565cf4e50b75319/ecs-pattern-1.2.0.tar.gz",
    "platform": null,
    "description": ".. http://docutils.sourceforge.net/docs/user/rst/quickref.html\r\n\r\n========================================================================================================================\r\necs_pattern \ud83d\ude80\r\n========================================================================================================================\r\n\r\nImplementation of the ECS pattern (Entity Component System) for creating games.\r\n\r\nMake a game instead of architecture for a game.\r\n\r\n`\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043d\u0430 \u0420\u0443\u0441\u0441\u043a\u043e\u043c <https://github.com/ikvk/ecs_pattern/blob/master/_docs/README_RUS.rst#ecs_pattern->`_.\r\n\r\n.. image:: https://img.shields.io/pypi/dm/ecs_pattern.svg?style=social\r\n\r\n===============  ==========================================\r\nPython version   3.3+\r\nLicense          Apache-2.0\r\nPyPI             https://pypi.python.org/pypi/ecs_pattern/\r\nDependencies     dataclasses before 3.7, typing before 3.5\r\n===============  ==========================================\r\n\r\n.. contents::\r\n\r\nIntro\r\n========================================================================================================================\r\n| ECS - Entity-Component-System - it is an architectural pattern created for game development.\r\n\r\nIt is great for describing a dynamic virtual world.\r\n\r\nBasic principles of ECS:\r\n\r\n* Composition over inheritance\r\n* Data separated from logic (Data Oriented Design)\r\n\r\n| *Component* - Property with object data\r\n| *Entity* - Container for properties\r\n| *System* - Data processing logic\r\n| *EntityManager* - Entity database\r\n| *SystemManager* - Container for systems\r\n\r\nInstallation\r\n========================================================================================================================\r\n::\r\n\r\n    $ pip install ecs-pattern\r\n\r\nGuide\r\n========================================================================================================================\r\n\r\n.. code-block:: python\r\n\r\n    from ecs_pattern import component, entity, EntityManager, System, SystemManager\r\n\r\n* Describe components - component\r\n* Describe entities based on components - entity\r\n* Distribute the responsibility of processing entities by systems - System\r\n* Store entities in entity manager - EntityManager\r\n* Manage your systems with SystemManager\r\n\r\nComponent\r\n------------------------------------------------------------------------------------------------------------------------\r\n    | Property with object data. Contains only data, no logic.\r\n\r\n    | The component is used as a mixin in entities.\r\n\r\n    | Use the ecs_pattern.component decorator to create components.\r\n\r\n    | Technically this is python dataclass.\r\n\r\n    .. code-block:: python\r\n\r\n        @component\r\n        class ComPosition:\r\n            x: int = 0\r\n            y: int = 0\r\n\r\n        @component\r\n        class ComPerson:\r\n            name: str\r\n            health: int\r\n\r\nEntity\r\n------------------------------------------------------------------------------------------------------------------------\r\n    | Container for properties. Consists of components only.\r\n\r\n    | It is forbidden to add attributes to an entity dynamically.\r\n\r\n    | Use the ecs_pattern.entity decorator to create entities.\r\n\r\n    | Technically this is python dataclass with slots=True.\r\n\r\n    .. code-block:: python\r\n\r\n        @entity\r\n        class Player(ComPosition, ComPerson):\r\n            pass\r\n\r\n        @entity\r\n        class Ball(ComPosition):\r\n            pass\r\n\r\nSystem\r\n------------------------------------------------------------------------------------------------------------------------\r\n    | Entity processing logic.\r\n\r\n    | Does not contain data about entities and components.\r\n\r\n    | Use the ecs_pattern.System abstract class to create concrete systems:\r\n\r\n    .. code-block:: python\r\n\r\n        class SysInit(System):\r\n            def __init__(self, entities: EntityManager):\r\n                self.entities = entities\r\n\r\n            def start(self):\r\n                self.entities.init(\r\n                    TeamScoredGoalEvent(Team.LEFT),\r\n                    Spark(spark_sprite(pygame.display.Info()), 0, 0, 0, 0)\r\n                )\r\n                self.entities.add(\r\n                    GameStateInfo(play=True, pause=False),\r\n                    WaitForBallMoveEvent(1000),\r\n                )\r\n\r\n        class SysGravitation(System):\r\n            def __init__(self, entities: EntityManager):\r\n                self.entities = entities\r\n\r\n            def update(self):\r\n                for entity_with_pos in self.entities.get_with_component(ComPosition):\r\n                    if entity_with_pos.y > 0:\r\n                        entity_with_pos.y -= 1\r\n\r\nEntityManager\r\n------------------------------------------------------------------------------------------------------------------------\r\n    | Container for entities.\r\n\r\n    | Use the ecs_pattern class.EntityManager for creating an entity manager.\r\n\r\n    | Time complexity of get_by_class and get_with_component - like a dict\r\n\r\n    | *entities.add* - Add entities.\r\n\r\n    | *entities.delete* - Delete entities.\r\n\r\n    | *entities.delete_buffer_add* - Save entities to the delete buffer to delete later.\r\n\r\n    | *entities.delete_buffer_purge* - Delete all entities in the deletion buffer and clear the buffer.\r\n\r\n    | *entities.init* - Let manager know about entities. KeyError are raising on access to unknown entities.\r\n\r\n    | *entities.get_by_class* - Get all entities of the specified classes. Respects the order of entities.\r\n\r\n    | *entities.get_with_component* - Get all entities with the specified components.\r\n\r\n    .. code-block:: python\r\n\r\n        entities = EntityManager()\r\n        entities.add(\r\n            Player('Ivan', 20, 1, 2),\r\n            Player('Vladimir', 30, 3, 4),\r\n            Ball(0, 7)\r\n        )\r\n        for entity_with_pos in entities.get_with_component(ComPosition):\r\n            print(entity_with_pos.x, entity_with_pos.y)\r\n        for player_entity in entities.get_by_class(Player):\r\n            print(player_entity.name)\r\n            entities.delete_buffer_add(player_entity)\r\n        entities.delete_buffer_purge()\r\n        entities.delete(*tuple(entities.get_by_class(Ball)))  # one line del\r\n\r\nSystemManager\r\n------------------------------------------------------------------------------------------------------------------------\r\n    | Container for systems.\r\n\r\n    | Works with systems in a given order.\r\n\r\n    | Use the ecs_pattern.SystemManager class to manage systems.\r\n\r\n    | *system_manager.start_systems* - Initialize systems. Call once before the main systems update cycle.\r\n\r\n    | *system_manager.update_systems* - Update systems status. Call in the main loop.\r\n\r\n    | *system_manager.stop_systems* - Stop systems. Call once after the main loop completes.\r\n\r\n    .. code-block:: python\r\n\r\n        entities = EntityManager()\r\n        entities.add(\r\n            Player('Ivan', 20, 1, 2),\r\n            Player('Vladimir', 30, 3, 4),\r\n            Ball(0, 7)\r\n        )\r\n        system_manager = SystemManager([\r\n            SysPersonHealthRegeneration(entities),\r\n            SysGravitation(entities)\r\n        ])\r\n        system_manager.start_systems()\r\n        while play:\r\n            system_manager.update_systems()\r\n            clock.tick(24)  # *pygame clock\r\n        system_manager.stop_systems()\r\n\r\nExamples\r\n========================================================================================================================\r\n* `Pong <https://github.com/ikvk/ecs_pattern/tree/master/examples/pong#pong---classic-game>`_: game - pygame + ecs_pattern\r\n* `Snow day <https://github.com/ikvk/ecs_pattern/tree/master/examples/snow_day#snow-day---scene>`_: scene - pygame + ecs_pattern\r\n* `Trig fall <https://github.com/ikvk/ecs_pattern/tree/master/examples/trig#trig-fall---game>`_: commercial game - pygame + ecs_pattern + numpy\r\n\r\nAdvantages\r\n========================================================================================================================\r\n* Memory efficient - Component and Entity use dataclass\r\n* Convenient search for objects - by entity class and by entity components\r\n* Flexibility - loose coupling in the code allows you to quickly expand the project\r\n* Modularity - the code is easy to test, analyze performance, and reuse\r\n* Execution control - systems work strictly one after another\r\n* Following the principles of the pattern helps to write quality code\r\n* Convenient to parallelize processing\r\n* Compact implementation\r\n\r\nDifficulties\r\n========================================================================================================================\r\n* It can take a lot of practice to learn how to cook ECS properly\r\n* Data is available from anywhere - hard to find errors\r\n\r\nNewbie mistakes\r\n========================================================================================================================\r\n* Inheritance of components, entities, systems\r\n* Ignoring the principles of ECS, such as storing data in the system\r\n* Raising ECS to the absolute, no one cancels the OOP\r\n* Adaptation of the existing project code under ECS \"as is\"\r\n* Use of recursive or reactive logic in systems\r\n* Using EntityManager.delete in get_by_class, get_with_component loops\r\n\r\nGood Practices\r\n========================================================================================================================\r\n* Use \"Singleton\" components with data and flags\r\n* Minimize component change locations\r\n* Do not create methods in components and entities\r\n* Divide the project into scenes, a scene can be considered a cycle for the SystemManager with its EntityManager\r\n* Use packages to separate scenes\r\n\r\nProject tree example:\r\n::\r\n\r\n    /common_tools\r\n        __init__.py\r\n        resources.py\r\n        i18n.py\r\n        gui.py\r\n        consts.py\r\n        components.py\r\n        math.py\r\n    /menu_scene\r\n        __init__.py\r\n        entities.py\r\n        main_loop.py\r\n        surfaces.py\r\n        systems.py\r\n    /game_scene\r\n        __init__.py\r\n        entities.py\r\n        main_loop.py\r\n        surfaces.py\r\n        systems.py\r\n    main.py\r\n\r\nReleases\r\n========================================================================================================================\r\n\r\nHistory of important changes: `release_notes.rst <https://github.com/ikvk/ecs_pattern/blob/master/_docs/release_notes.rst>`_\r\n\r\nHelp the project\r\n========================================================================================================================\r\n* Found a bug or have a suggestion - issue / merge request \ud83c\udfaf\r\n* There is nothing to help this project with - help another open project that you are using \u270b\r\n* Nowhere to put the money - spend it on family, friends, loved ones or people around you \ud83d\udcb0\r\n* Star the project \u2b50\r\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Implementation of the ECS pattern for creating games",
    "version": "1.2.0",
    "project_urls": {
        "Homepage": "https://github.com/ikvk/ecs_pattern"
    },
    "split_keywords": [
        "python3",
        "python",
        "ecs",
        "pattern",
        "architecture",
        "games",
        "gamedev"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ffe8d98b0603b22857a5fb9def5fe2dc4cf43d7a0ca167dad7af56b105ed68fd",
                "md5": "5cd47bef4e894c2e65a595fa475de690",
                "sha256": "2ad2600607915209e6d5332452d360e829b44f635e6af2949ed08ddb14204f64"
            },
            "downloads": -1,
            "filename": "ecs_pattern-1.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5cd47bef4e894c2e65a595fa475de690",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 10285,
            "upload_time": "2023-11-08T11:38:44",
            "upload_time_iso_8601": "2023-11-08T11:38:44.291911Z",
            "url": "https://files.pythonhosted.org/packages/ff/e8/d98b0603b22857a5fb9def5fe2dc4cf43d7a0ca167dad7af56b105ed68fd/ecs_pattern-1.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "506c4abb75e4c12247ac078f0b05d1e7b7ace9d6b5dec8e00565cf4e50b75319",
                "md5": "2d644088dff2b9c81775c7eb64eef5a7",
                "sha256": "9ab5cd702a934e06e56715132e02ed61f629b47ec23095a8b86b058bc07cdb4f"
            },
            "downloads": -1,
            "filename": "ecs-pattern-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "2d644088dff2b9c81775c7eb64eef5a7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 11188,
            "upload_time": "2023-11-08T11:38:49",
            "upload_time_iso_8601": "2023-11-08T11:38:49.467459Z",
            "url": "https://files.pythonhosted.org/packages/50/6c/4abb75e4c12247ac078f0b05d1e7b7ace9d6b5dec8e00565cf4e50b75319/ecs-pattern-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-08 11:38:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ikvk",
    "github_project": "ecs_pattern",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "tox": true,
    "lcname": "ecs-pattern"
}
        
Elapsed time: 0.16173s