Sign in to follow this  
Sappharos

Entity Systems

Recommended Posts

Sappharos    140
EDIT: I understand that an entity system isn't necessarily a good idea in the first place, I'm going along with it for now. Also I apologise if this seems like a cloned thread, there are a couple of similar ones.

I've read up on several threads and articles to do with Entity Systems - some parts of it aren't fitting very well in my head, but this is the simplistic model I have so far: Individual classes such as PositionComponent and AnimationComponent are created, with constructors that register them to a single instance of ComponentManager. There is then a single Entity class which is a 'pure aggregation', composed of a set of pointers to components, thusly:

[code]
Class PhysicsComponent
{
// variables directly declared here, e.g.:
// - vectors for position and velocity
// - rotation matrix
};

Class Entity
{
PhysicsComponent *physicsComponent;
ParticleComponent *particleComponent;
InputComponent *inputComponent;
AIComponent *aiComponent;
CombatComponent *combatComponent;
AnimationComponent *animationComponent;
// etc
};
[/code]

1) How 'should' on-a relationships between objects be handled? Consider a cuirass worn by a mounted knight, on a ship (assuming that the cuirass, knight, horse and ship are all individual entities with their own properties). My approach would be to use an additional SceneGraphComponent or ChildrenComponent, however I don't know if this could possibly work:

[code]
class ChildrenComponent
{
std::list<Entity*> children;
};
[/code]

2) In theory, where necessary the object's type is inferred from those pointers which are not set to NULL. If this doesn't work, and I need to add a variable for the object type, should this variable be directly contained by the Entity object (thus breaking the idea of a pure aggregation) or by yet another component which is used by all entities?

3) Would (2) also apply to an object ID, for file I/O ? Edited by Sappharos

Share this post


Link to post
Share on other sites
LorenzoGatti    4442
[list][*]What's the point of wanting the Entity to be a "pure aggregation"? If every Entity has a type tag, it should be an Entity member variable. Components are pointers because they are optional; like in normal object-oriented design, anything mandatory should be a member.[*] By the way, what do you need type tags for? Both entities and collections of components contain objects or pointers of known types, and then you can rely on polymorphism. Segregating component collections by concrete types is perfectly reasonable.[*]Regarding strong typing, putting [code]std::list<Entity*> children[/code] in the entity sucks. The only things you can do with such a list are generic, like drawing or moving all descendants; armour needs specific data structures, plausibly an ArmourComponent rather than dumb Entities.[*]You seem confused between read-only data that is shared between similar Entities and data that represents the state of a single Entity. For example a "PhysicsComponent" conflates shape and material properties of a certain type of thing (immutable) and the current position, velocity, fractures etc. of each object that was created with that shape.[/list]

Share this post


Link to post
Share on other sites
Krohm    5030
People at Unity think having pointers set to [font="Courier New"]nullptr [/font]is just fine. Obviously they do it by references but that's the same. It's just a choice. Sure as hell it is a good choice for documentation "just set this pointer to <object> to make the entity own a <object> component". OOP-wise I don't like the approach either but I would not dismiss it so fast.


[quote]1) How 'should' on-a relationships between objects be handled?[/quote]It is my understanding you have no other choice than doing the generic list approach unless you want to provide n+1 calls such as [font="Courier New"]GetSubComponentTYPE()[/font]. The n calls are for the components you know, the +1 is for the component you just wrote and forgot to add. :P
In general, a language with introspection/reflection will make it easier. Note that, according to the thread I have myself spawned a couple of days ago, it seems reasonable the components would just "live by themselves".

On a slightly offtopic note, I have been noted to not use the term "SceneGraph" (unless you're propagating state which is evil). You probably want to use TransformationGraph or VisibilityGraph. Back to topic...

[color="#1C2837"][size="2"][quote]2) In theory, where necessary the object's type is inferred from those pointers which are not set to NULL. If this doesn't work...[/quote]Type of what? Of the aggregating class? Why should that fail?[/size][/color]
[color="#1C2837"] [/color]
[color="#1C2837"][size="2"][quote][/size][/color][color="#1C2837"][size="2"]and I need to add a variable for the object type, should this variable be directly contained by the Entity object (thus breaking the idea of a pure aggregation) or by yet another component which is used by all entities?[/quote]Slap them in a generic array of pointers. It sidesteps the problem by allowing you to build the class "as you need" on a object-by-object basis. Which is the whole point of the component model. But if you want to go that way, I'd add it in a derived class.[/size][/color]
[color="#1C2837"] [/color]
[color="#1C2837"][size="2"][quote]3) Would (2) also apply to an object ID, for file I/O ? [/quote]I think I don't see the connection. Personally my object ID is in the Object class and has nothing to deal with IO. Would you elaborate?[/size][/color]

Share this post


