Jump to content

  • Log In with Google      Sign In   
  • Create Account

Like
62Likes
Dislike

Understanding Component-Entity-Systems

By Boreal Games | Published Apr 02 2013 01:37 PM in Game Programming
Peer Reviewed by (Alpheus, Glass_Knife, evolutional)

component entity system component-entity-system architecture

The traditional way to implement game entities was to use object-oriented programming. Each entity was an object, which intuitively allowed for an instantiation system based on classes and enabled entities to extend others through polymorphism. This led to large, rigid class hierarchies. As the number of entities grew, it became increasingly difficult to place a new entity in the hierarchy, especially if the entity needed a lot of different types of functionality. Here, you can see a simple class hierarchy. A static enemy does not fit well into the tree.

Attached Image: classdiagram.png

To solve this, game programmers started to build entities through composition instead of inheritance. An entity is simply an aggregation (technically a composition) of components. This has some major benefits over the object-oriented architecture described above:

  1. It's easy to add new, complex entities
  2. It's easy to define new entities in data
  3. It's more efficient

Here's how a few of the entities above would be implemented. Notice that the components are all pure data - no methods. This will be explained in detail below.

Attached Image: compositiondiagram.png

The Component


A component can be likened to a C struct. It has no methods and is only capable of storing data, not acting upon it. In a typical implementation, each different component type will derive from an abstract Component class, which provides facilities for getting a component's type and containing entity at runtime. Each component describes a certain aspect of an entity and its parameters. By themselves, components are practically meaningless, but when used in conjunction with entities and systems, they become extremely powerful. Empty components are useful for tagging entities.

Examples

  • Position (x, y)
  • Velocity (x, y)
  • Physics (body)
  • Sprite (images, animations)
  • Health (value)
  • Character (name, level)
  • Player (empty)

The Entity


An entity is something that exists in your game world. Again, an entity is little more than a list of components. Because they are so simple, most implementations won't define an entity as a concrete piece of data. Instead, an entity is a unique ID, and all components that make up an entity will be tagged with that ID. The entity is an implicit aggregation of the components tagged with its ID. If you want, you can allow components to be dynamically added to and removed from entities. This allows you to "mutate" entities on the fly. For example, you could have a spell that makes its target freeze. To do this, you could simply remove the Velocity component.

Examples

  • Rock (Position, Sprite)
  • Crate (Position, Sprite, Health)
  • Sign (Position, Sprite, Text)
  • Ball (Position, Velocity, Physics, Sprite)
  • Enemy (Position, Velocity, Sprite, Character, Input, AI)
  • Player (Position, Velocity, Sprite, Character, Input, Player)

The System


Notice that I've neglected to mention any form of game logic. This is the job of the systems. A system operates on related groups of components, i.e. components that belong to the same entity. For example, the character movement system might operate on a Position, a Velocity, a Collider, and an Input. Each system will be updated once per frame in a logical order. To make a character jump, first the keyJump field of the Input data is checked. If it is true, the system will look through the contacts contained in the Collider data and check if there is one with the ground. If so, it will set the Velocity's y field to make the character jump.

Because a system only operates on components if the whole group is present, components implicitly define the behaviour an entity will have. For example, an entity with a Position component but not a Velocity component will be static. Since the Movement system uses a Position and a Velocity, it won't operate on the Position contained within that entity. Adding a Velocity component will make the Movement system work on that entity, thus making the entity dynamic and affected by gravity. This behaviour can be exploited with "tag components" (explained above) to reuse components in different contexts. For example, the Input component defines generic flags for jumping, moving, and shooting. Adding an empty Player component will tag the entity for the PlayerControl system so that the Input data will be populated based on controller inputs.

Examples

  • Movement (Position, Velocity) - Adds velocity to position
  • Gravity (Velocity) - Accelerates velocity due to gravity
  • Render (Position, Sprite) - Draws sprites
  • PlayerControl (Input, Player) - Sets the player-controlled entity's input according to a controller
  • BotControl (Input, AI) - Sets a bot-controlled entity's input according to an AI agent

Conclusion


To wrap up, OOP-based entity hierarchies need to be left behind in favour of Component-Entity-Systems. Entities are your game objects, which are implicitly defined by a collection of components. These components are pure data and are operated on in functional groups by the systems.

