Part 2 – What is an Entity System?
Sadly, there’s some disagreement about what exactly an Entity System (ES) is. For some people, it’s the same as a Component System (CS) and even Component-Oriented Programming (COP). For others, it means something substantially different. To keep things clear, I’m only going to talk about Entity Systems, which IMHO are a particular subset of COP. Personally, I think Component System is probably a more accurate name given the term COP, but then COP is improperly named and is so confusing that I find if you call these things Component Systems they miss the point entirely. The best would be Aspect Systems, but then AOP has already taken ownership of the Aspect word.
An entity system is simply a part of your program that uses a particular way of breaking up the logic and variables of your program into source code.
For the most part, it does this using the Component Oriented Programming paradigm instead of the OOP paradigm – but there’s subtleties that we’ll go into later.
We refer to an entity “system” instead of entity “programming” because ES’s are usually found embedded in a larger, OOP, program. They are used to solve a subset of problems that OOP is poor at dealing with.
So, it is generally a replacement for Object Oriented Programming. The two are mutually exclusive: you have to choose one or the other (although any complex program may have multiple levels of abstraction, and you could mix and match OOP and COP/ES at different layers, any given layer is going to be one or the other (or, of course, any other alternative way of structuring your program).
Common misconception #1 – Entity Systems are part of OOP
Common misconception #2 – Entity == Class, Component == Object
Where OOP has Classes and Objects, an ES has Entities and Components – but it is very important to note that an Entity is NOT equivalent to a class, and a Component is NOT equivalent to an Object, although superficially they seem to share some characteristics. If you think of Entities/Component’s in OOP terms, you will never understand the ES, and you will screw up any attempt to program with it.
The whole point of ES’s using a different programming *paradigm* is that this means there CAN NEVER BE a direct equivalent between Classes and anything, or between Objects and anything – if there were, it would actually be the same paradigm, and just be a variant of OOP. It’s not. It’s fundamentally different and incompatible.
What’s an Entity?
An Entity System is so named because Entities are the fundamental conceptual building block of your system, with each entity representing a different concrete in-game object. For every discernible “thing” in your game-world, you have one Entity. Entities have no data and no methods.
In terms of number of instances at runtime, they are like Objects from OOP (if you have 100 identical tanks, you have 100 Entities, not 1).
However, in terms of behaviour, they are like classes (Entities indirectly define all the behaviour of the in-game object – we’ll see how in a second).
So, entities on their own are pretty much entirely useless – they are coarse-grained, and they serve to do little more than to tag every coarse gameobject as a separate item. This is where Components come in.
What’s a Component?
Every in-game item has multiple facets, or aspects, that explain what it is and how it interacts with the world. A bicycle, for instance, is:
- Made of metal
- Can be used by a human
- A means of transportation
- Something that can be bought and sold
- A popular birthday present
At this point, please note: OOP does not have this concept of multiple aspects; it hard-codes all the aspects into one glob, and declares that the set of behaviours and values of data to be the single-aspected Class of an Object. C++’s Multiple inheritance and Java’s Interfaces can get you a small part of the way towards the aspects of an ES, but they quickly collapse under the strain in fundamental ways that cannot be fixed within OOP.
The way that an Entity for an item represents the different aspects of the item is to have one Component for each aspect. The Component does one really important thing:
- Labels the Entity as possessing this particular aspect
It may do several other things, depending upon your implementation and the design of your ES. However, with an ES, this is the most important, because this is the basis of all method execution and processing.
What’s a System? (or subsystem)
An ES goes further than OOP in how it splits up the universe of code and data. In OOP, you make everything into Objects. With an ES, you have two different things that you split code and data into: the first is “Entity + Components”, and the second is “Systems”.
This is the source of a lot of the value of an ES. OOP is very good at implementing the part of any program that has lots of data floating around and lots of methods floating around which need to be executed only on a small, instanced, subset of the data in the program. OOP is very poor at implementing the “global” parts of a program, which have to operate “on everything”, or have to be invoked “from everywhere”. An Es solves this by explicitly dealing with all the global stuff using Systems, which are outside the realm of Entity/Component.
Each System runs continuously (as though each System had it’s own private thread) and performs global actions on every Entity that possesses a Component of the same aspect as that System.
There is a one to one relationship between Systems and AVAILABLE aspects (i.e. types of Component). A System essentially provides the method-implementation for Components of a given aspect, but it does it back-to-front compared to OOP. OOP style would be for each Component to have zero or more methods, that some external thing has to invoke at some point. ES style is for each Component to have no methods but instead for the continuously running system to run it’s own internal methods against different Components one at a time.
Typical Systems in a game would be: Rendering System, Animation System, Input System, etc.
The Rendering system wakes up every 16 milliseconds, renders every Entity that has the Renderable Component, and then goes back to sleep.
The Animation system constantly looks out for anything that would trigger a new animation, or cause an existing animation to change (e.g. player changes direction mid-step), and updates the data of each affected Entity (of course, only those that actually have the Animatable Component, i.e. are animations).
The Input system polls the gamepad, mouse, etc, and changes the state of whichever Entities with the Inputable Component are currently marked as being controlled by the player.
In tradtional OOP, if you have 100 units on a battlefield, and each is represented by an object, then you theoretically have 100 copies of each method that can be invoked on a unit. In practice, most OOP languages use runtime and compiler optimizations to share those methods behind the scenes and avoid wasting memory – although scripting languages for instance often don’t do any sharing, allowing all the methods to be independently changed on each and every instance.
By contrast, in an ES, if you have 100 units on a battlefield, each represented by an Entity, then you have zero copies of each method that can be invoked on a unit – because Entities do not contain methods. Nor do Components contain methods. Instead, you have an external system for each aspect, and that external system contains all the methods that can be invoked on any Entity that possess the Component that marks it as being compatible with this system.
That’s not an Entity System!
Well … at least, that’s what *most* people I’ve worked with consider to be an Entity System. But even within a single project, I’ve found multiple different ideas of what an ES is, some of which are compatible, others of which are incompatible. Here are some of the other ideas I’ve come across that people thought were ES’s.
Alternative definitions of entity systems:
1. An ES provides a different model of class-inheritance to OOP, especially w.r.t inheritance of fields. For any given entity-class you declare which aspects that class possesses, and the actual class is looked-up at runtime by piecing together all the different aspects.
2. The same as 1., but taken literally for methods as well as fields, i.e. this provides an interesting way to mix-n-match inheritance of functions/methods. So long as methods are attached to the fields upon which they operate, and/or a “pre-requisite” system is implemented such that “having aspect X automatically causes you to also have aspect Y”, then this works quite smoothly. NB: this is implementing “modular objects”: the “aspects” are complete objects from the standard theory of OOP.
3. A variant on 1. or 2. where the aspect data is pre-compiled into a large number of OOP classes at compile time, so that at runtime you are just running “normal” classes, without any lookup cost of the dynamic “I’ve got an entity E which claims to have aspect X; just hold on a sec while I build a function table to find out what the heck to do now someone just tried to invoke function Z…”
4. A way of compiling standard OOP classes into runtime-data (note: disassociating them from their OOP-ness) specifically so that you can treat them as streamed data instead of chunked binary + data. The main value of this is to play nicely with hardware that has tiny tiny amounts of memory available in the code cache and/or very very slow access to fetch extra code, but has vast bandwidth to stream SEQUENTIAL data through the CPU. PlayStation consoles especially like this approach, as opposed to the typical PC approaches. Note that in this case, the idea is that the game-programmers and game-designers are UNAWARE that there’s an entity system – it’s a runtime/compile time performance optimization, not a design-feature.
5. A system design that revolves around excessive use of the Observer pattern, but does so using standard OOP techniques. I mention this because it’s a common (ab)use of the concepts of ES’s, but lacks much of the advantages. For what it’s worth … that’s the situation I was in when I first discovered ES’s. So, personally, I really don’t count these as ES’s. These are not an ES, but an: “OMG, I need an ES!”, but many people persist in thinking (and claiming) they’re a true ES.
NB: IMHO this is one of those “you really shouldn’t do this” classes of Entity System usage. Why? Because you end up just creating MASSIVE OOP classes with tonnes of independent implemented Observer methods tacked onto them. That’s fine as a general approach, it buys you something whilst remaining ENTIRELY OOP, but it also loses most of what ES’s have to offer, especially in the realm of flexibility and compound inheritance.
Who cares about ES’s and why? (where did they invent these from?)
1. Coders who are used to writing a graphics/rendering engine and trying to keep it isolated / separate from the rest of the computer game. They learnt that they can write the entire graphics engine using only PARTIAL information (a couple of aspects – no more than 2 or 3) of every OOP object that exists in the game-universe. They need to use: Renderable (do I have to paint it to the screen every frame? [it will have all the methods necessary to do that painting generically]), Updateable (does it potentially change in response to one or more game-loop-ticks? [animations are a great example of this - their internal state changes independently of how many times they're rendered]),
2. Multi-threaded coders who are looking at the concept of aspects per se (i.e. Renderable as opposed to Updateable) to allow for coarse-grained multi-threading: you are allowed one thread per aspect, and this is guaranteed safe simply because the aspects are – by definition! – independent from one another. Since a typical ES will have a dozen or more aspects, you’ve just bought yourself reasonably effective performance scaling of up to 12 separate CPU cores, for free.
Also … going to the next level of difficulty and performance improvement, they’re looking for the largest possible individual (literally: things that “cannot be divided”) things that can be made the atomic level of multi-threading. The default position is that only manually-hard-coded atomic operations count, and OOP objects certainly are full of all sorts of multi-threading individual pieces so are far too coarse, but maybe components within entities are small enough to be the unit of atomicity.
3. Game designers who want to enable “everything to become anything”.
Do Cameras shoot people?
Do Bullets accept input from the player?
Well … have you played Unreal Tournament? If you have but didn’t answer yes to the earlier questions then you need to find someone to show you a Redeemer being used in Alternate Fire mode (hint: you get to manually “fly by wire” the rocket from a first-person view inside the warhead itself).
ES’s allow everything and anything to be used as anything and everything, interchangeably, with no re-coding. That’s the beauty for designers – all the artifical constraints on design that were previously enforced by coders having to, you know, place SOME constraints just to write their own damn code and have it be reasonably performant and bug-free are suddenly lifted.
It’s true – you really CAN have strongly-typed safe code and yet have total freedom to pass any object to any method; at least, you can with Entity Systems.
4. Coders who go a bit overboard with the Observer pattern.
If you’re unsure about this one, and have used Observers a lot, ask yourself this: have you ever had that problem with Observers where you found that “just one base class isn’t enough”? i.e. one base class that implemented a handful of different Observers worked great, but as your system / game / application expanded you found you needed more variety in that base class, you needed multiple different versions, and you needed *every possible combination* of those different versions, because base-classes cannot/will not “stack” nicely on top of each other.
Thought for the day
Programming *well* with Entity Systems is very close to programming with a Relational Database. It would not be unreasonable to call ES’s a form of “Relation Oriented Programming”.
This needs a followup post, but you might want to think about that :) both in terms of how the above statement could be true (hint: think about what most of the code you write for each System is going to look like, and what exactly it is doing), and also in terms of what the knock-on effects of this are if it is true.
Bear in mind that no-one’s yet managed to do OOP fast with Relations; the excessively high conversion cost between RDBMS and OOP – both at coding-time and at runtime – is still one of the biggest single development problems with writing an MMO.
NEXT: Part 3