From 7bc07666d010ef9cfe7d66a8ca10fbf7362f3a28 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 2 May 2020 21:11:22 +0000 Subject: [PATCH 1/2] Initial release README.md --- README.md | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3f6816..abc9709 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,180 @@ -# Dynamic Entity Component System +# Bubel Entity Component System [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -Entity-Component-System implementation in D language. +BubelECS is Entity-Component-System architecture implementation in D language. +Library aims to delivery fast and flexible architecture for developing games. Library is @nogc and betterC compatible. Even Emscripten build works very well. +Important goal is to keep code without any external dependencies, i. eg. multithreading support don't contain any parallel execution +but emit jobs with delegate and array of dependencies. + +BubelECS was tested on Linux, Windows, Android and WASM. + +**Currently library is in beta stage so some significant API changes can appear.** + +## Design + +For core information about Entity-Component-System architectural pattern I recommend to read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). + +Main design principles are: + + * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly + * **Fast and safe EntityID** - every entity is referenced by its unique ID. If entity was destroyed EntityManager will return null pointer for given EntityID. Access to entity from ID is linear operation. + * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems update are generated automatically. + * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. + * **Easy systems ordering** - systems are ordered by single priority value. Order of execution of systems with same priority is undefined but order for different priorites are always preserved. + * **Flexible entity to system assignment** - system iterate over any entity that has chosen components. Components can be marked as optional so isn't required but can be used by system. Additionaly system can contain list of components which makes entity excluded from calculation. + * **Builtin events handling** - along with EntityManager library contain EventsManager which makes easier to communicate between multiple entities. + * **Hot-reload** - hot-reloading for systems should be as easy as possible. **Currently not achived yet (WIP!)**. + +Currently library is incredibly fast to iterate over entities and fast enought in direct access to entity component if it's needed. \ +There are some assumptions that should be considered when developing application: + + * Iterating over same components is incredibly fast so it's should be main way of making calculations. + * Using of direct access and events should be used very wisely and not too much. + * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. But due to memory fragmentation there sould by many of entities with same type. In other words, sometimes making to many components can lead to performence drop even if adding or removing components is fast enough. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your appliactiona wisely it should be trivial to change some core logic by changing only one system, or adding new system. Every entity can easily takes some behaviour from different entity type by adding several components. + +### Features + + * ECS architectural pattern + * Data oriented design + * Safe identifiers (EntityID) + * EntityTemplates - used to add entities, contain list of components and it's data + * Basic events handling + * Easy systems ordering + * Automatic multithreaded jobs generating + * Runtime and fast components adding and removing + * Listeners for adding and removing entity components inside systems + * Passes - systems are grouped to passes. Pass update call update callback of assigned systems. + * Calling custom callbacks for system entity groups + * betterC compatibility + * Emscripten compatibility + +### Planned + + * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. + * Hot-reload support - currently only reloading systems (their functions) works and only if code changes apperas only inside functions. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. + * External dependencies - ability to provide dependencies between system which isn't related to components. + * Static components - this components will have different memory model and can be accessed only directly. It will be slower with access but don't trigger memory copy when component is added or some different entity was destroyed. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. + * Better EventManager - currently implementy event handling system isn't it what I wanted. I'm not sure exacly what I can improve but multithreaded event execution is one of things which I considered and it probably will work. + * More demos and examples - demo appliaction is very basic now, but in future I planned more minigames and sanbox mode (opportunity to mix many components and systems). I planed some examples to show how to use basic functionality. + * C API - this is currenly in consideration. Everything is dependent on my free time and amount of work required to create good C API. + * More smaller improvement in draft stage... + +For more information about design and usage I recommend to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)**. + +## Build Instructions + +To build library you needs recent D compiler and optionally Emscripten (with python) to build web version. Currenlty tested are: LDC, DMD and GDC. \ +Supported build systems are DUB and Meson. + +##### DUB +```shell +#available configurations: library, dynlib, library-betterC, dynlib-betterC +dub build -c library -b release +``` + +##### Meson +```shell +#use '-DbetterC=true ' to build betterC code +meson build . #add '--buildtype=release' to build release code +cd build +ninja +``` + +##### Emscripten +```shell +python compile_wasm.py -opt +``` + +For more detailed build options please check documentation for used build system. + +## Demos + +Repository contain demo application. You can check demo [online](https://mergul.gitlab.io/bubel-ecs/ecs_demo.html) or build it form source code using DUB. \ +Online demo support multithreading and page tries to check if client support WASM multithreading or not and loads properly JS and WASM code. It was tested on Chrome, Firefox, Opera, Brave on Linux and Android. On firefox there is problem with multithreaded version so if demo don't works please try to disable shared_memory in browser flags. + +## Code example + +```d + +struct Position +{ + mixin ECS.Components; //makes struct component + float x; + float y; +} + +struct Velocity +{ + mixin ECS.Components; + //default values works + float x = 0.1; + float y = 1; +} + +struct StaticFlag +{ + mixin ECS.Components; +} + +struct UpdateSystem +{ + mixin ECS.System; //makes struct system + + ECS.ExcludedComponents!(StaticFlag); //prevents static entities from update + + struct EntitiesData + { + int length; //entities count + @readonly Entity[] entities; //entities arrays, entity contain ID only + Position[] positions; //positions array + @readonly Velocity[] velocities; //veocities array, readonly (Multithreading tag) + } + + void onUpdate(EntitiesData data) //update callback, called multiple times per frame for every entities types + { + foreach(i; 0..data.length) //iterate over entities + { + data.positions[i].x += data.velocities[i].x * dt; + data.positions[i].y += data.velocities[i].y * dt; + } + } +} + +void main() +{ + manager.beginRegister(); + //register components + manager.registerComponent!Position; + manager.registerComponent!Velocity; + manager.registerComponent!StaticFlag; + //register system with priority 0 + manager.registerSystem!UpdateSystem(0); + manager.endRegister(); + + //allocate template + EntityTemplate* tmpl = manager.allocateEmplate([Velocity.component_id, Position.component_id].staticArray); + scope (exit) manager.freeTemplate(tmpl); + + //gets pointer to template component data + Position* position = tmpl.getComponent!Position; + foreach(i; 0 .. 100) + { + position.x = i % 10; + position.y = i / 10; + manager.addEntity(tmpl); + } + + manager.begin(); //start frame + manager.update(); //update all systems, there onUpdate callbacks are called + manager.end(); //end frame +} + +``` + +## Links + +Documentation: https://mergul.gitlab.io/bubel-ecs/ecs.html \ +Online demo: https://mergul.gitlab.io/bubel-ecs/ecs_demo.html From 109775af871e05f8f7c814e380a900d341c44f20 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Mon, 4 May 2020 10:33:54 +0000 Subject: [PATCH 2/2] Update README.md --- README.md | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index abc9709..400b0a1 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -BubelECS is Entity-Component-System architecture implementation in D language. -Library aims to delivery fast and flexible architecture for developing games. Library is @nogc and betterC compatible. Even Emscripten build works very well. -Important goal is to keep code without any external dependencies, i. eg. multithreading support don't contain any parallel execution -but emit jobs with delegate and array of dependencies. +BubelECS is Entity-Component-System architectural pattern implementation in D language. +Library aims to delivery fast and flexible architecture for developing games. Library is **@nogc** and **betterC** compatible. WASM is supported thorugh Emscripten. +Project haven't any external dependencies. BubelECS was tested on Linux, Windows, Android and WASM. @@ -13,40 +12,38 @@ BubelECS was tested on Linux, Windows, Android and WASM. ## Design -For core information about Entity-Component-System architectural pattern I recommend to read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). +For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). Main design principles are: * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly - * **Fast and safe EntityID** - every entity is referenced by its unique ID. If entity was destroyed EntityManager will return null pointer for given EntityID. Access to entity from ID is linear operation. - * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems update are generated automatically. + * **Fast and safe EntityID** - every entity is referenced by its unique ID. Accessing by ID is safe even if entity don'y exist. Access by ID is constant time operation. + * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems parallel execution are generated automatically. * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. - * **Easy systems ordering** - systems are ordered by single priority value. Order of execution of systems with same priority is undefined but order for different priorites are always preserved. - * **Flexible entity to system assignment** - system iterate over any entity that has chosen components. Components can be marked as optional so isn't required but can be used by system. Additionaly system can contain list of components which makes entity excluded from calculation. - * **Builtin events handling** - along with EntityManager library contain EventsManager which makes easier to communicate between multiple entities. - * **Hot-reload** - hot-reloading for systems should be as easy as possible. **Currently not achived yet (WIP!)**. + * **Flexible execution model** - system iterate over entities which meet specified conditions. Components can be marked as required, optional or excluded. Systems are exectued in specific order determined by system priority. + * **Builtin events handling** - library has builtin support for event handlig to makes easier communication between different entities. + * **Hot-reload** - hot-reloading for systems should be as easy as possible. In other words library should give functionality to support hot-reload of systems and components with minimal work. **(WIP!)**. -Currently library is incredibly fast to iterate over entities and fast enought in direct access to entity component if it's needed. \ There are some assumptions that should be considered when developing application: - * Iterating over same components is incredibly fast so it's should be main way of making calculations. - * Using of direct access and events should be used very wisely and not too much. + * Iterating over components is fastest way of access data so it's should be main way of making calculations. + * Using of direct access and events should be used very wisely and minimized. * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. - * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. But due to memory fragmentation there sould by many of entities with same type. In other words, sometimes making to many components can lead to performence drop even if adding or removing components is fast enough. - * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your appliactiona wisely it should be trivial to change some core logic by changing only one system, or adding new system. Every entity can easily takes some behaviour from different entity type by adding several components. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. Using too much component based marking can lead to memory fragmentation and performence drop. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your application wisely it should be trivial to change some core logic by changing only several systems or adding some new systems. Every entity can easily takes some behaviour from different entity type by adding several components. ### Features * ECS architectural pattern * Data oriented design * Safe identifiers (EntityID) - * EntityTemplates - used to add entities, contain list of components and it's data + * EntityTemplates * Basic events handling * Easy systems ordering * Automatic multithreaded jobs generating * Runtime and fast components adding and removing * Listeners for adding and removing entity components inside systems - * Passes - systems are grouped to passes. Pass update call update callback of assigned systems. + * Update passes * Calling custom callbacks for system entity groups * betterC compatibility * Emscripten compatibility @@ -54,15 +51,16 @@ There are some assumptions that should be considered when developing application ### Planned * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. - * Hot-reload support - currently only reloading systems (their functions) works and only if code changes apperas only inside functions. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. + * Hot-reload support - currently only reloading systems (their functions) works. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. * External dependencies - ability to provide dependencies between system which isn't related to components. - * Static components - this components will have different memory model and can be accessed only directly. It will be slower with access but don't trigger memory copy when component is added or some different entity was destroyed. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. - * Better EventManager - currently implementy event handling system isn't it what I wanted. I'm not sure exacly what I can improve but multithreaded event execution is one of things which I considered and it probably will work. - * More demos and examples - demo appliaction is very basic now, but in future I planned more minigames and sanbox mode (opportunity to mix many components and systems). I planed some examples to show how to use basic functionality. - * C API - this is currenly in consideration. Everything is dependent on my free time and amount of work required to create good C API. - * More smaller improvement in draft stage... + * Static components - this components will have different memory model and can be accessed only directly. It will be slower to access but won't trigger memory copy when component is added. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. + * Better EventManager - there are several optimization and improvements that can be added in the future. + * More demos and examples - demo appliaction is very basic now, but in future more minigames and sanbox mode (opportunity to mix many components and systems) are planned. + * C API - in highly depends on amount of work required. Makes possible to use library from different languages. + * GPU compute - idea in draft stage. Special components and systems whose data wolud be on GPU memory. + * More smaller improvements... -For more information about design and usage I recommend to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)**. +For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)** and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home). ## Build Instructions