Please note: the design described in this blog post has been much improved and updated and put up – with full source – on http://entity-systems.wikidot.com/.
On the wiki linked above, there is now a wholly new Entity System design, based on this one, but much improved. There’s a brief post about it here, recommended instead of this ES design: http://t-machine.org/index.php/2011/08/22/entity-system-rdbms-beta-a-new-example-with-source/.
I’ve been writing about Entity Systems sporadically for the last few years. Recently, I finally had the time and the excuse to build one of my own (i.e. not owned by an employer). If you haven’t read the main series of ES posts, you should do that first. There are many things in the world masquerading under the Entity/Component banner – and even more that just coincidentally share the name, but describe something else completely. It’s worth understanding which variant I’m talking about before you read about what I’ve done :).
Why build an Entity System?
At a generic level, this is covered in the other posts. But it’s taken years for me to have the time/inclination to write a new one from scratch outside of my day-job. What happened?
- I left my iPhone in America, and it took 2 months to get it back
- Google gave me a free Nexus One, in the hope I’d write something for it (ha! Their cunning plan worked…)
- The Android marketplace is such a miserable morasss of third-rate crap that eventually I was compelled to write my own Android game … just so that I would have something to play (there are very few games on the Android store that are even worth the time it takes to download them)
I’ve been making games for a long time. I know how much effort will go into it, how much time, and how much slog there is before it becomes worth it. Writing a game on your own often means putting in 90% of the effort to get 10% of the reward.
Enter … the Entity System. If I were to pick a game-design that mostly used data-driven game features, I could implement it around an ES, and massively reduce the amount of planning needed to get the game running. I could maybe have a working game after a mere 20% of the effort. Hmm…
Building the ES for Android
Android runs something that’s *almost* Java (although more on that later – Android’s version of Java is very slow at some of the core libraries, and it really shouldn’t be). Technically, Android supports all the core data structures from Java (Collections), and the templating system (Generics).
If I were writing an ES in C++, I’d do it using templates without pausing to think; I wondered how well the same might work with Generics, given that Generics is *not* a complete templating system, although it provides quite a lot.
Getting started: early ES decisions
How to design/implement this thing? Well, we know one thing for sure:
Entities have a single name/label/global-ID. Entities MUST NOT contain ANY DATA: these are NOT objects, this is NOT OOP!
There you go, the Entity class wrote itself:
[java]
public class Entity
{
public int id;
}
[/java]
This immediately raised some concerns for me, being the seasoned coder I am (ha!). How the heck was I going to write any code that dealt with these things if I didn’t have references to them? Obviously, sometimes you do have references, but other times you expect to follow refs from within the objects you have, to get to the objects you need. That wouldn’t be happening here, since there are no inter-object refs.
[java]
public class BaseEntitySystem implements EntitySystem
{
/** I’m too lazy to write a "safe" method to get a globally-unique ID; for now,
I just return 1 the first time I’m called, 2 the second time, etc… */
protected int getNextAvailableID();
/** Whenever you create an entity, you’d better invoke this method too!*/
public void registerEntity( Entity e );
/** The method to solve my fears above */
public Entity getEntity( int id )
/**
* Merely removes the entity from the store. It becomes a GC candidate
* almost immediately (since all other refs are transient)
*/
public void killEntity( Entity e )
}
[/java]
…but, again, being a Veteran coder, the survivor of many painful battles on the field of programming … I didn’t trust myself in the slightest to “always remember” to invoke registerEntity. Quick trick: give the Entity class a static reference to a default EntitySystem, and have each EntitySystem check if that reference is null when starting; if so, set itself as the “default”.
[java]
public class Entity
{
…
public static EntitySystem defaultEntitySystem;
…
public Entity( int i )
{
id = i;
if( defaultEntitySystem == null )
throw new IllegalArgumentException( "There is no global EntitySystem; create a new EntitySystem before creating Entity’s" );
defaultEntitySystem.registerEntity( this );
}
…
}
public class BaseEntitySystem implements EntitySystem
{
…
public BaseEntitySystem()
{
if( Entity.defaultEntitySystem == null )
{
slog( "Setting myself as default entity system (Entity.default… is currently null) self = " + this );
Entity.defaultEntitySystem = this;
}
}
…
}
[/java]
W00t! I can create Entity’s, and I can find them later on. Awesome. What about those Components, then?
Getting started: Components in Java
I’ve done ES in C++ before, with real templates, so I wasn’t really thinking at this point … I just ran with what seemed natural based on prior experience. The thought process (had there been one) would have been something like this:
- This is java, I use Eclipse: I absolutely *must* have the IDE know what data/fields exist in each component so that Content-Assist/Autocomplete works 100%. Otherwise I will gouge my own eyes out having to remember, and doubly so each time the app compiles but dies at runtime because of a typo in a field-name.
- Requirement: each unique Component must be defined as a java Class, with each of the fields being a public member of that class
- Requirement: to access a Component of a given Entity, you must invoke a method which returns something that is typed (as in language typing) to the correct Class
I made a Component class, and had all Components extend it; there is a particular reason for this, but it doesn’t matter right now – essentially, it lets you define shared behaviour for all Component subclasses, and just saves you time on typing.
My first real Component:
(NB: I defined this *inside* another class, because I couldn’t be bothered having N source files for the (large number of) N Components I was bound to create. Hence the “static”):
[java]
public class MyEntitySystemExperiment
{
…
static class Position extends Component
{
float x, y;
int width, height;
float rotationDegrees;
@Override public String toString()
{
return "("+super.toString()+" @ ("+x+","+y+") * rot."+rotationDegrees+")";
}
}
…
}
[/java]
Great. I have a component. Now comes the largest single piece of work in the entire implementation of the ES: writing the methods to:
- Add a component to an Entity
- Fetch a component from an Entity
- Remove a component from an Entity
Fetching a Component from an Entity
This is the win/lose point: if this works well, our ES will be nice and easy to use. The other two methods (add and remove) are simply twiddling bits of data. This one is the challenge: can you make it *easy* to write code that uses the ES, and for that code to be clearly *understandable*?
[java]
public class EntitySystemSimple extends BaseEntitySystem
{
HashMap<Class, HashMap<Entity, ? extends Component>> componentStores;
public <T> T getComponent( Entity e, Class<T> exampleClass )
{
HashMap<Entity, ? extends Component> store = componentStores.get( exampleClass );
T result = (T) store.get( e );
if( result == null )
throw new IllegalArgumentException( "GET FAIL: "+e+" does not
possess Component of class\n missing: "+exampleClass );
return result;
}
…
}
[/java]
Boom! It works.
Let’s just stop briefly and I’ll explain why. Reading Java generics code from cold (just like reading C++ templates) often takes a lot of hard thinking.
Looking at the “result” of this method, we want it to be (enforced by the compiler):
- “an instance of a class that extends Component”
- “an instance of the particular class/Component that we requested – not just any old subclass”
[java]
/** based on comments at end of blog post, think this is correct,
but not checked */
public <T extends Component> T getComponent( Entity e, Class<T> exampleClass )
[/java]
It causes you to write application code that looks something like this:
[java]
public void doSomethingWithAnEntity( int globalId )
{
// remember, we NEVER hold refs to Entity objects for long
Entity e = entitySystem.get( globalId );
Position position = entitySystem.getComponent( e, Position.class );
position.x = 5;
}
[/java]
…and what’s important is that the “type” of the “Position position = …” line is already hard-typed to “Position”. So, the content-assist will *auto-complete* anything put after a dot on the end of that line, e.g.:
[java]
entitySystem.getComponent( e, Position.class ).AUTO_COMPLETE
[/java]
…so you can instead write your method much quicker, and yet very clearly, as:
[java]
public void doSomethingWithAnEntity( int globalId )
{
// remember, we NEVER hold refs to Entity objects for long
Entity e = entitySystem.get( globalId );
entitySystem.getComponent( e, Position.class ).x = 5;
entitySystem.getComponent( e, Damage.class ).hitpoints = 145;
entitySystem.getComponent( e, Renderable.class ).foregroundColour = Color.red;
}
[/java]
Time-out: HashMap
HashMap is the “correct” class to use in Java for this setup: it’s the exact equivalent of Hashtable / Dictionary / etc in other languages. We need to map (somewhere, somehow) from one thing (an entity) to another thing (a component).
NB: this does not mean that you have to use HashMap as your data-store for the ES; I positively encourage you to consider other options. I used it here as the most obvious, simplest possible structure that would do the job. If you think back to my posts on Entity Systems for MMO development, I’ve often suggested that the data store could *and should* be any of many different things. In particular, SQL databases make for an excellent data-store (and remember you can get in-memory SQL implementations that do away with all the expensive write-to-disk stuff).
Unfortunately … Android seems to only partially support HashMap. You can use the class, but it runs an order of magnitude slower than you expect for a normal JVM (compared to the speed with which it runs other methods). It seems to have problems with the hashcode methods, but also even with basic iteration over the Map contents. Odd. Later on, I had to do some tricks to speed up the ES, just because of this problem.
Fetching a Component from an Entity: Redux
The examples I gave above for accessing components were lean and clear on the right hand side (thanks to autocomplete and strong typing), but terrible on the left-hand-side. By the magic of OOP, I’m going to clean up the LHS. BUT (and this is a big “but”) … make sure you fully understand what I’m doing here. With what I’m about to do, it would be very easy to fall into one of the traps of ES development: slipping back into OOP techniques.
Looking at the example:
[java]
entitySystem.getComponent( e, Position.class ).x = 5;
entitySystem.getComponent( e, Damage.class ).hitpoints = 145;
entitySystem.getComponent( e, Renderable.class ).foregroundColour = Color.red;
[/java]
… applying OOP mindset, we see that the first argument is redundant; the Entity already knows about the EntitySystem to which it’s registered.
Also, we know that the Entity class will never have any methods or data other than the ID. If that’s the case, the only thing we’d ever “get” from an Entity is a Component. So, we can add this to Entity:
[java]
public class Entity
{
…
/** Gets a filtered view of the entity’s data, only returning the subset that
* corresponds to a particular one of its components */
public <T extends Component> T getAs( Class<T> type )
{
return source.getComponent( this, type );
}
…
}
[/java]
…which converts our usage example to:
[java]
e.getAs( Position.class ).x = 5;
e.getAs( Damage.class ).hitpoints = 145;
e.getAs( Renderable.class ).foregroundColour = Color.red;
[/java]
Using the ES with Systems
Recap: right now, we can:
- Create entities
- Add components to entities
- Read/Write the data inside each component, on a per-entity basis
- Fetch entities by globally unique ID
One last thing is needed before the ES can work: we need a way to fetch Entities “by component”.
e.g.:
[java]
public class MyEntitySystemExperiment
{
…
public void runLoop()
{
while( true )
{
// move all the entities
positionSystem.move( MOVEABLE_ENTITIES );
// check for collisions
collisionDetectionSystem.process( MOVEABLE_ENTITIES );
// render all the visible entities
renderingSystem.render( RENDERABLE_ENTITIES );
}
}
…
}
[/java]
We need a way to provide the arguments that are capitalized above. We know that these should be plain-old lists of entities. We know they have to come from the EntitySystem. Finally, we know that the only defining characteristic of these lists is that everything in the list has *at least* a particular Component.
(respectively, in the example above, the lists contain: “all entities that are moveable”, “all entities that are moveable AND all entities that are barriers to movement (e.g. solid walls)”, and “all entities that should be displayed on-screen”)
So, one more method for the EntitySystem interface:
[java]
public interface EntitySystem
{
…
public List<Entity> getAllEntitiesPossessing( Class… requiredComponents );
…
}
[/java]
“Class…” is just a convenience; in many cases, you’ll be insisting on a single Component. In many other cases, you’ll be insisting on a set of components. Java varargs provide the minor convenience of doing both of those in one method, while retaining type-safety.
The implementation of this method is obvious: it iterates over every entity that’s been registered, and checks it against ALL the required components. If it possesses all of them, it goes into the output list.
Finis
That’s it. So easy! Obviously, there’s more to it – the other methods you need to create should be mostly self-evident – but this should be enough to get you started.
Now, I’m not sure where to go from here. I’ve got a working Java ES. I’ve got some performance improvements and feature improvements. But … in practice, hardly anyone writes games in Java (except Android programmers, and there aren’t many of those), so … is it worth it?
Alternatively, I might just run through some of the practical pros and cons I encountered when actually using the ES in writing the game-logic. There’s some interesting things that came up which most people encounter sooner or later when doing their first ES, and which might be worth looking at in more detail.
One last thought…
Did it work? Did this ES allow me to write a decent Android game?
Yep. I wrote a space-invaders / bullet-hell game with it. It worked fine on Android phones for a hundred-odd enemies and bullets on screen. On Android, thanks to the crappy JVM, it started to chug after that (dropped below 30 FPS), so I had to make some substantial performance improvements, and now it’s happily rendering 300 things all flying around at 20-30 FPS. The game is far from finished, but it’s playable and fun for a minute or so – a definite achievement considering how little of it I’ve written so far.
NB: it’s got some way to go before I’ll be happy releasing it. But, given a few more spare evenings, I hope to get this up on the Android Market as a free download in the near future.
I’m pleasantly surprised that the Android phones can handle something as high-level as an ES, in a pure, unoptimized “simplest possible” implementation.
Did this post help you?
You can say “thank you” by giving me your email address, and letting me contact you next time I make a game of my own:
[smlsubform emailtxt=”” showname=” mailinglist=”pif-entity-systems”]