Link to post
Share on other sites
Sappharos    140
[size="2"]Thanks for the responses. :)

@[b]LorenzoGatti[/b]:
[quote]What's the point of wanting the Entity to be a "pure aggregation"? If every Entity has a type tag, it should be an Entity member variable. Components are pointers because they are optional; like in normal object-oriented design, anything mandatory should be a member.[/quote]
So there's no reason to make sure the only member variables of an Entity are components? Good, that makes things simpler.
[quote]By the way, what do you need type tags for? Both entities and collections of components contain objects or pointers of known types, and then you can rely on polymorphism. Segregating component collections by concrete types is perfectly reasonable.[/quote]
I thought type tags might be necessary in case I needed to perform a type-specific operation on an entity without knowing its type, if that makes any sense. Or could all operations be managed by components?

I'm not sure what a component collection is - is it the structure that manages every single component of a certain type in the game?
[quote]Regarding strong typing, putting [code]std::list<Entity*> children[/code] in the entity sucks. The only things you can do with such a list are generic, like drawing or moving all descendants; armour needs specific data structures, plausibly an ArmourComponent rather than dumb Entities.[/quote]
Okay, but I somehow need to find a way to link entities up so that they move together - holding pointers to the children entities was the only idea I had. :mellow:
[quote]You seem confused between read-only data that is shared between similar Entities and data that represents the state of a single Entity. For example a "PhysicsComponent" conflates shape and material properties of a certain type of thing (immutable) and the current position, velocity, fractures etc. of each object that was created with that shape.[/quote]
How should such immutable properties be held?

@[b]Krohm[/b]:
I think some confusion was caused by me using the terms "object" and "entity" interchangeably - sorry, I meant the same thing.
[quote]
People at Unity think having pointers set to [/size][font="Courier New"][size="2"]nullptr [/size][/font][size="2"]is just fine. Obviously they do it by references but that's the same. It's just a choice. Sure as hell it is a good choice for documentation "just set this pointer to <object> to make the entity own a <object> component". OOP-wise I don't like the approach either but I would not dismiss it so fast.[/quote]
What's the alternative? I considered making a component base class and putting a list of these into entity - so if it has only a PhysicsComponent and an AnimationComponent, the list would have 2 elements. This however raises the possibility of an object having more than one component of a type; isn't this bad?

[quote]It is my understanding you have no other choice than doing the generic list approach unless you want to provide n+1 calls such as [/size][font="Courier New"][size="2"]GetSubComponentTYPE()[/size][/font][size="2"]. The n calls are for the components you know, the +1 is for the component you just wrote and forgot to add. :P
In general, a language with introspection/reflection will make it easier. Note that, according to the thread I have myself spawned a couple of days ago, it seems reasonable the components would just "live by themselves".[/quote]
Sorry, I'm not sure what's meant by "the generic list approach", or components "living by themselves"... Please bear with me - I'm pretty slow with understanding this subject. :( Perhaps it would help if I just try to shove together an entity system now and see what issues need addressing, then I'll be able to relate to what you've said.

[/size][size="2"][color="#1C2837"][quote][/color][/size][size="2"]On a slightly offtopic note, I have been noted to not use the term "SceneGraph" (unless you're propagating state which is evil). You probably want to use TransformationGraph or VisibilityGraph. Back to topic...[/size][size="2"][color="#1C2837"][/quote][/color][/size][size="2"]
Well, I was thinking the position of a mounted knight will definitely depend on the position of his horse; considering the two are both individual entities, how do I relate them without propagating their positions?

[/size][size="2"][color="#1C2837"][quote]Type of what? Of the aggregating class? Why should that fail?[/color][/size][size="2"][color="#1C2837"][/quote]
I meant the type of entity [/color][/size][size="2"][color="#1C2837"]is inferred from which components it has. Is this good practice?

[/color][/size][size="2"][color="#1C2837"][quote][/color][/size][size="2"][color="#1C2837"]Slap them in a generic array of pointers. It sidesteps the problem by allowing you to build the class "as you need" on a object-by-object basis. Which is the whole point of the component model. But if you want to go that way, I'd add it in a derived class.[/color][/size][size="2"][color="#1C2837"][/quote][/color]
[/size] [size="2"]Erm... my bad. I should have asked: should the Entity class contain a variable holding the entity type, or should this variable itself be in a component? From what LorenzoGatti said, there's no reason to hold everything in components - things like entity type and ID can be held as member variables of the Entity class.

[/size][size="2"][color="#1C2837"][quote]I think I don't see the connection. Personally my object ID is in the Object class and has nothing to deal with IO. Would you elaborate?[/color][/size][size="2"][/quote]
To hold relationships between entities I wanted to somehow use pointers between them. These pointers can't be saved to file, though, so I'd need to convert them to an Entity ID instead. I guess the ID should just be a member variable of Entity; as all Entities have an ID, there's no reason to put it in an component.

Actually, there's another important gap in my understanding... I'm not even sure how components should communicate between themselves. Let's say the AI or Input component wants to change the component holding the entity's position - how would that be done?

Once again thanks for your time. :)
[/size]

