Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Component Based Entity System

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Component Based Entity System
tolgagerekci
Member #14,293
May 2012

I'm making a game framework using allegro5. I have read many article about entity systems and i decided to go "component aggregation" method. And i did some search on google but can't found any usage examples of this method. I only found an entity framework called "artemis"(for java) but in its classes there is no method like "GetComponent". Entity creation part is ok

Entity wall;
wall.AddComponent( new PositionComponent() );
wall.AddComponent( new SpriteComponent("wall.png") );
wall.AddComponent( new RenderComponent() );

But how can do actions? For example how can i move my entity etc.

Thanks

AMCerasoli
Member #11,955
May 2010
avatar

Read the T=Machine blog. It's what I read... At the end I implemented my own version but it helps you a lot.

SiegeLord
Member #7,827
October 2006
avatar

Here's how my latest component-based framework works. It's written in D, but in principle should be doable in C++ too. Pseudo code:

#SelectExpand
1class Component 2{ 3 void WireUp(Entity* entity) { } 4} 5 6class Position : Component 7{ 8 int X, Y; 9} 10 11class Velocity : Component 12{ 13 void WireUp(Entity* entity) 14 { 15 Pos = entity.GetComponent("position"); 16 assert(Pos); 17 18 /* Use your favourite Signal/Slot library here, I obviously implemented my own */ 19 Game->UpdateEvent.Register(&Update); 20 } 21 22 void Update() 23 { 24 Pos->X += Vx; 25 Pos->Y += Vy; 26 } 27 28 Position* Pos; 29} 30 31class Entity 32{ 33 void AddComponent(Component* component) 34 { 35 Components.push_back(component); 36 } 37 38 39 Component* GetComponent(char* name) 40 { 41 // Blah blah blah 42 } 43 44 void WireUp() 45 { 46 for(comp : Components) 47 comp->WireUp(this); 48 } 49 50 vector<Component*> Components; 51} 52 53class Game 54{ 55 Game() 56 { 57 /* Obviously can use a configuration file driven factory here */ 58 auto new_entity = new Entity; 59 new_entity->AddComponent(new Velocity); // Order doesn't matter 60 new_entity->AddComponent(new Position); 61 new_entity->WireUp(); 62 63 auto velocity = dynamic_cast<Velocity*>((new_entity->GetComponent("velocity")); 64 /* Start it moving */ 65 velocity.Vx = 5; 66 67 Entities.push_back(new_entity); 68 } 69 70 void Update() 71 { 72 UpdateEvent.Trigger(); 73 } 74 75 vector<Entity*> Entities; 76 MagicalSlot UpdateEvent; 77}

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Stas B.
Member #9,615
March 2008

But how can do actions? For example how can i move my entity etc.

By having something else that can access and modify the position component. That can either be another component (if your components implement logic) or a subsystem responsible for moving entities (if your components are simple data containers).

AMCerasoli
Member #11,955
May 2010
avatar

SiegeLord said:

#SelectExpand
1class Velocity : Component 2{ 3 void WireUp(Entity* entity) 4 { 5 Pos = entity.GetComponent("position"); 6 assert(Pos); 7 8 /* Use your favourite Signal/Slot library here, I obviously implemented my own */ 9 Game->UpdateEvent.Register(&Update); 10 } 11 12 void Update() 13 { 14 Pos->X += Vx; 15 Pos->Y += Vy; 16 } 17 18 Position* Pos; 19}

Stas B. said:

That can either be another component (if your components implement logic)

One of the beneficial part of making an entity system is avoid having methods inside components.

SiegeLord
Member #7,827
October 2006
avatar

One of the beneficial part of making an entity system is avoid having methods inside components.

Everybody has a different definition of what makes a component system. For me, the primary benefit is runtime composition and freedom from class hierarchies.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

AMCerasoli
Member #11,955
May 2010
avatar

Well yhea, that's an important one too. :)

Stas B.
Member #9,615
March 2008

One of the beneficial part of making an entity system is avoid having methods inside components.

And what exactly is the huge benefit of not being able to do logic inside components? Sometimes subsystems make the most sense. Sometimes not.

AMCerasoli
Member #11,955
May 2010
avatar

Well, an entity system as the name suggest is based on entities and systems.

Entities are just data. An entity is composed by components, and at the same time those components have their own systems (separated).

Each component has its own system which controls it. And each system is dedicated to just one component.

Ideally one entity should have just one system, but that's not practical because you would need to rewrite too much code sometimes, for that reason each entity is able to have multiple components.

But at any time you should be able to split components as you want. Just create a new system to handle that part and that's it.

Therefore, having methods inside components would mix everything up.

If you have methods inside components you're almost inside the OOP world and that's not how an entity system works. You could even get tempted to inherit some class and that's it, you have screwed the whole system...

Thomas Fjellstrom
Member #476
June 2000
avatar

Hmm, wouldn't putting the methods inside the component make it its own system? I don't see the harm in that at all. I'm not sure what it would even look like with the implementation split off from the component (not sure what the point is either).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Stas B.
Member #9,615
March 2008

Well, an entity system as the name suggest is based on entities and systems.

I remember the days when entity systems were systems that handled entities. ???
Anyway, your post completely ignores the question of why components that do their own logic are essentially bad and why they and subsystems are mutually-exclusive.

AMCerasoli
Member #11,955
May 2010
avatar

What is the difference between a component which handle its own logic or an object which handle its own logic... You just changed the name and magically have created and entity system? :-/

The goodies of an entity system are easier to see when you're programming an MMOG.

A component which handles its own logic is just and object; like:

class{
   private:
      int x,y;
   public:
      void move();
      void export();
};

... So it's not a component.

I can't imagine a component with its own method to handle logic because then instead of adding components I would just use inheritance.

Components allow you to make any entity do whatever you want without having to rewrite code and without having to use inheritances (which usually ends up with a bloated supper class incredible difficult to maintain).

I don't really have the time to explain you this by myself, but I'm following the blog that posted earlier. There is everything explained.

To me, this is in a new level, it's like using a RDBMS. Databases have the data, and you do whatever you want with the data, this gives you an incredible freedom that mos OOP programmers (as myself) are not used to.

If you have used a RDBMS before you will know what I'm talking about, maybe there is no problem having method inside the components I have no idea, but I wouldn't never do that now that I know this method.

SiegeLord has a vector of components inside his entities, my entities are just Id's...

class{
   public
      int id;
};

Thomas Fjellstrom
Member #476
June 2000
avatar

... So it's not a component.

Maybe we're just not talking about the same thing? When I (and I assume most everyone here) say component, we mean just a single bit of functionality of a larger object (entity). Like say the position, velocity or collision. Instead of combining them all into one single object, your entity class just holds a list of components, and those components each take care of one of those properties.

Quote:

SiegeLord has a vector of components inside his entities, my entities are just Id's...

How is that even useful? You still have the data and code for them stored elsewhere, so those are the actual entities. That list of ids are really just indexes or tags for the real entities.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Stas B.
Member #9,615
March 2008

What is the difference between a component which handle its own logic or an object which handle its own logic...

The difference is that you can construct your objects from small and reusable blocks that can be added or removed in real-time, which is the basic idea behind any component-based system.

Quote:

I can't imagine a component with its own method to handle logic because then instead of adding components I would just use inheritance.

I can imagine that. I guess SiegeLord can imagine that. The creators and users of Unity3D can imagine that, just to name a few. It offers many adventages over inheritance.

Quote:

maybe there is no problem having method inside the components I have no idea, but I wouldn't never do that now that I know this method.

Now we're getting closer to the root of the problem. ;)
Maybe you should consider some alternatives and their pros and cons. There are no magic bullets. Subsystems are overkill for most things from my experience. There is no inherent value in putting the data and logic in separate classes.

AMCerasoli
Member #11,955
May 2010
avatar

When I (and I assume most everyone here) say component, we mean just a single bit of functionality of a larger object (entity). Like say the position, velocity or collision.

Well, to me that's wrong. Position an velocity are components, but collision is not a component, because collision is something that happens and not just data. In case you mean collision as data describing how to perform collision detection then it's component, but if you mean collision as checking for collision detection then to me that is not a component.

Quote:

How is that even useful?

It's useful when you create the entity system as the blog I posted earlier (which I said I'm not going to explain here again), now I think I have improve the system a little bit, but maybe I haven't.

The ES in the blog execute "queries" to get all the components of an entity, and perform actions on that data and for doing so you need an ID. Now, since each system is made to process data of a specific component/components I have decided to create a map for each component in my videogame, that way I don't have to execute the "queries" all the time. I actually made that comment on the blog and guy told me that I should prove it, at least he didn't say a big NO! hehehe.

Stas B. said:

The difference is that you can construct your objects from small and reusable blocks that can be added or removed in real-time, which is the basic idea behind any component-based system.

Yep indeed, but with no methods is better... To me, though.

Quote:

I can imagine that. I guess SiegeLord can imagine that. The creators and users of Unity3D can imagine that, just to name a few. It offers many adventages over inheritance.

Good...

Quote:

Now we're getting closer to the root of the problem.

Yes, and now you feel better.

Quote:

There is no inherent value in putting the data and logic in separate classes.

My god! :o

Thomas Fjellstrom
Member #476
June 2000
avatar

That sounds incredibly over engineered. I used to have a habit of doing that. I find it wastes a very large amount of time and effort for little to no gain.

Well, to me that's wrong. Position an velocity are components, but collision is not a component, because collision is something that happens and not just data. In case you mean collision as data describing how to perform collision detection then it's component, but if you mean collision as checking for collision detection then to me that is not a component.

::) Fine nitpick all you want. Collision was just a part of a given entity that could be pulled out into its own component. Ie: its own data+methods. That is to say, the new component class could have a polygon or rectangle to check against, and possibly some kind of collide() or doesCollide() method.

