www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Entity Component Architecture

reply vladdeSV <v vladde.net> writes:
Hi,

I have created a project, which is an Entity Component System 
(ECS)-like structural setup for projects. It is to be used as 
building blocks for (most likely) games.

I call it 'Entity Component Architecture' (ECA).

The difference from ECS to ECA is fundamentally different. ECS 
consists of three parts: the Entity, Component and it's System. 
ECS uses systems to handle the entity's logic based upon the data 
in the entity's components.

ECA however, only has two pieces, namely Entity and Component. In 
ECA, the logic of the entity is calculated in the components 
themselves, which also usually contains data.

For me personally, this approach felt more reasonable to use. The 
entities' logic is directly handled in the components, and not in 
systems (which might be scattered around in code (Can very well 
vary from dev to dev)).

Now, the main reason why I write here is because: I wrote ECA for 
a school project, and I am going to write about this type of 
project structure. Since I do not have much experience with ECS 
or bigger scale game development, what do you people think of 
this new approach?

I am searching for feedback. What do you think it's pros and cons 
are? Preformance, memory usage, scaleability, etc?

:)

---

My ECA project can be found at https://github.com/vladdeSV/eca-d
The README.md contains snippets of typical code usage, and the 
docs contain examples (specifically 'source/package.d')
Aug 24 2016
next sibling parent reply ilariel <peramaki.ilari gmail.com> writes:
On Wednesday, 24 August 2016 at 17:57:33 UTC, vladdeSV wrote:
 Hi,

 I have created a project, which is an Entity Component System 
 (ECS)-like structural setup for projects. It is to be used as 
 building blocks for (most likely) games.

 I call it 'Entity Component Architecture' (ECA).

 The difference from ECS to ECA is fundamentally different. ECS 
 consists of three parts: the Entity, Component and it's System. 
 ECS uses systems to handle the entity's logic based upon the 
 data in the entity's components.

 ECA however, only has two pieces, namely Entity and Component. 
 In ECA, the logic of the entity is calculated in the components 
 themselves, which also usually contains data.

 For me personally, this approach felt more reasonable to use. 
 The entities' logic is directly handled in the components, and 
 not in systems (which might be scattered around in code (Can 
 very well vary from dev to dev)).

 Now, the main reason why I write here is because: I wrote ECA 
 for a school project, and I am going to write about this type 
 of project structure. Since I do not have much experience with 
 ECS or bigger scale game development, what do you people think 
 of this new approach?

 I am searching for feedback. What do you think it's pros and 
 cons are? Preformance, memory usage, scaleability, etc?

 :)

 ---

 My ECA project can be found at https://github.com/vladdeSV/eca-d
 The README.md contains snippets of typical code usage, and the 
 docs contain examples (specifically 'source/package.d')
I'm sorry if this sounds rude. For a small scale project where you don't get performance problems there is nothing wrong this approach if it fits your purpose. Ask, profile, fix bottlenecks and optimize. The approach itself is not new, but instead a failed one which ECS in general avoid due to inefficiency caused by virtual function calls and bad cache locality. Your "ECA" approach itself is "flawed". It is merely another term for OOP in this case. You have entities which have components which are polymorphic objects implementing virtual functions. You are basically throwing away the good parts of ECS. One of the strengths of ECS is that you compute in tight loops with as little indirection/branching based on existence of components. In your example usage you query for existence of a position component so that you can move an entity in your movement component if said component exists. In an ECS this would be solved by requiring Velocity/Movement-System to require entity to have a position and a velocity component after all something without a position cannot move. I recommend you to read the pages at http://entity-systems-wiki.t-machine.org/ and also 10/10 for effort.
Aug 24 2016
parent vladdeSV <v vladde.net> writes:
On Wednesday, 24 August 2016 at 21:09:36 UTC, ilariel wrote:
 I'm sorry if this sounds rude.