Share this post


Link to post
Share on other sites
Krohm    5030
[quote name='Sappharos' timestamp='1311079761' post='4837349'][size="2"]What's the alternative? I considered making a component base class and putting a list of these into entity - so if it has only a PhysicsComponent and an AnimationComponent, the list would have 2 elements. This however raises the possibility of an object having more than one component of a type; isn't this bad?[/size][size="2"][color="#1C2837"][/quote]Only if the underlying semantics are meant to be unique. Which is possibly a good reason for which Unity goes that way.[/color][/size]
[size="2"][color="#1c2837"]
[/color][/size][size="2"][color="#1c2837"]Example of "good" multi-component: a[/color][/size][color="#1C2837"][size="2"]dding multiple "spurts of blood" to a model which was hit - attach multiple [font="'Courier New"]ParticleEmitter[/font]s to an entity.[/size][/color]
[color="#1C2837"][size="2"]Example of "bad": adding a 2nd "transform" sub-component. What transform to use?[/size][/color]
[size="2"][color="#1c2837"]
[/color][/size][quote name='Sappharos' timestamp='1311079761' post='4837349'][size="2"]Sorry, I'm not sure what's meant by "the generic list approach", or components "living by themselves"... Please bear with me - I'm pretty slow with understanding this subject. :( Perhaps it would help if I just try to shove together an entity system now and see what issues need addressing, then I'll be able to relate to what you've said.[/size][color="#1C2837"][size="2"][/quote]Those issues are were touched (although not deeply investigated) in the other discussion which I strongly suggest to read as it was very helpful to me.[/size][/color]
[color="#1C2837"][size="2"]Using the above example: suppose an entity got a particle emitter. Those sub-components don't actually need to 'tick'. They will just evolve and change state by themselves because somebody (the system managing them) know they exist. Simply because they exist. You cannot update them as as nobody guarantees (in a pure component model) entity X will get only sub-components it knows about. At best, you could 'tick' them using a generic interface.[/size][/color][color="#1C2837"] [/color]
[color="#1C2837"][size="2"]For example, say we are running in a "visual debug mode" so each "trigger entity" actually gets a "model" sub-component attached to it... or in editor mode, a sound emitter gets a speaker icon attached which will render as a billboard.[/size][/color]
[size="2"] [/size]
[size="2"][color="#1C2837"][quote][/color][/size][size="2"]Well, I was thinking the position of a mounted knight will definitely depend on the position of his horse; considering the two are both individual entities, how do I relate them without propagating their positions?[color="#1C2837"][/quote]I asked the same thing. It's not a question of doing what, pure terminology. See his [url="http://www.gamedev.net/topic/604910-scenegraph-vs-components/page__view__findpost__p__4827605"]very clear explanation[/url].[/color]

[/size][size="2"][color="#1C2837"][quote][/color][/size][size="2"][color="#1C2837"]I meant the type of entity [/color][/size][color="#1C2837"][size="2"]is inferred from which components it has. Is this good practice?[/quote]It is not relevant for a component model (and I wonder if this is possible in the first place). The type of an entity and its behavior[/size][/color][color="#1C2837"][size="2"] emerges naturally from the interactions between their internal sub-components. Perhaps you want to use a standard (perhaps inheritance-oriented) entity model?[/size]
[/color]
[color="#1C2837"][size="2"][quote][/size][/color][size="2"]Actually, there's another important gap in my understanding... I'm not even sure how components should communicate between themselves. Let's say the AI or Input component wants to change the component holding the entity's position - how would that be done?[/quote]I'm working on this right now (hence my interest in this discussion) to connect rigid body dynamics to mesh drawing. My solution for the time being is the following (but it doesn't work with dynamic composition for the time being).[/size]
[size="2"]A [font="Courier New"]RigidBody [/font]and a [font="Courier New"]Mesh [/font]are put in an "entity". The same piece of code doing that has knowledge of those two types. My [font="Courier New"]RigidBody [/font]has the ability to notify another object of position change using an interface ([font="Courier New"]TransformListener[/font]). An object of a class implementing [font="Courier New"]TransformListener [/font]is used to explicitly connect [font="Courier New"]RigidBody [/font]to [font="Courier New"]Mesh[/font]. [/size]

Share this post


Link to post
Share on other sites
Sappharos    140
Something clicked when I saw Hodgman's code, bits of it are clearer now. A general 'Entity' class, whether used as a base class or not, isn't necessary - it's probably easier to have specialised classes for each type of game object, each containing a different set of components. I don't know why but that makes things a lot simpler in my head.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this