www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Handling different types gracefully

reply "Roderick Gibson" <kniteli gmail.com> writes:
I'm asking because I'm doing some game development in D and I've 
come upon the entity component architecture, and it looks like a 
good way to handle the complexity and interdependency that games 
seem to have.

The components wind up being plain old data types (I currently 
use structs), with systems that actually modify and interact with 
them on a per-entity basis. The basic idea is that you compose 
entities (basically just an id) with various components to give 
the specific functionality you need for that particular game 
object.

The whole entity system is just a database for the different 
subsystems to query for entities (just an id) which have 
components that fulfill their criteria (for example a physics 
subsystem might only be interested in entities with the 
components position, movement, and collision, while a render 
subsystem might only be interested in entities with components 
position, mesh, sprite). There's also the reverse where the 
subsystems register which components they are looking for and 
then the entity system serves up entities that match the criteria.

The standard way to store components is just to subclass them 
from a base class "Component" and then store a pointer to them in 
a Component[] in an overall entity manager. But then you have to 
do things like type casting the pointers when you return the 
queries, which seems a bit rough. It also feels wrong to make 
them inherit a class for the SOLE reason of getting around the 
type system.

Anyway, I think I'm just rubber ducking a bit here, but I'm 
wondering if there's another way to do this, if someone has any 
experience with this sort of system.

As an example of what I'm looking for, say there is a class 
Entities, with some type of container that could hold arrays of 
different component types (this is the part that really stumps 
me). I'd like to be able to do something like:

...
auto entities = new Entities();
auto entity_id = entities.createEntity();
entities.addComponent!(position)(entity_id, pos);
entities.addComponent!(movement)(entity_id, mov);
entities.addComponent!(collision)(entity_id, col);
auto physics_data = entities.getEntitiesWithComponents!(position, 
movement, collision)();

The two big requirements are some kind of regular, queryable 
structure to hold the components (of different types), and the 
ability to filter by type. Is anything like that remotely 
possible?
Jul 01 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Roderick Gibson:

 auto entities = new Entities();
 auto entity_id = entities.createEntity();
 entities.addComponent!(position)(entity_id, pos);
 entities.addComponent!(movement)(entity_id, mov);
 entities.addComponent!(collision)(entity_id, col);
 auto physics_data = 
 entities.getEntitiesWithComponents!(position, movement, 
 collision)();

 The two big requirements are some kind of regular, queryable 
 structure to hold the components (of different types), and the 
 ability to filter by type. Is anything like that remotely 
 possible?
If the possible types are know, then there's std.variant.Algebraic, otherwise there is a free Variant or VariantN. They are not perfect, but maybe they are good enough for you. Bye, bearophile
Jul 01 2013
parent reply "Roderick Gibson" <kniteli gmail.com> writes:
On Monday, 1 July 2013 at 12:16:50 UTC, bearophile wrote:
 Roderick Gibson:

 auto entities = new Entities();
 auto entity_id = entities.createEntity();
 entities.addComponent!(position)(entity_id, pos);
 entities.addComponent!(movement)(entity_id, mov);
 entities.addComponent!(collision)(entity_id, col);
 auto physics_data = 
 entities.getEntitiesWithComponents!(position, movement, 
 collision)();

 The two big requirements are some kind of regular, queryable 
 structure to hold the components (of different types), and the 
 ability to filter by type. Is anything like that remotely 
 possible?
If the possible types are know, then there's std.variant.Algebraic, otherwise there is a free Variant or VariantN. They are not perfect, but maybe they are good enough for you. Bye, bearophile
Variant is a possiblity. How is the performance with large containers of these, since these structures will likely hold the majority of the data in the game?
 Waiting for multiple "alias this" ??
 And opDispatch to respond to unimplemented components.
I'm not sure what you mean by this.
Jul 01 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Roderick Gibson:

 Variant is a possiblity. How is the performance with large 
 containers of these, since these structures will likely hold 
 the majority of the data in the game?
You probably have to benchmark yourself. (But I have suggested an Algebraic). Bye, bearophile
Jul 01 2013
parent reply "Roderick Gibson" <kniteli gmail.com> writes:
On Tuesday, 2 July 2013 at 06:54:58 UTC, bearophile wrote:
 Roderick Gibson:

 Variant is a possiblity. How is the performance with large 
 containers of these, since these structures will likely hold 
 the majority of the data in the game?