No problem.
 For a small scale project where you don't get performance 
 problems there is nothing wrong this approach if it fits your 
 purpose. Ask, profile, fix bottlenecks and optimize.
 The approach itself is not new, but instead a failed one which 
 ECS in general avoid due to inefficiency caused by virtual 
 function calls and bad cache locality.

 Your "ECA" approach itself is "flawed". It is merely another 
 term for OOP in this case. You have entities which have 
 components which are polymorphic objects implementing virtual 
 functions. You are basically throwing away the good parts of 
 ECS.
If we don't compare it to ECS, could there be any improvements to this structure?
 One of the strengths of ECS is that you compute in tight loops 
 with as little indirection/branching based on existence of 
 components. In your example usage you query for existence of a 
 position component so that you can move an entity in your 
 movement component if said component exists. In an ECS this 
 would be solved by requiring Velocity/Movement-System to 
 require entity to have a position and a velocity component 
 after all something without a position cannot move.
When I was designing I intended multiple features being able to happen , in the same update call, depending on what compnents exist. Ex. if poisoned compnent existe, movement will be slowed. I do not fully understand how ECS work, but does the entities require systems for all different component combinations?
 I recommend you to read the pages at 
 http://entity-systems-wiki.t-machine.org/ and also 10/10 for 
 effort.
Will do! Thank you for your reply :)
Aug 26 2016
prev sibling next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Wed, 24 Aug 2016 17:57:33 +0000, vladdeSV wrote:
 I am searching for feedback. What do you think it's pros and cons are?
 Preformance, memory usage, scaleability, etc?
It's like thirty lines of code and does almost nothing that I need. Why no `getOrAdd`? Why no ID? Why is there nothing to help me find all components of a given type? Where's the reference back from Component to Entity? How do I get all components on an entity that implement a given interface? Why do all components need to have `update()` and `active`? I really don't think the problem your library is addressing is both complex enough and standardized enough to reasonably turn it into a library.
Aug 24 2016
parent reply vladdeSV <v vladde.net> writes:
On Wednesday, 24 August 2016 at 22:26:00 UTC, Chris Wright wrote:
 It's like thirty lines of code and does almost nothing that I 
 need.
I've never done anything similar to this. I do not know what others might need.
 Why no `getOrAdd`?
Entity has getComponent and addComponent which do different things.
 Why no ID?
I simply found no use of them in the small test I did.
 Why is there nothing to help me find all components of a given 
 type?
An Entity must only have one (1) of a component type. I have not found a use of having two of the same components.
 Where's the reference back from Component to Entity?
In my implementation, via the `void update(Entity e)` method. Update is the only part of a component which interacts with the Entity.
 How do I get all components on an entity that implement a given 
 interface?
Never thought of this. That could come in handy, but I, personally, do not see any use of it.
 Why do all components need to have `update()` and `active`?
`update(Entity e)` is the core of ECA, `active` is something I added in which simply allows components to have an on/off state. Not necessary though.
 I really don't think the problem your library is addressing is 
 both complex enough and standardized enough to reasonably turn 
 it into a library.
I think you see this as ECS, which it is not. This system only uses the terms Entity and Component, but does not behave in the way ECS does. When it comes to this approach, it is definitely not the way traditional ECS should behave. But this is not ECS. It is ECA.
Aug 26 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Fri, 26 Aug 2016 19:30:43 +0000, vladdeSV wrote:

 On Wednesday, 24 August 2016 at 22:26:00 UTC, Chris Wright wrote:
 It's like thirty lines of code and does almost nothing that I need.
I've never done anything similar to this. I do not know what others might need.
 Why no `getOrAdd`?
Entity has getComponent and addComponent which do different things.
Null safety is awesome.
 Why no ID?
I simply found no use of them in the small test I did.
The absence makes serialization a lot harder.
 Why is there nothing to help me find all components of a given type?
An Entity must only have one (1) of a component type. I have not found a use of having two of the same components.
I want to broadcast a message to all players. Your library doesn't help me do that.
 Where's the reference back from Component to Entity?