I hope I've managed to help you to understand how Component-Entity-Systems work, and to convince you that they are better than traditional OOP. If you have any questions about the article, I'd appreciate a comment or message.

A follow-up article has been posted, which provides a sample C implementation and solves some design problems. Implementing Component-Entity-Systems

Article Update Log


1 April 2013 - Initial submission
2 April 2013 - Initial publication; cleaned up formatting
29 September 2013 - Added notice of follow-up article; changed some formatting)



License


GDOL (Gamedev.net Open License)






Comments

How would systems operate on a collection of components? And what would be a good way to store components? As I undersand from the article components derive from an interface and are stored under entities. This leads to me something like :

 

 

 

class IComponent{};

class Position : public IComponent
{
public:
float x,y;
};

class Velocity: public IComponent
{
public:
float x,y;
};

class Entity
{
public:
std::vector<IComponent*> components;
};
 

 

 

Afterwards a Physics system operates on the components of entities to add velocity to the position of these entities but how does that system work and decide if a component is a specific type(dynamic casts?virtual functions in the IComponent?). Would it be better to store components like so :

 

 

 

class Entity
{
public:
std::map<std::string,IComponent*> components;
};
 

So you can give names to components and access them with those names.

 

I think it could be nice to have a pt2 which goes a bit into implementation details.

 

If performance is not an issue, this system should work fine.

 

The problem here, is that using a string map, or even an integer map if you decided to use an enum instead of strings, is that if you are looking up components in a map, and you are doing this many times per frame (in the hundreds or thousands), the performance will suffer big time.  

 

The way I have implemented the entity-component model if performance is important is to use multiple inheritance  and use the compentent classes like "mixins".  For instance, if you want a Rock to have Sprite and Velocity, per the example in the article, you would do:

 

class Rock : public SpriteComponent, public VelocityComponent

 

Now Rock has those getters/setters, and you don't have to do any icky dynamic casting or string map lookups, of course at the cost of the dynamic ability to create new entity types, since now you will have to create a new class definition for each new entity type.  Tradeoffs.

A follow-up to this article has now been posted!

 

Implementing Component-Entity-Systems

The link to the follow up article is broken.

It just needs to be peer reviewed.

EDIT: The article has been published and is now available!

Very concise article, when we created a component system, we hit the wall everyone does where you wonder how components communicate to each other. 

 

We ended up solving this with a post-office-messaging system a component would send a message to a "mailing list". And it would be sent to an entities "post office" (the world was also treated as an entity, so we could send messages to that, the parent or a colliding object etc) 

other components could subscribe and unsubscribe to mailing lists.

What was nice about the system was a component didn't have to be finished for you to use its behavior, i.e. you could fire "Play Sound" to the "Audio" mailing list and the game would run without the need to implement any form of sound player. It was very easy to swap components in and out etc, it also played nicely with the A.I. the A.I could listen for messages "Shot At" and translate them into responses for other components "Run Away".

it had less overhead cost of cycling through every component BUT it had the overhead of the over all message handling system. We felt it was a reasonable sacrifice for our game despite the fact it was an RTS and it handled it quite well. 

I look forward to reading your follow up article :)

How would you obtain values from some component which is in some entity. For example your player object has velocity(x,y). How would you obtain this from some random object?

 

Would you have getVelocity() accessor for every entity which returns x,y if they are there or return component itself?

 

Or something else? :)

في الآونة الاخيرة اصبحت العاب بنات تحتل شهرة كبيرة داخل النت واصبه لديها عدة معجبين ولهذا فان موقع العاب بنات يقدم لكم تشكيلة جيدة ومتجددة باستمرار ودائما يقدم حصريات مميزة وهي بدورها تتضمن عدة اصناف جميلة ويعشقها الكتير وخاصة البنات منها العاب تلبيس ومكياج التي تمزج بين التلبيس وكذلك الميك اب في آن واحد هذا الامر الدي يزيد من جمالها وتجعل كل من يلعبها يستمتع بذلك ويتم وضع العاب جديدة كل اسبوع لهذا ندعوكم الى زيارة موقع العاب تلبيس بنات من اجل التشجيع على المواصلة بنفس النهج وبالتوفيق للجميع .


Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.




PARTNERS