You probably have to benchmark yourself. (But I have suggested an Algebraic). Bye, bearophile
I should know the types at compile time, so I will be using it most likely, but reading the docs it looks like Algebraic is built on top of the same structure as Variant. Is there any difference in implementation?
Jul 02 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Roderick Gibson:

 I should know the types at compile time, so I will be using it 
 most likely, but reading the docs it looks like Algebraic is 
 built on top of the same structure as Variant. Is there any 
 difference in implementation?
Take a look at the Phobos source code, it's much faster than waiting for my answer. Algebraic is built on top of VariantN. Algebraic accepts only a limited number of types, while Variant doesn't have such limitation. So Algebraic is type safe. And maybe Algebraic can ideally be implemented more efficiently than a Variant because to denote the contained type an enum suffices, instead of a TypeInfo. Please take a look at VariantN if it contains the enum or a Typeinfo or something else. Bye, bearophile
Jul 02 2013
parent "Roderick Gibson" <kniteli gmail.com> writes:
On Tuesday, 2 July 2013 at 21:45:57 UTC, bearophile wrote:
 Roderick Gibson:

 I should know the types at compile time, so I will be using it 
 most likely, but reading the docs it looks like Algebraic is 
 built on top of the same structure as Variant. Is there any 
 difference in implementation?
Take a look at the Phobos source code, it's much faster than waiting for my answer. Algebraic is built on top of VariantN. Algebraic accepts only a limited number of types, while Variant doesn't have such limitation. So Algebraic is type safe. And maybe Algebraic can ideally be implemented more efficiently than a Variant because to denote the contained type an enum suffices, instead of a TypeInfo. Please take a look at VariantN if it contains the enum or a Typeinfo or something else. Bye, bearophile
Thanks, I'll do that. Thanks for the help, bearophile!
Jul 02 2013
prev sibling parent "Anthony Goins" <neontotem gmail.com> writes:
On Monday, 1 July 2013 at 12:03:25 UTC, Roderick Gibson wrote:
 I'm asking because I'm doing some game development in D and 
 I've come upon the entity component architecture, and it looks 
 like a good way to handle the complexity and interdependency 
 that games seem to have.

 The components wind up being plain old data types (I currently 
 use structs), with systems that actually modify and interact 
 with them on a per-entity basis. The basic idea is that you 
 compose entities (basically just an id) with various components 
 to give the specific functionality you need for that particular 
 game object.

 The whole entity system is just a database for the different 
 subsystems to query for entities (just an id) which have 
 components that fulfill their criteria (for example a physics 
 subsystem might only be interested in entities with the 
 components position, movement, and collision, while a render 
 subsystem might only be interested in entities with components 
 position, mesh, sprite). There's also the reverse where the 
 subsystems register which components they are looking for and 
 then the entity system serves up entities that match the 
 criteria.

 The standard way to store components is just to subclass them 
 from a base class "Component" and then store a pointer to them 
 in a Component[] in an overall entity manager. But then you 
 have to do things like type casting the pointers when you 
 return the queries, which seems a bit rough. It also feels 
 wrong to make them inherit a class for the SOLE reason of 
 getting around the type system.

 Anyway, I think I'm just rubber ducking a bit here, but I'm 
 wondering if there's another way to do this, if someone has any 
 experience with this sort of system.

 As an example of what I'm looking for, say there is a class 
 Entities, with some type of container that could hold arrays of 
 different component types (this is the part that really stumps 
 me). I'd like to be able to do something like:

 ...
 auto entities = new Entities();
 auto entity_id = entities.createEntity();
 entities.addComponent!(position)(entity_id, pos);
 entities.addComponent!(movement)(entity_id, mov);
 entities.addComponent!(collision)(entity_id, col);
 auto physics_data = 
 entities.getEntitiesWithComponents!(position, movement, 
 collision)();

 The two big requirements are some kind of regular, queryable 
 structure to hold the components (of different types), and the 
 ability to filter by type. Is anything like that remotely 
 possible?
Waiting for multiple "alias this" ?? And opDispatch to respond to unimplemented components.
Jul 01 2013