blog / Why Use Entity Systems for Game Engineering?

Why Use Entity Systems for Game Engineering?

Jul 05, 2013

An Entity System is an architecture for developing games that avoids many of the problems that are a feature of games developed using Object Oriented Programming (OOP). This article explains how moving from the OOP paradigm to an Entity System approach requires a change in engineers' thought processes and the abandoning of the principle of encapsulation. Making this change simplifies development and allows code to be more modular. This in turn enables the engineer to better respond to issues of scale and changing requirements.

Software Architecture

The secondary value of software is its behavior ... The ability of software to tolerate and facilitate such ongoing change is the primary value of software. The primary value of software is that it's soft

-- Bob Martin, Clean Code, Episode 9

All software is a combination of data and algorithms. The challenge for software engineering is how best to structure the data and algorithms such that it remains open to future change. Software architecture helps the engineer meet these challenges by providing a simple, consistent way to structure the data and algorithms into modules, and provides mechanisms for linking these modules together.

Over time, breaking an application down into modules is necessary because it keeps each part of the application relatively simple. However, as soon as an application is modular those modules must be linked together and linking is the source of rigidity. The biggest problem for software architecture lies in solving how to link two modules of code together so that changing one module does not require changing those modules to which it is linked; how to keep the software soft.

Entities, States, Nouns and Verbs

Games are comprised of entities. An entity is a stateful, independent thing that persists over a period of time during a game. How a game works can be described in terms these entities using three distinct concepts: state, nouns and verbs. The nouns in a game describe the different categorisations of entity that the game has: alien, bullet, hero, timer, score, or camera are all kinds of entity. The state of an entity describes the different data structures they contain: position, color, shape, intention... The verbs in a game describe change: An entity may move, fight, die, collide, rotate, inflate, blink... In code, verbs are expressed by the algorithms that manipulate the entities' state.

Given a design, the software engineer building the game has two main options for choosing how to organize her code. She may choose as her central organizing units of code the nouns of the game, or she may choose the verbs.

Object Oriented Programming - Organizing Code Around Nouns