You are clearly not talking about the same kind of "components" that everyone else is in this thread. I think you are talking about properties. As in the base properties of a given thing. Like its location in the world. Sure that can live without code. But its not very useful that way. The kind of component everyone else is talking about is a functionality slice, which needs both data, and some code in order to make that data useful.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

SiegeLord
Member #7,827
October 2006
avatar

The thing I don't like about explicitly separating data from logic is that the representation of data can be logic dependent, and once you commit to a certain data representation you are left out dry if it doesn't allow what you want with it.

For example, say your entity needs a position... for most entities you'd need an X and a Y position, so you make a data component that other systems can use. Now imagine an entity that rotates around a point (let's say it's the origin). So, you create a new data component with an angle and a radius and a system to update the X and Y given the angle and radius.

Now, there are two issues with this example:

  1. What's the point of the X and Y variables in the rotating entity? Angle and radius already determine the position of the entity and X and Y are vestigial.


  2. Even though the angle/radius data component is separate from the associated system, they are still tailored to each other and the data was added because of the system's requirements and not vice-versa. Ultimately you are still tying data and system together.

Now in my system the position component would be an interface that could be implemented by something with an angle/radius or an X/Y.

Here's a different example... again with positions. Say you're using an external physics engine... that engine already takes care of the positions of different entities. How would you use that external engine in a component system? If you're just using the data components, you'd have to use those vestigial X/Y variables. How about making a dedicated physics component? Well, in that case you're stuck having physics enabled for every object, even things that don't need to have physics (e.g. lights). If you use interface components then you don't have an issue: the physics component would simply implement the position interface.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Stas B.
Member #9,615
March 2008

