.. 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"
}