For an engineer that has a lot of experience in OOP this is no choice at all. OOP is based on the organizing principle of encapsulation: that the data and the algorithms that manipulate that data comprise a module, or class. Since for one entity many verbs will manipulate the same data structures (move and collide may both reference an entity's position, for example), encapsulation dictates that they must all be part of the same module. So, the OOP engineer will start to define her class Alien as follows:

class Alien
{
  var position:Vector2;
  var velocity:Vector2;

  public function move(deltaTime:Float);
  public function collide(other:?);
}

There are two main criticisms of this approach: using OOP the nouns define the top-level modules of the code, and the states and verbs are tightly coupled to them. The strong links define a rigid internal structure for each object, which makes it difficult to reuse the verbs or states in different contexts.

The experienced OOP engineer may counter that there are many design patterns and strategies available to her that lets her mitigate this problem. The engineer may avoid repeating herself and share the algorithm for movement between two different classes: Alien and Hero, by defining a Humanoid class from which Alien and Hero inherit. Alternatively she could use a strategy-pattern to define a Movement behaviour and composite the behaviour into the Alien and Hero classes... For the OOP developer to avoid the problems of big, rigid modules she has to make lots of difficult architectural decisions. Sadly, this is in-itself a problem: she must sacrifice consistency to achieve modularity. Instead of wielding a few, big architectural designs, her code becomes separated into many small concepts that interact with each other in lots of different, complicated ways.

The source of the engineer's difficulties is that the initial choice of organizing her code around the nouns is a mistake. It is a premise of modularity that it is better to have many, smaller modules than to have few, big modules, and it is equally better to have a few, simple ways that modules interact with each other. There will always be fewer nouns than verbs in a game's design, so organizing code around nouns runs against the best interests of modularity.

There are many other general criticisms of OOP that won't be discussed here. OOP is a very intuitive way to structure code and has many benefits. This article does not intend to criticise OOP but rather suggest that there is an approach for games engineering that is more robust and scalable.

Entity Systems and Component Systems - Organizing Code Around Verbs

The engineer's alternative route is to treat as the central organizing modules of her code the verbs. A consequence of this is that the nouns of the system are not centrally defined at all. Instead, the class Entity is defined as a dynamic, runtime composition of Components. Components define the different aspects of the entity's state, and drive which verbs are applicable to it. For example, the verb 'to move' is defined by the Movement Component, which contains (minimally) the entity's velocity. The algorithm that applies movement is applied to all and only those entities that have the movement and position components; to trigger movement the Movement component is added to the entity, to cancel movement it is removed.

There are two main variations to how the algorithm is applied. In what I term a Component System, the movement algorithm is defined in the Component itself, in an update method. Every component will have an update method, so that as part of the main game-loop every component in every entity is iterated through and update() called.

The structure of the code in a Component System looks something like this:

class Position
{
  public var position:Vector2;

  public function update(deltaTime:Float);
}

[Require(Position)] // only to be added to an entity with a Position.
class Movement
{
  [Inject] public var entity:Entity;

  public var velocity:Vector2;

  public function update(deltaTime:Float)
  {
    var position = entity.get(Position).position;
    position.offset(velocity * deltaTime);
  }
}

At first glance this approach may look like it maintains encapsulation, though this is not the case. For the Movement component's update algorithm to do anything it must access and modify the Position component's data. The central problem for this architecture is how to reference other components. The most popular incarnation of this approach is currently Unity3D. The Unity3D team solved this problem by forcing all components to inherit from a base class MonoBehaviour, which stores a reference to the entity and allows inter-component communication.

In what I term an Entity System the data and algorithms are kept separate. Components are simply value objects containing the necessary state for a given concept. Algorithms are defined in what I term a System. Every system has an iterate() method. When systems are registered to the main game-loop iterate() is called as part of that loop.

The structure of the code in an Entity System looks something like this:

class Position
{
  public var position:Vector2;
}

class Movement
{
  public var velocity:Vector2;
}

class MovementSystem
{
  // a collection of entities with position and movement components
  [Inject] public var collection:Collection;

  public function iterate(deltaTime:Float)
  {
    for (entity in collection)
    {
      var position = entity.get(Position).position;
      var velocity = entity.get(Movement).velocity;
      position.offset(velocity * deltaTime);
    }
  }
}

The central problem for this approach is how the MovementSystem maintains a reference to all and only those entities that have both a Movement and a Position component. How I do this in dust (Haxe Entity System) will be the subject of an upcoming article. The clear disadvantage to an Entity System approach is the amount of CPU needed each cycle to maintain these references. However, this disadvantage can be mitigated by the architects developing efficient ways to maintain these structures, so that the gameplay engineer can concentrate on implementing the systems needed.

These approaches avoid the problems caused by organizing code around the nouns of code. If more verbs are added to the game design document, more modules can be added in the code without touching any of the existing functionality. The software engineer can develop and test new features independently without fear of causing regressions.

Of course, problems with this approach can emerge when two or more systems modify the same data structures. Independent modules for Movement and Collision may contradict one another for example in which case the order in which they are run can also become an issue. These problems are not magically handled by an Entity System. In this case, it may make sense to remove movement and collision as separate modules and create a bigger, more over-arching Physics system. These sorts of problem are an inevitable issue for game engineering irrespective of the architecture. To solve such problems in an Entity System or Component System is to create a new system; the structure of the code remains consistent.

The primary advantage to this approach is that the code remains extremely consistent and extremely modular. Every system has exactly one entry point. Systems can be turned off and on by adding and removing them from the main game-loop, their speed can be monitored and compared to one another, so their impact on the game can be carefully measured and assessed.

Summary

An Entity System is a software architecture for game development. Entity (and Component) System Architecture combines a clear separation of data structures and algorithms with a core mechanism to manage which data is passed into which algorithm and when. The separation of data and algorithms encourages good separation of concerns, enabling highly modular application development.

The Object Oriented Programming approach to game engineering is problematic because it leads to either too few modules with big rigid structures, or modules that are linked to each other in complicated, inconsistent ways. By contrast, Entity System architecture seeks to minimize the links between the different parts of game code and define a few, extremely simple ways that they can interact.

The software engineer developing a game in an Entity System architecture must organize her thoughts and code around the verbs of the game, rather than the nouns. This can feel like an alien way to organize code initially, but eventually it rewards the developer with simpler, more consistent code that scales and responds to change better.

Entity Systems are a better way to organize code for game engineering.