Yes, and now you feel better.

I feel sad because you don't seem to get the point. (Specifically, that maybe you're just being a little narrow-minded here.) :'(

Quote:

My god!

Yeah, I'm sorry to have to break it to you, but solutions don't have an inherent value. A solution that solves a problem I don't have is worthless to me. You don't seem to have any idea what problems your particular system is designed to solve. ::)

SiegeLord said:

For example, say your entity needs a position... for most entities you'd need an X and a Y position, so you make a data component that other systems can use. Now imagine an entity that rotates around a point (let's say it's the origin). So, you create a new data component with an angle and a radius and a system to update the X and Y given the angle and radius.

Have a transform component. Rotation around a point is a transformation. ???

Quote:

Here's a different example... again with positions. Say you're using an external physics engine... that engine already takes care of the positions of different entities. How would you use that external engine in a component system?

Use the values from the physics engine to set the object's transformation.

Quote:

Now in my system the position component would be an interface that could be implemented by something with an angle/radius or an X/Y.

Sounds like major overkill.

AMCerasoli
Member #11,955
May 2010
avatar

SiegeLord said:

For example, say your entity needs a position... for most entities you'd need an X and a Y position, so you make a data component that other systems can use. Now imagine an entity that rotates around a point (let's say it's the origin). So, you create a new data component with an angle and a radius and a system to update the X and Y given the angle and radius.

Yay I like problems.

Ok if I have an entity1 that has a position, a static position and then I draw an entity (entity2) near to entity1, entity1 should start rotating around entity2.

In this case my component for entity1 would be just a boolean, something like bool gravity = true and my entity2 would have another boolean something like bool point_of_gravity = true.

So I create a system called void perform_point_of_gravity() and another one called void perform_gravity().

void perform_point_of_gravity() will search all the entities inside the std::map<int, GRAVITY_COMP*> and execute the algorithm to attract the entity to the entities inside the std::map<int, POINT_OF_GRAVITY_COMP*> it doesn't matter what kind of entity it is, if it has a ´GRAVITY_COMP´ the system will start changing its X and Y coordinates.

This function only attracts entities while the entity itself remain static, If we add the same GRAVITY_COMP to both entities and create another system more generic called void perform_gravity() then the two entities would start trying to rotate around each other.

Quote:

What's the point of the X and Y variables in the rotating entity? Angle and radius already determine the position of the entity and X and Y are vestigial.

There are other system that need that data, the rendering system, or the collision detection, I'm actually trying to make videogames not trying to figure out the most bizarre situations.

Quote:

Even though the angle/radius data component is separate from the associated system, they are still tailored to each other and the data was added because of the system's requirements and not vice-versa. Ultimately you are still tying data and system together.

