Why Use Entity Systems for Game Engineering?

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)] // an indicator that Movement can only be added to an entity that has a Position
class Movement
{
	[Inject] public var entity:Entity; // the entity to which this instance of Movement is added

	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
{
	[Inject] public var collection:Collection; // a collection of entities with position and movement components

	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.

11 thoughts on “Why Use Entity Systems for Game Engineering?

  1. Nice , but how would you make different systems interact ? for example when a ship is turning left it needs to update the animation (to another sequence) how will the rendering system know that the moving system needs that animation change?

    1. Hi Dan P,

      Thanks for the question!

      In the example you gave, it isn’t that two systems need to interact but that they need to reference the same state. Let me try to flesh out your example a little:

      Staying 2D to make it easy to think about, a turn happens in the MovementSystem because something sets the Movement state to something like a deltaAngle != 0. An AnimationSystem is responsible for setting the frame value on the Animation component, and also for choosing which sequence of frames the ship is currently using, so when deltaAngle > N AnimationSystem changes the animation sequence to rightTurnSequence. The render system is responsible for drawing the given frame from the AnimationSystem to the canvas/GPU.

      So, using my dust library I would configure my systems like this:

      systems.map(MovementSystem).toCollection([Position, Movement]);
      systems.map(AnimationSystem).toCollection([Movement, Animation]);
      systems.map(RenderSystem).toCollection([Position, Animation]);

      In the MovementSystem Position is updated from Movement.
      In the AnimationSystem Animation is updated from Movement.
      In the RenderSystem the canvas is drawn using both Position and Animation.

      Does this help?
      Alec

      1. Hi Alec, thanks for the fast reply and the example, it is very helpful. I am trying to see if I can switch my architecture from a Component Systems approach to the Entity Systems you describe here so , thanks again!

        1. Good luck! Please feel free to get in touch if you want help, or to discuss any implementation details. What language are you coding in?

          I’m hopefully going to finish a second article with details of my implementation by the end of this week… watch this space!

          1. I will , I am writing it in C# XNA (for now) looking to port to MonoGame later on , the only question I would have so far is : How do you feel about a messanging service ? Is that useful in the Entity Systems approach ? I found it quite useful for the components based approach initially but… I’m not quite sure now because of the extra burden of adding all those message data-storage (the data that the message needs to transfer).

            Good luck with the article , looking forward to reading it!

  2. Hi Alec and thank you for this interesting article on a real issue.

    Sorry to return so easily to OOP, but isn’t-it the visitor pattern you describe? https://en.wikipedia.org/wiki/Visitor_pattern

    And rigidity is generally resolved with factory which works quite well (but everything has its limit).

    This is of course a small example in your article but I don’t think It’s a good idea to put collection iteration in each action class.

    I will read the article on limits on OOP you pointed at, it looks interested.

    There are a lot of problems where its a good idea to completely separates data and behavior (while keeping class keyword…) and generic action/command system may be one, like the command pattern (sorry again ;p)

    1. Hi Vincent,

      I don’t think it’s true to say that “rigidity is generally resolved with factory”. It’s too simplistic. Rigidity derives from structure, and anywhere where you make structural assumptions about how code should be organized means when you change your mind later, you have to go back and rewrite all the code based on that assumption. Rigidity is unavoidable.

      My argument is that for games where the norm is flux rather than stability, Entity Systems keeps rigidity very low by treating all data as public, organized into small value objects, and treating all algorithms as systems that operate on those value objects. It also has the added benefit of overwhelming, boring consistency. I find that OOP people love patterns, love to use patterns, and love to use lots of different patterns. Done without care (or even sometimes, with care but over a long time), the pattern of patterns can make me dizzy. That said of course, done with care it is entirely possible to produce a game in many different, equally elegant ways. I am *not* claiming that an Entity System *exclusively* solves these problems, just that it does solve them!

      I’m curious why you state without argument that it is not a good idea to iterate over a collection in each system (‘action class’). Why is it not? Are you worried about the cost of several small or empty loops? I assure you, that cost is next-to-nothing in all practical contexts. If there are no elements the overhead is tiny. If there are elements the overhead is immaterial. I offer that there is a lot of overhead within, let’s say an MVC system which is hidden inside the architecture. Event dispatching, constructing and destructing commands, all the dependency injection into commands (whether manual or automatic), all eats up time. When my systems eat up time I can measure exactly how much time they eat, and if things get slow I can easily identify which systems are causing the problem.

      Yes, there is definitely a corollary between the Visitor Pattern and an Entity System. They seek to solve the same problem similarly. I’m not sure they are isomorphic however, just because the entity system relies on a core structure to manage which entities are passed into which systems. I will publish a follow-up blog about how that is done by the end of the week.

      Thanks! I hope I don’t sound too aggressive in my responses, I don’t mean to but I have been told my writing style can read a bit aggressively at times. I really appreciate your questioning of my approach, it gives me lots to think about!

      Alec

      1. Hi,

        Thank you for your reply.

        I was quite quick on some argumentation as you stated ^^

        You’ve noticed well I like OO pattern but I like too to be kind of agnostic and pragmatic in the way I program. I do game myself too and I generally never use any kind of ‘complex’ pattern in it, just the good old game loop. It was just it evoked me with some kind of similarity with the visitor pattern. But you are right I didn’t really got the core entity system structure you talked about. Will wait your next post to get it.

        With a more general view what you talked about make me think too of what is call anemic model which is treated here as an anti-pattern (first link I found on the term): http://martinfowler.com/bliki/AnemicDomainModel.html

        In my opinion it is not necessary an anti-pattern, in the contrary it is in fact mainly used and useful in almost any company software which deals with more than 1 layer (in an architecture pov) because data must go through this layers and their shape changes through the processes (data object, business object, value object, service objects…). It transforms computer system in something more like an assembly line with engines which have the intelligence to transform inert material.

        On your side you need such engine to add behavior to entities but it is quite the same for me. You want machines which moves your puppet entities because if I understood well you say than behavior changes more than data.

        I understand (and use) this kind of mechanism a lot but I sometime prefer too to have an animated and intelligent puppet which can handle its own life. I quite prefer this in an intellectual way of thinking behavior but this is here purely subjective. Sorry if my puppet thing is not clear, I’ve watched too many ghost in the shell.

        For the iteration issue I pointed at the argument is: why iterate multiple times on potentially the same entity when you can iterate once on all objects and apply behavior?

        It’s a performance/optimization issue which is often an important one with video game. In a scalability point of view, if you add a behavior applied to all entities (extrem case) you will reiterate again for all of them, or I didn’t understood well, or this not really nice I think. It can be OK in some special handled cases for which we can know this risk is out, but make this a general mechanism I’m not sure.

        Regards

  3. I implemented a similar system to the component system method. Just wanting to know how you handle removal of dead gameobjects. They get tied into several system collections and therefore need to be removed from several places.

    1. The intention of this system is that the only places in which entity references are maintained are collections, which are managed by the application. Entity has a dispose method which removes all components and removes the entity from all collections. If I reference an entity explicitly somewhere, then I have to remove it explicitly, of course.

      As it happens, I’m starting to move away from this idea towards an ‘engine-less approach’; I still try to use the functional principles that led towards using an entity system, but I don’t try to shoehorn everything into a particular structure anymore. Anyway, I hope it helps. Let me know if I can help with anything else.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>