In my implementation, via the `void update(Entity e)` method. Update is the only part of a component which interacts with the Entity.
I've found it useful quite often. My procedural generation code tends to store references to rooms and such directly so as not to incur a lookup cost as often. (The cost being having to write the code more than computation time.) Then sometimes I need to look at other components, which means I need the attached Entity. Also, for serialization, if Entity is an opaque ID, that makes it easy to serialize references between entities.
 How do I get all components on an entity that implement a given
 interface?
Never thought of this. That could come in handy, but I, personally, do not see any use of it.
The `update()` method on Component is you hard-coding that for one specific member function.
 I really don't think the problem your library is addressing is both
 complex enough and standardized enough to reasonably turn it into a
 library.
I think you see this as ECS, which it is not.
Which seems to be something you invented that's loosely inspired by ECS. Your version has less implementation complexity than ECS, though, which means it's less valuable as a library. For instance, in ECS, you tend to store components separate from entities (because an entity is just an ID), so an ECS library would provide efficient querying capabilities for components, both by ID and by type. This is probably simple but might have some quirks that would recommend using an existing implementation.
Aug 26 2016
prev sibling parent reply MrSmith <mrsmith33 yandex.ru> writes:
On Wednesday, 24 August 2016 at 17:57:33 UTC, vladdeSV wrote:
 I am searching for feedback. What do you think it's pros and 
 cons are? Preformance, memory usage, scaleability, etc?
Your solution is basically OOP with composition used. It is enough for convenience, but not enough for speed. Also memory allocation for each component looks scary. Systems simply iterate over a all entities that have given set of components. Check my solution API https://gist.github.com/MrSmith33/e861a289d295ec4659a0 I have query maker that iterates over smallest collection and gets other components. Full code is here https://github.com/MrSmith33/voxelman/tree/master/source/datadriven. WIP. Here is example of usage (single component used here though) https://github.com/MrSmith33/voxelman/blob/master/plugins/test/entitytest/plugin.d
Aug 26 2016
parent reply vladdeSV <v vladde.net> writes:
On Friday, 26 August 2016 at 16:34:26 UTC, MrSmith wrote:
 Your solution is basically OOP with composition used. It is 
 enough for convenience, but not enough for speed. Also memory 
 allocation for each component looks scary.
 Systems simply iterate over a all entities that have given set 
 of components.
 Check my solution API 
 https://gist.github.com/MrSmith33/e861a289d295ec4659a0
 I have query maker that iterates over smallest collection and 
 gets other components. Full code is here 
 https://github.com/MrSmith33/voxelman/tree/master/source/datadriven. WIP.
 Here is example of usage (single component used here though) 
 https://github.com/MrSmith33/voxelman/blob/master/plugins/test/entitytest/plugin.d
What I can conclude so far is my approach uses a lot of processing power. I did a test where I generated 10000 entities and it drained my CPU to 50%. All feedback is appreciated. Thank you for your input :)
Aug 26 2016
parent reply Lurker <lurker gmail.com> writes:
On Friday, 26 August 2016 at 19:55:30 UTC, vladdeSV wrote:
 What I can conclude so far is my approach uses a lot of 
 processing power. I did a test where I generated 10000 entities 
 and it drained my CPU to 50%.

 All feedback is appreciated. Thank you for your input :)
hasComponent()/getComponent() should be O(1) and preferrably CTFEable. You could turn Entity into a template, or store a bitmask of applied Components etc.
Aug 26 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Fri, 26 Aug 2016 23:59:05 +0000, Lurker wrote:

 On Friday, 26 August 2016 at 19:55:30 UTC, vladdeSV wrote:
 What I can conclude so far is my approach uses a lot of processing
 power. I did a test where I generated 10000 entities and it drained my
 CPU to 50%.

 All feedback is appreciated. Thank you for your input :)
hasComponent()/getComponent() should be O(1) and preferrably CTFEable. You could turn Entity into a template, or store a bitmask of applied Components etc.
Which requires specifying in advance every component the system contains. Part of the reason for using a loose component architecture like this is making it trivial to add features that require additional data. I suppose you could do this with runtime reflection -- iterate through all modules, then all classes in those modules, check each to see if it's convertible to Component, then generate the bitfield. Awkward.
Aug 26 2016