There are system that use the data for different purposes than other system. If one system needs more data just to actually make that system work then you just add another component to the entity to that specific system. And indeed the data is most of the time made for one specific system, but it doesn't have to be all the time. Just like when you create methods inside and object which performs operations in that specific data of the object.

SiegeLord
Member #7,827
October 2006
avatar

Stas B. said:

Have a transform component. Rotation around a point is a transformation. ???
Use the values from the physics engine to set the object's transformation.

What does a light need with a transformation? Or anything that doesn't need to be rotated for that matter? What you did here is the god object anti-pattern except applied to components.

Quote:

Sounds like major overkill.

Overkill in what sense? It'll save on useless data and take less code to implement.

Yay I like problems.

Problems you completely misunderstand? :P I didn't mention gravity, or attraction whatsoever.

Ignoring that, yes, I see your point. It is nice how separating logic from data allows you to add completely new behaviors to entities without actually changing the entities themselves. I still wouldn't code it that way and use interfaces instead.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Oscar Giner
Member #2,207
April 2002
avatar

I think the point of having the methods in a separate system class is because this way such function can perform an operation that operates on more than one component (for example, a CollisionSystem may work with polygons and circles, and allow any kind of combination between the two, and at the same time being able to add new kind of objects easily, because all the collision code is in a single place). Having the collision code in a Polygon class doesn't make that much sense either, since Polygons may be used for other things where you don't want any kind of collision detection.

Also, refactoring is easier: if you want to split a component in 2 different ones (or join 2 components into one), you only need to update the system(s) that uses that component without altering code in any other place. Well you may need to alter the creation function if the model is hard-coded.

Also, if you go to other languages (like java or c#) where all methods are "virtual" (or SiegeLord's method using interfaces since they'll need to be virtual (that WireUp method need to be virtual or things won't work ;))), having the methods in the components (which may be thousands of instances of each one) will have both a bigger memory footprint and performance hit than if it's on a system class (since there's only one instance of each system).

At least, that's what I get after reading AMCerasoli's link, and this one. Both seem to agree about what an Entity System is. What you people are describing is an OOP design with some component based thing on top of it, which doesn't mean it's a bad thing, but it's not an Entity System. From the reads it looks like a pure Entity System is mostly useful for bigger projects, with several people working on it and probably not that useful for small/medium projects.

Here's another implementation. This one doesn't even have an Entity class, entities are just integer ID's. -(edit: after reading that page a bit better, it's actually a full programing language that uses the Entity System paradigm)- (edit2: I was reding something else and mixed things up, forget the edit :-X).

Disclaimer: this is my understanding, but I've never used this method. Although I want to try it.

SiegeLord
Member #7,827
October 2006
avatar

having the methods in the components (which may be thousands of instances of each one) will have both a bigger memory footprint

Number of methods has nothing to do with the memory footprint :-/ (certainly not one scaled by the number of instances).

The other blog has a somewhat saner implementation (no more wtf queries or std::maps), but it still has the problem of data duplication.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Stas B.
Member #9,615
March 2008

SiegeLord said:

What does a light need with a transformation?

Because it has an offset from the world origin. Or maybe it's a rotating light. If you don't want your light to be transformable, don't add a transformation component to it.

Quote:

What you did here is the god object anti-pattern except applied to components.

Yeah. That horrible god-object is called a transformation matrix. :P

Quote:

Overkill in what sense?

Overkill in the sense that it took me a minute to understand what you're even talking about and given your examples, I seriously doubt it solves any problems that aren't solvable by simply having sane components. :P

I think the point of having the methods in a separate system class is because this way such function can perform an operation that operates on more than one component (for example, a CollisionSystem may work with polygons and circles, and allow any kind of combination between the two, and at the same time being able to add new kind of objects easily, because all the collision code is in a single place). Having the collision code in a Polygon class doesn't make that much sense either, since Polygons may be used for other things where you don't want any kind of collision detection.

That's a perfect example of when subsystems are useful. I use subsystems when they're convenient and logic inside components when that's convenient, in the same projects. I don't really see the problem.

SiegeLord
Member #7,827
October 2006
avatar

Stas B. said:

I seriously doubt it solves any problems that aren't solvable by simply having sane components. :P

Well, show me a solution using these "sane" components that doesn't involve data duplication.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Oscar Giner
Member #2,207
April 2002
avatar

SiegeLord said:

Number of methods has nothing to do with the memory footprint (certainly not one scaled by the number of instances).

Virtual tables. Each instance need its own virtual table, and each method is an extra entry on each object's virtual table.

Quote:

but it still has the problem of data duplication.

What data duplication? in one of the steps it shows how that is removed, there's no duplicated data in the final implementation.

 1   2 


Go to: