Entity Systems

Updated at 2014-06-14 01:19

Entity system is a software architecture pattern where you have individual components and composition of components is used instead of inheritance.

  • Functional programming is all about creating behaviour using functions.
  • Object-oriented design has classes which are used to create object instances. All behaviour in the classes and instances of those classes.
  • Entity system design uses systems, which contain entities which are made up with components. All behaviour is in the systems and components have only data.

Each entity is a concrete item which themselves have no data or behaviour. You can think them as an unique label for an object or container i.e. globally unique identifier.

If you have 100 identical tanks, you have 100 entities, not 1.

Each component is a possible aspect of a system item. Component is a chunk of stuff that provides a particular aspect to an entity. All data is stored in components e.g. coordinates are in here.

Bicycle is made of metal, can be used by human and used for transportation.
Bicycle is an entity.
Coordinates, size, weight, material, fact that it is used by humans and
fact that it is used for transportation are components.

Each system runs continuously and performs global actions on every entity that possesses a component that relates to the system. A system essentially provides behaviour for components of a given aspect.

There is a visual component that tells how an entity looks.
There is a physical component that tells where the entity is.
There is a drawing system that renders an entity based on these two components.

This allows using relational database to efficiently save program state. Entity is a database key, database query can be used to get entity components. This makes data flow and the system-logic feel smoother. No need for objects -> RDBMS -> objects loop.

Database Example

Entity system stored in relation database.


// Knowledge is component data.
<entity>: entity_id, debug_label
<component>: component_id, debug_label, description, knowledge_table_name
<knowledge>: knowledge_id, 1..M columns for each piece of data
<entity_component_knowledge>: entity_id, component_id, knowledge_id

// You can split <e_c_k> table to sub-tables by component_id as each
// system uses all components with the same component_id.

// Assemblages are like classes.
<assemblage>: assemblage_id, debug_label, description
<assemblage_component>: assemblage_id, component_id

// You can cache <component>, <entity_component_knowledge>,
// <assemblage> and <assemblage_component> as they do not change much.

Tanks Example

int createTank() {
    int newId = createNewEntity();

    // Attach components to entity using default values.
    createComponentAndAddTo( TRACKED_COMPONENT, newId );
    createComponentAndAddTo( RENDERABLE_COMPONENT, newId );
    createComponentAndAddTo( PHYSICS_COMPONENT, newId );
    createComponentAndAddTo( GUN_COMPONENT, newId );

    // Attach component to entity using custom values.
    float[] gunData = getKnowledgeForEntity( GUN_COMPONENT, newId );
    gunData[ GUN_SIZE ] = 500;
    gunData[ GUN_DAMAGE ] = 10000;
    gunData[ GUN_FIRE_RATE ] = 0.001;
    setKnowledgeForEntity( GUN_COMPONENT, newId, gunData );
    return newId;

Bomberman Component Example

    x (int)
    y (int)
    x (int)
    y (int)
    timeRemaining (float)
    effectType (enum: SPREAD, VANISH)
    depth (int) – decreases by 1 each square it spreads. At 0, it runs out.
    spreadPattern (enum:
    ) – the Behaviour will interpret these
    kills (int)
    deaths (int)
    hitPoints (int)
    height (int)
    – if height > Spreadable.depth, we flow AROUND instead of OVER.
    Also, we can give players a “height” they can move over. This also
    lets us implement “jumping” in terms of increasing (for a single step)
    the height you can move over (makes it easy for us to have “jumpable”
    and “non-jumpable” squares).
    inflictDamage (int)
BombLayer – (something that lays bombs, not a rendering “layer”)
    spread (int)
    depth (int)
    damage (int)
    cellsDeltaX (int) – +1 = right one square, -1 = left one square
    cellsDeltaY (int) – +1 = down one square, -1 = up one square
    addsFeature (enum: FLAME_LENGTH, BOMB_AMOUNT)
    amount (int) – +2 has double the effect, +3 has triple, etc