What is an entity system framework for game development?
19th January 2012
Last week I released Ash, an entity system framework for Actionscript game development, and a number of people have asked me the question “What is an entity system framework?”. This is my rather long answer.
Entity systems are growing in popularity, with well-known examples like Unity, and lesser known frameworks like Actionscript frameworks Ember2, Xember and my own Ash. There’s a very good reason for this; they simplify game architecture, encourage clean separation of responsibilities in your code, and are fun to use.
In this post I will walk you through how an entity based architecture evolves from the old fashioned game loop. This may take a while. The examples will be in Actionscript because that happens to be what I’m using at the moment, but the architecture applies to all programming language.
This is based on a presentation I gave at try{harder} in 2011.
The examples
Throughout this post, I’ll be using a simple Asteroids game as an example. I like to use Asteroids as an example because it involves simplified versions of many of the systems required in larger games – rendering, physics, ai, user control of a character, non-player characters.
The game loop
To understand why we use entity systems, you really need to understand the old-fashioned game loop. A game loop for Asteroids might look something like this
function update( time:Number ):void
{
game.update( time );
spaceship.updateInputs( time );
for each( var flyingSaucer:FlyingSaucer in flyingSaucers )
{
flyingSaucer.updateAI( time );
}
spaceship.update( time );
for each( var flyingSaucer:FlyingSaucer in flyingSaucers )
{
flyingSaucer.update( time );
}
for each( var asteroid:Asteroid in asteroids )
{
asteroid.update( time );
}
for each( var bullet:Bullet in bullets )
{
bullet.update( time );
}
collisionManager.update( time );
spaceship.render();
for each( var flyingSaucer:FlyingSaucer in flyingSaucers )
{
flyingSaucer.render();
}
for each( var asteroid:Asteroid in asteroids )
{
asteroid.render();
}
for each( var bullet:Bullet in bullets )
{
bullet.render();
}
}
This game loop is called on a regular interval, usually every 60th of a second or every 30th of a second, to update the game. The order of operations in the loop is important as we update various game objects, check for collisions between them, and then draw them all. Every frame.
This is a very simple game loop. It’s simple because
- The game is simple
- The game has only one state
In the past, I have worked on console games where the game loop, a single function, was over 3,000 lines of code. It wasn’t pretty, and it wasn’t clever. That’s the way games were built and we had to live with it.
Entity system architecture derives from an attempt to resolve the problems with the game loop. It addresses the game loop as the core of the game, and pre-supposes that simplifying the game loop is more important than anything else in modern game architecture. More important than separation of the view from the controller, for example.
Processes
The first step in this evolution is to think about objects called processes. These are objects that can be initialised, updated on a regular basis, and destroyed. The interface for a process looks something like this.
interface IProcess
{
function start():Boolean;
function update( time:Number ):void;
function end():void;
}
We can simplify our game loop if we break it into a number of processes to handle, for example, rendering, movement, collision resolution. To manage those processes we create a process manager.
class ProcessManager
{
private var processes:PrioritisedList;
public function addProcess( process:IProcess, priority:int ):Boolean
{
if( process.start() )
{
processes.add( process, priority );
return true;
}
return false;
}
public function update( time:Number ):void
{
for each( var process:IProcess in processes )
{
process.update( time );
}
}
public function removeProcess( process:IProcess ):void
{
process.end();
processes.remove( process );
}
}
This is a somewhat simplified version of a process manager. In particular, we should ensure we update the processes in the correct order (identified by the priority parameter in the add method) and we should handle the situation where a process is removed during the update loop. But you get the idea. If our game loop is broken into multiple processes, then the update method of our process manager is our new game loop and the processes become the core of the game.
The render process
Lets look at the render process as an example. We could just pull the render code out of the original game loop and place it in a process, giving us something like this
class RenderProcess implements IProcess
{
public function start() : Boolean
{
// initialise render system
return true;
}
public function update( time:Number ):void
{
spaceship.render();
for each( var flyingSaucer:FlyingSaucer in flyingSaucers )
{
flyingSaucer.render();
}
for each( var asteroid:Asteroid in asteroids )
{
asteroid.render();
}
for each( var bullet:Bullet in bullets )
{
bullet.render();
}
}
public function end() : void
{
// clean-up render system
}
}
Using an interface
But this isn’t very efficient. We still have to manually render all the different types of game object. If we have a common interface for all renderable objects, we can simplify matters a lot.
interface IRenderable
{
function render();
}
class RenderProcess implements IProcess
{
private var targets:Vector.<IRenderable>;
public function start() : Boolean
{
// initialise render system
return true;
}
public function update( time:Number ):void
{
for each( var target:IRenderable in targets )
{
target.render();
}
}
public function end() : void
{
// clean-up render system
}
}
Then our spaceship class might contain some code like this
class Spaceship implements IRenderable
{
public var view:DisplayObject;
public var position:Point;
public var rotation:Number;
public function render():void
{
view.x = position.x;
view.y = position.y;
view.rotation = rotation;
}
}
This code is based on the flash display list. If we were blitting, or using stage3d, it would be different, but the principles would be the same. We need the image to be rendered, and the position and rotation for rendering it. And the render function does the rendering.
Using a base class and inheritance
In fact, there’s nothing in this code that makes it unique to a spaceship. All the code could be shared by all renderable objects. The only thing that makes them different is which display object is assigned to the view property, and what the position and rotation are. So lets wrap this in a base class and use inheritance.
class Renderable implements IRenderable
{
public var view:DisplayObject;
public var position:Point;
public var rotation:Number;
public function render():void
{
view.x = position.x;
view.y = position.y;
view.rotation = rotation;
}
}
class Spaceship extends Renderable
{
}
Of course, all renderable items will extend the renderable class, so we get a simple class heirarchy like this
The move process
To understand the next step, we first need to look at another process and the class it works on. So lets try the move process, which updates the position of the objects.
interface IMoveable
{
function move( time:Number );
}
class MoveProcess implements IProcess
{
private var targets:Vector.<IMoveable>;
public function start():Boolean
{
return true;
}
public function update( time:Number ):void
{
for each( var target:IMoveable in targets )
{
target.move( time );
}
}
public function end():void
{
}
}
class Moveable implements IMoveable
{
public var position:Point;
public var rotation:Number;
public var velocity:Point;
public var angularVelocity:Number;
public function move( time:Number ):void
{
position.x += velocity.x * time;
position.y += velocity.y * time;
rotation += angularVelocity * time;
}
}
class Spaceship extends Moveable
{
}
Multiple inheritance
That’s almost good, but unfortunately we want our spaceship to be both moveable and renderable, and many modern programming languages don’t allow multiple inheritance.
Even in those languages that do permit multiple inheritance, we have the problem that the position and rotation in the Moveable class should be the same as the position and rotation in the Renderable class.
One common solution is to use an inheritance chain, so that Moveable extends Renderable.
class Moveable extends Renderable implements IMoveable
{
public var velocity:Point;
public var angularVelocity:Number;
public function move( time:Number ):void
{
position.x += velocity.x * time;
position.y += velocity.y * time;
rotation += angularVelocity * time;
}
}
class Spaceship extends Moveable
{
}
Now the spaceship is both moveable and renderable. We can apply the same principles to the other game objects to get this class hierarchy.
We can even have static objects that just extend Renderable.
Moveable but not Renderable
But what if we want a Moveable object that isn’t Renderable? An invisible game object, for example? Now our class hierarchy breaks down and we need an alternative implementation of the Moveable interface that doesn’t extend Renderable.
class InvisibleMoveable implements IMoveable
{
public var position:Point;
public var rotation:Number;
public var velocity:Point;
public var angularVelocity:Number;
public function move( time:Number ):void
{
position.x += velocity.x * time;
position.y += velocity.y * time;
rotation += angularVelocity * time;
}
}
In a simple game, this is clumsy but manageable, but in a complex game using inheritance to apply the processes to objects rapidly becomes unmanageable as you’ll soon discover items in your game that don’t fit into a simple linear inheritance tree, as with the force-field above.
Favour composition over inheritance
It’s long been a sound principle of object-oriented programming to favour composition over inheritance. Applying that principle here can rescue us from this potential inheritance mess.
We’ll still need Renderable and Moveable classes, but rather than extending these classes to create the spaceship class, we will create a spaceship class that contains an instance of each of these classes.
class Renderable implements IRenderable
{
public var view:DisplayObject;
public var position:Point;
public var rotation:Number;
public function render():void
{
view.x = position.x;
view.y = position.y;
view.rotation = rotation;
}
}
class Moveable implements IMoveable
{
public var position:Point;
public var rotation:Number;
public var velocity:Point;
public var angularVelocity:Number;
public function move( time:Number ):void
{
position.x += velocity.x * time;
position.y += velocity.y * time;
rotation += angularVelocity * time;
}
}
class Spaceship
{
public var renderData:IRenderable;
public var moveData:IMoveable;
}
This way, we can combine the various behaviours in any way we like without running into inheritance problems.
The objects made by this composition, the Static Object, Spaceship, Flying Saucer, Asteroid, Bullet and Force Field, are collectively called entities.
Our processes remain unchanged.
interface IRenderable
{
function render();
}
class RenderProcess implements IProcess
{
private var targets:Vector.<IRenderable>;
public function update(time:Number):void
{
for each(var target:IRenderable in targets)
{
target.render();
}
}
}
interface IMoveable
{
function move();
}
class MoveProcess implements IProcess
{
private var targets:Vector.<IMoveable>;
public function update(time:Number):void
{
for each(var target:IMoveable in targets)
{
target.move( time );
}
}
}
But we don’t add the spaceship entity to each process, we add it’s components. So when we create the spaceship we do something like this
public function createSpaceship():Spaceship
{
var spaceship:Spaceship = new Spaceship();
...
renderProcess.addItem( spaceship.renderData );
moveProcess.addItem( spaceship.moveData );
...
return spaceship;
}
This approach looks good. It gives us the freedom to mix and match process support between different game objects without getting into spagetti inheritance chains or repeating ourselves. But there’s one problem.
What about the shared data?
The position and rotation properties in the Renderable class instance need to have the same values as the position and rotation properties in the Moveable class instance, since the Move process will change the values in the Moveable instance and the Render process will use the values in the Renderable instance.
class Renderable implements IRenderable
{
public var view:DisplayObject;
public var position:Point;
public var rotation:Number;
public function render():void
{
view.x = position.x;
view.y = position.y;
view.rotation = rotation;
}
}
class Moveable implements IMoveable
{
public var position:Point;
public var rotation:Number;
public var velocity:Point;
public var angularVelocity:Number;
public function move( time:Number ):void
{
position.x += velocity.x * time;
position.y += velocity.y * time;
rotation += angularVelocity * time;
}
}
class Spaceship
{
public var renderData:IRenderable;
public var moveData:IMoveable;
}
To solve this, we need to ensure that both class instances reference the same instances of these properties. In Actionscript that means these properties must be objects, because objects can be passed by reference while primitives are passed by value.
So we introduce another set of classes, which we’ll call components. These components are just value objects that wrap properties into objects for sharing between processes.
class PositionComponent
{
public var x:Number;
public var y:Number;
public var rotation:Number;
}
class VelocityComponent
{
public var velocityX:Number;
public var velocityY:Number;
public var angularVelocity:Number;
}
class DisplayComponent
{
public var view:DisplayObject;
}
class Renderable implements IRenderable
{
public var display:DisplayComponent;
public var position:PositionComponent;
public function render():void
{
display.view.x = position.x;
display.view.y = position.y;
display.view.rotation = position.rotation;
}
}
class Moveable implements IMoveable
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
public function move( time:Number ):void
{
position.x += velocity.velocityX * time;
position.y += velocity.velocityY * time;
position.rotation += velocity.angularVelocity * time;
}
}
When we create the spaceship we ensure the Moveable and Renderable instances share the same instance of the PositionComponent.
class Spaceship
{
public function Spaceship()
{
moveData = new Moveable();
renderData = new Renderable();
moveData.position = new PositionComponent();
moveData.velocity = new VelocityComponent();
renderData.position = moveData.position;
renderData.display = new DisplayComponent();
}
}
The processes remain unaffected by this change.
A good place to pause
At this point we have a neat separation of tasks. The game loop cycles through the processes, calling the update method on each one. Each process contains a collection of objects that implement the interface it operates on, and will call the appropriate method of those objects. Those objects each do a single important task on their data. Through the system of components, those objects are able to share data and thus the combination of multiple processes can produce complex updates in the game entities, while keeping each process relatively simple.
This architecture is similar to a number of entity systems in game development. The architecture follows good object-oriented principles and it works. But there’s more to come, starting with a moment of madness.
Abandoning good object-oriented practice
The current architecture uses good object-oriented practices like encapsulation and single responsibility – the IRenderable and IMoveable implementations encapsulate the data and logic for single responsibilities in the updating of game entities every frame – and composition – the Spaceship entity is created by combining implementations of the IRenderable and IMoveable interfaces. Through the system of components we ensured that, where appropriate, data is shared between the different data classes of the entities.
The next step in this evolution of entity systems is somewhat counter-intuitive, breaking one of the core tenets of object-oriented programming. We break the encapsulation of the data and logic in the Renderable and Moveable implementations. Specifically, we remove the logic from these classes and place it in the processes instead.
So this
interface IRenderable
{
function render();
}
class Renderable implements IRenderable
{
public var display:DisplayComponent;
public var position:PositionComponent;
public function render():void
{
display.view.x = position.x;
display.view.y = position.y;
display.view.rotation = position.rotation;
}
}
class RenderProcess implements IProcess
{
private var targets:Vector.<IRenderable>;
public function update( time:Number ):void
{
for each( var target:IRenderable in targets )
{
target.render();
}
}
}
Becomes this
class RenderData
{
public var display:DisplayComponent;
public var position:PositionComponent;
}
class RenderProcess implements IProcess
{
private var targets:Vector.<RenderData>;
public function update( time:Number ):void
{
for each( var target:RenderData in targets )
{
target.display.view.x = target.position.x;
target.display.view.y = target.position.y;
target.display.view.rotation = target.position.rotation;
}
}
}
And this
interface IMoveable
{
function move( time:Number );
}
class Moveable implements IMoveable
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
public function move( time:Number ):void
{
position.x += velocity.velocityX * time;
position.y += velocity.velocityY * time;
position.rotation += velocity.angularVelocity * time;
}
}
class MoveProcess implements IProcess
{
private var targets:Vector.<IMoveable>;
public function move( time:Number ):void
{
for each( var target:Moveable in targets )
{
target.move( time );
}
}
}
Becomes this
class MoveData
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
}
class MoveProcess implements IProcess
{
private var targets:Vector.<MoveData>;
public function move( time:Number ):void
{
for each( var target:MoveData in targets )
{
target.position.x += target.velocity.velocityX * time;
target.position.y += target.velocity.velocityY * time;
target.position.rotation += target.velocity.angularVelocity * time;
}
}
}
It’s not immediately clear why we’d do this, but bear with me. On the surface, we’ve removed the need for the interface, and we’ve given the process something more important to do – rather than simply delegate its work to the IRenderable or IMoveable implementations, it does the work itself.
The first apparent consequence of this is that all entities must use the same rendering method, since the render code is now in the RenderProcess. But that’s not actually the case. We could, for example, have two processes, RenderMovieClip and RenderBitmap for example, and they could operate on different sets of entities. So we haven’t lost any flexibility.
What we gain is the ability to refactor our entities significantly to produce an architecture with clearer separation and simpler configuration. The refactoring starts with a question.
Do we need the data classes?
Currently, our entity
class Spaceship
{
public var moveData:MoveData;
public var renderData:RenderData;
}
Contains two data classes
class MoveData
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
}
class RenderData
{
public var display:DisplayComponent;
public var position:PositionComponent;
}
These data classes in turn contain three components
class PositionComponent
{
public var x:Number;
public var y:Number;
public var rotation:Number;
}
class VelocityComponent
{
public var velocityX:Number;
public var velocityY:Number;
public var angularVelocity:Number;
}
class DisplayComponent
{
public var view:DisplayObject;
}
And the data classes are used by the two processes
class MoveProcess implements IProcess
{
private var targets:Vector.<MoveData>;
public function move( time:Number ):void
{
for each( var target:MoveData in targets )
{
target.position.x += target.velocity.velocityX * time;
target.position.y += target.velocity.velocityY * time;
target.position.rotation += target.velocity.angularVelocity * time;
}
}
}
class RenderProcess implements IProcess
{
private var targets:Vector.<RenderData>;
public function update( time:Number ):void
{
for each( var target:RenderData in targets )
{
target.display.view.x = target.position.x;
target.display.view.y = target.position.y;
target.display.view.rotation = target.position.rotation;
}
}
}
But the entity shouldn’t care about the data classes. The components collectively contain the state of the entity. The data classes exist for the convenience of the processes. So we refactor the code so the spaceship entity contains the components rather than the data classes.
class Spaceship
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
public var display:DisplayComponent;
}
class PositionComponent
{
public var x:Number;
public var y:Number;
public var rotation:Number;
}
class VelocityComponent
{
public var velocityX:Number;
public var velocityY:Number;
public var angularVelocity:Number;
}
class DisplayComponent
{
public var view:DisplayObject;
}
By removing the data classes, and using the constituent components instead to define the spaceship, we have removed any need for the spaceship entity to know what processes may act on it. The spaceship now contains the components that define its state. Any requirement to combine these components into other data classes for the processes is some other class’s responsibility.
Systems and Nodes
Some core code within the entity system framework (which we’ll get to in a minute) will dynamically create these data objects as they are required by the processes. In this reduced context, the data classes will be mere nodes in the collections (arrays, linked-lists, or otherwise, depending on the implementation) used by the processes. So to clarify this we’ll rename them as nodes.
class MoveNode
{
public var position:PositionComponent;
public var velocity:VelocityComponent;
}
class RenderNode
{
public var display:DisplayComponent;
public var position:PositionComponent;
}
The processes are unchanged, but in keeping with the more common naming I’ll also change their name and call them systems.
class MoveSystem implements ISystem
{
private var targets:Vector.<MoveNode>;
public function update( time:Number ):void
{
for each( var target:MoveNode in targets )
{
target.position.x += target.velocity.velocityX * time;
target.position.y += target.velocity.velocityY * time;
target.position.rotation += target.velocity.angularVelocity * time;
}
}
}
class RenderSystem implements ISystem
{
private var targets:Vector.<RenderNode>;
public function update( time:Number ):void
{
for each( var target:RenderNode in targets )
{
target.display.view.x = target.position.x;
target.display.view.y = target.position.y;
target.display.view.rotation = target.position.rotation;
}
}
}
interface ISystem
{
function update( time:Number ):void;
}
And what is an entity?
One last change – there’s nothing special about the Spaceship class. It’s just a container for components. So we’ll just call it Entity and give it a collection of components. We’ll access those components based on their class type.
class Entity
{
private var components : Dictionary;
public function add( component:Object ):void
{
var componentClass : Class = component.constructor;
components[ componentClass ] = component'
}
public function remove( componentClass:Class ):void
{
delete components[ componentClass ];
}
public function get( componentClass:Class ):Object
{
return components[ componentClass ];
}
}
So we’ll create our spaceship like this
public function createSpaceship():void
{
var spaceship:Entity = new Entity();
var position:PositionComponent = new PositionComponent();
position.x = Stage.stageWidth / 2;
position.y = Stage.stageHeight / 2;
position.rotation = 0;
spaceship.add( position );
var display:DisplayComponent = new DisplayComponent();
display.view = new SpaceshipImage();
spaceship.add( display );
engine.add( spaceship );
}
The core Engine class
We mustn’t forget the system manager, formerly called the process manager.
class SystemManager
{
private var systems:PrioritisedList;
public function addSystem( system:ISystem, priority:int ):void
{
systems.add( system, priority );
system.start();
}
public function update( time:Number ):void
{
for each( var system:ISystem in systemes )
{
system.update( time );
}
}
public function removeSystem( system:ISystem ):void
{
system.end();
systems.remove( system );
}
}
This will be enhanced and will sit at the heart of our entity system framework. We’ll add to it the functionality mentioned above to dynamically create nodes for the systems.
The entities only care about components, and the systems only care about nodes. So to complete the entity system framework, we need code to watch the entities and, as they change, add and remove their components to the node collections used by the systems. Because this is the one bit of code that knows about both entities and systems, we might consider it central to the game. In Ash, I call this the Engine class, and it is an enhanced version of the system manager.
Every entity and every system is added to and removed from the Engine class when you start using it and stop using it. The Engine class keeps track of the components on the entities and creates and destroys nodes as necessary, adding those nodes to the node collections. The Engine class also provides a way for the systems to get the collections they require.
public class Engine
{
private var entities:EntityList;
private var systems:SystemList;
private var nodeLists:Dictionary;
public function addEntity( entity:Entity ):void
{
entities.add( entity );
// create nodes from this entity's components and add them to node lists
// also watch for later addition and removal of components from the entity so
// you can adjust its derived nodes accordingly
}
public function removeEntity( entity:Entity ):void
{
// destroy nodes containing this entity's components
// and remove them from the node lists
entities.remove( entity );
}
public function addSystem( system:System, priority:int ):void
{
systems.add( system, priority );
system.start();
}
public function removeSystem( system:System ):void
{
system.end();
systems.remove( system );
}
public function getNodeList( nodeClass:Class ):NodeList
{
var nodes:NodeList = new NodeList();
nodeLists[ nodeClass ] = nodes;
// create the nodes from the current set of entities
// and populate the node list
return nodes;
}
public function update( time:Number ):void
{
for each( var system:ISystem in systemes )
{
system.update( time );
}
}
}
To see one implementation of this architecture, checkout the Ash entity system framework, and see the example Asteroids implementation there too.
Conclusion
So, to summarise, entity systems originate from a desire to simplify the game loop. From that comes an architecture of entities, which represent the state of the game, and systems, which operate on the state of the game. Systems are updated every frame – this is the game loop. Entities are made up of components, and systems operate on the entities that have the components they are interested in. The engine monitors the systems and the entities and ensures each system has access to a collection of all the entities that have the appropriate components.
However, systems don’t generally care about the entity as a whole, just the specific components they require. So, to optimise the architecture and provide additional clarity, the systems operate on statically typed node objects that contain the appropriate components, where those components all belong to the same entity.
An entity system framework provides the basic scaffolding and core management for this architecture, without providing any actual entity or system classes. You create your game by creating the appropriate entities and systems.
An entity based game engine will provide many standard systems and entities on top of the basic framework.
Three entity system frameworks for Actionscript are my own Ash, Ember2 by Tom Davies and Xember by Alec McEachran. Artemis is an entity system framework for Java, that has also been ported to C#.
My next post covers some of the reasons why I like using an entity system framework for my game development projects.
Tags: Actionscript, Ash, Entity systems, Game development

75 Comments add your own
Thank you Richard,
It’s way clearer to me now. Following this refactoring step by step is certainly helpful. Great post.
Nicolas Bousquet | 19th January 2012 at 15:28
Great post, thank you!
I have learned a lot to learn from this.
Oliver | 19th January 2012 at 18:45
Hi,
interesting, but you should definitely avoid for each loops, since it is the slowest. Try for, with decrementation.
var i:int;
var length:int
for (var = length – 1; i > = 0; i –){}
Martin Weiser | 20th January 2012 at 10:20
Hi Martin
You miss the point. Yes, for() is faster than for each(). But this is an article about architecture, not optimisation. for each() is a standard loop construct in Actionscript and is the appropriate construct to use when describing how the architecture works. If you want to see an optimised implementation of the architecture, take a look at Ash, which uses linked lists rather than vectors because they’re so much faster.
Richard | 20th January 2012 at 10:56
Hi Richard,
Can you indicate how you would implement PrioritisedList? — Dictionary with the item and priority?
charlie | 20th January 2012 at 16:26
Hi Charlie
Ash is a full implementation of the architecture described above. Here’s the implementation of the prioritised list from there.
Richard | 20th January 2012 at 16:46
Thanks Richard… And apologies for missing the obvious.
I have a further question: It seems that if I wanted to add in some sort of collision checking I could either extend the MoveSystem, or add in a new CollisionSystem.
But if I wanted to use a 3rd party physics engine, what would be the best way of adding/using it?
charlie | 20th January 2012 at 21:27
Hi Charlie
That depends very much on the circumstances. Generally, more and simpler systems is better, provided that doesn’t compromise the game by limiting functionality. If you can split the physics into multiple systems with different responsibilities then you should do so. If it only works as one big system then that’s the way to go.
Integrating a 3rd party physics engine is dependent on the engine. Ideally, you’d create one or more systems whose functionality is backed by the 3rd party engine.
Richard | 21st January 2012 at 11:09
[...] explained why we need a simple entity system. Richard Lord has made an amazing blog post : What is an entity framework for game development?. Now I’ve fully understand how it works. But mixing it with box2d, frame animation, input [...]
CitrusEngine goes Stage3D with Starling :Aymeric Lamboley | 21st January 2012 at 14:46
Hi, taking it from twitter. At the begin of the article you used initialization examples to make your point clearer:
public function createSpaceship():Spaceship
{
var spaceship:Spaceship = new Spaceship();
…
renderProcess.addItem( spaceship.renderData );
moveProcess.addItem( spaceship.moveData );
…
return spaceship;
}
I would like to see how the entities/system are initialized with an example also after your conclusions. Thank you very much.
Sebastiano | 21st January 2012 at 18:18
Hi Sebastiano
Thanks for the suggestion. I’ve added the final initialisation code to the article (look for “createSpaceship” if you can’t find it immediately).
Richard | 22nd January 2012 at 19:37
Hi Richard,
I’m just having a go at trying to implement this…
I’m just struggling with rendering the DisplayObjects.
It seemed to me that adding a Sprite to the renderProcess and then trying to add/remove theDisplayObject to/from that Sprite when you addItem/removeItem would be the way to go.
But, this hasn’t worked and I wondered if you could offer an insight?
Charlie
charlie | 23rd January 2012 at 16:09
Hi Charlie
There’s an example here.
Richard | 23rd January 2012 at 17:05
Thanks! (And apologies again, prpobably should have noticed that – I have looked at Ash, but clearly didn’t go thru all the directories.).
charlie | 23rd January 2012 at 19:30
Hi Richard,
it’s a very interesting article, and Ash is a really high quality implementation.
The only part it wasn’t clear for me was the last one, so I had to look at the code to fully understand it.
It was how to create a node from an entity, then I saw the describeType function is used, though I suppose in another language the class of the node could provide a static array of the required classes.
I’m currently developing with the Pushbutton Engine, which is an object oriented entity framework like the one you described just before the “pause” in the article, so I can see the big change with this approach.
What I’d like to ask you is to elaborate more about the advantages of this framework and some disadvantages I could think of:
- the entities cannot have more components of the same type. For example, in my project I can have two renderables for the same entity.
- in a big project the number of systems could explode, having many systems which work for just one entity each.
- in a big project with a lot of entities and a lot of systems, it couldn’t be easy to have unexpected behaviours, like for example adding a component to an entity, and then it gets “detected” by the node constructor, which in turn starts to create nodes for it. Shorter, a system could modify the components and we are not aware of it.
- in a big projects with a lot of entities, an entity could need a new component, which would force us to update the system that handles it, which in turn would require to update all the entities the new component. Wouldn’t it be hard to maintain?
Thank you for your attention
Riccardo | 24th January 2012 at 10:26
Hi Riccardo
Thank you for the feedback. I’m hoping to find more time for blog posts about advantages beyond those I mention above.
1. If you want to have two instances of the same component on an entity, there’s usually a better solution. Often it is to have two entities.
2. More systems is not a problem. In fact, many simple systems is one goal of this architecture. You need to put the code somewhere, and if you separate it into its own system that avoids complicating other code.
3. Don’t confuse an entity needing a new component to correctly define its state with a system needing entities to have a new component in order to apply its functionality. In the first case, there’s no need to update other components. In the latter case, yes you have to update all the entities. The system you’re implementing requires this.
Richard | 25th January 2012 at 19:40
Hi Richard,
Thanks for posting this. I was just wondering if you had seen the PushButton engine framework and how you specifically view Ash as being different? Thanks
Sean | 30th January 2012 at 15:26
Hi Sean
I haven’t used PushButton, but I’m reliably informed it’s architecture is like that I describe part way through the article, at the section called ‘A good place to pause’. So everything after this in the article is what makes the architecture of Ash different.
Richard | 31st January 2012 at 19:17
Great article!
I read a couple of articles about Entity Frameworks but anyone was so practical! Finally I got how it should work and how it should be used. Thanks a lot, I will try to use it in my next game. Do you have any experience with haXe? I would love to see ash ported to haXe. If you are not interested would you mind if I try to do it future?
Jorasso | 31st January 2012 at 21:18
Hi,
It’s a very interesting solution that you propose here. It’s a demonstration that true OOP programming is not about blindly applying the same trendy framework or architecture in any context for any purpose.
I have absolutely any skill in game programming, but again OOP is about applying rules that probably might not differ very much from those applied in other programming domains.
Design by contract and testability should be the first priorities especially if you create a framework.
IMHO I think that your solution could be improved for testability.
When you write this:
target.display.view.rotation = target.position.rotation , you don’t respect the Demeter Law.
Favoring composition over inheritance doesn’t imply that you can request properties so deeply nested in the composition chain.
I have tried to find a way to avoid it and here is a possible solution.
First I don’t understand why you create a DisplayComponent class wrapping an instance of the DisplayObject with no logic inside the class. If you want to use it as a proxy of the display object , why not implementing a true proxy and add all the getters and setters of the display object properties that you need for all further processing. You won’t then write “display.view.x” but “display.x”.
And perhaps add some getters and setters that the DisplayObject class doesn’t have and build a decorator of the DisplayObject class, if needed.
But do u really need to wrap the DisplayObject ?
Secondly, if I well understood, your intention was to encapsulate the updating process of different group of properties that defines a state or a behavior of an object according to the time passed to respect the single responsibility principle.
That’s the really good idea of your solution.
But I think that the each System class should just have the only responsibility of updating each node without knowing what exactly to do to update the node. The implementation of the update process should IMO be the responsibility of the Node.
For instance, If you implement a Node like that.
class MoveNode implement IUpdatable{
public var position:PositionComponent;
public var velocity:VelocityComponent;
public function update(time :Numer) :void{
position.x += velocity.velocityX * time;
position.y += velocity.velocityY * time;
position.rotation += velocity.angularVelocity * time;
}
}
The MoveNode class knows about the position API and the velocity API which are direct collaborators of the class, the Demeter law is respected.
Then your system class becomes :
class MoveSystem implements IUpdatable
private var targets:Vector.;
public function update( time:Number ):void{
for each( var target:IUpdatable in targets ) {
target.update(time);
}
}
Again Demeter Law is respected because the class knows about the IUpdatable interface through the Vector definition.The system has the only responsibility of iterating over nodes and applying the update.
Again thanks for posting this, and hope to read about what u think about this kind of refactoring
boris | 31st January 2012 at 23:18
Hi Jorasso
Yes, haXe is interesting, particularly with the introduction of NME. I don’t have any experience with it at the moment, but it’s one of the languages/platforms I intend to look into this year. I’d be very happy for you to port Ash to haXe.
Richard | 1st February 2012 at 09:02
Hi Boris
The architecture you describe seems to be exactly the architecture I describe in the article just before the section called “A good place to pause”.
One difficulty with putting the update logic in the node is, how would you handle updating a system where the nodes react to other nodes – collision detection for example? This can’t be isolated to a single node and sits better in the system, where all the nodes are available.
Richard | 1st February 2012 at 12:51
Hi Richard,
yes it seems that I made a 360° turn on myself… lol
But then, why don’t you proxy all the properties your need for your system logic ?
for instance in the ModeNode having
get x():Number{
return postionComponent.x;
}
set x(value:Number):void{
positionComponent.x=value;
}
and the same for velocityX etc,
You would be able to extract an interface of that? don’t you think it would be more easy to test?
boris | 2nd February 2012 at 09:19
Hi Boris
Because it’s a lot more typing and will execute more slowly. It’s a pragmatic decision.
And as I said before, I’m not concerned with testing the value objects. Because they all use simple properties – no getters and setters – they have no side effects, so I don’t think there’s any need to test them or to mock them. When testing the systems I just use instances of the value object in the tests.
Richard | 2nd February 2012 at 09:45
Again, terrific explanation!
With regards update logic in the node (as per Boris), I favor this approach in “awe6″. Yes, it’s often inappropriate for complex interactions (such as physics or rendering) but I find these things are generally best handled by third party subsystems (i.e. they need to be wrapped and injected into anyway).
Whereas the benefit of an “Entity that does everything” (state and logic) is that “System” and “Component” classes become redundant. This allows Entities to safely handle their own dependencies on the fly.
For example Spaceship:Entity needs Moveable:Entity which needs Position:Entity. When Moveable is added to Spaceship it searches inside Spaceship (parent) for Position, if found then use it, if not then create it. Next when Renderable:Entity is added to Spaceship it will find an existing Position in Spaceship and use that. Position itself could even search for X:Entity etc, and continue to look up the tree until it found Physics:Entity etc. Also multi phase initialization becomes possible. iirc PushButton Engine also considered such a dependency tree?
And by avoiding Static Systems all dependencies can rely on interface. So elaborate Entities could fulfill numerous obligations directly if preferred, or overwrite existing fulfillments with newer ones as new behaviors are added & combined. E.g. if an Entity contains Movable and Renderable replace both with SuperDuperMovableRenderable which has some optimizations as a result of the union.
Next by adding state machines to the Entities (I call them “agendas”) this can enable or disable nested entity logic making for some flexible AI possibilities.
Fascinating subject.
Rob | 7th February 2012 at 19:14
Hi Rob
Entities as objects is the classic object-oriented approach to modern game development and is in no way incorrect. However, it’s not the architecture I favour and is not the architecture I use in Ash.
I find that games are not best suited to an object-oriented approach. For me, they are better suited to a state/systems approach because they are so much about large state and systems that affect that state.
When using an object-oriented language, it’s often hard to stop thinking about objects. The architecture I describe above is not object-oriented, and that is its strength. It is about big state, represented by the components, and systems that affect that state. In my experience, it provides much greater flexibility than the object oriented approaches.
Nothing you describe can’t be done in a component/systems architecture, and it would be achieved without the need for “elaborate Entities” that “fulfil numerous obligations”.
At the end of the day, it’s about choice. We all have to build and ship good quality games. If your object-oriented architecture enables you to do that, that’s what matters.
But I would encourage you to give the component/system architecture a go to find out what it can do. Your brain will hurt at first, as you struggle to stop thinking in an object-oriented way. But it’s well worth the effort.
Richard | 8th February 2012 at 08:49
I’ve build a mountain of games using the traditional OOP approach described above. In the last 6 months I’ve used Ember, Ember 2 and now Ash for my projects and I can say that I find it far more flexible. Once you get over the initial learning curve, the flexibility it offers outweighs any advantage I have found from other methods.
Phil | 8th February 2012 at 14:47
Hi Richard,
thank you for Ash and for this great article.
After a lot of study and different experiments (with Citrus and PushButton engines) I’m definitely convinced that composition is the best approach for game frameworks and this page is a very good point to start implementing it in Actionscript.
Eros Marcon | 13th February 2012 at 11:42
Hi, Richard, thanks for the excellent article!
One thing I want to ask is that you don’t mention communications & data sharing among entities/components in this framework, nor do I see from the code base of the example. Is there any brief way to implement that? Thanks!
Silver | 13th February 2012 at 20:11
Hi Silver
Data sharing between entities can be done one of two ways -
1. A component may contain a reference to an entity. So, for example, an object may contain a reference to the entity that is holding the object. Or alternatively an entity may contain a reference to the entities it is holding. (Try not to do both
)
2. A component may be shared by two entities. So, for example, an entity representing a speech bubble may share a position component with the entity whose speech it displays.
Communication occurs between systems not entities, because entities are just value objects. You will generally choose one of two methods to communicate between systems -
1. Systems dispatch events (or signals) which other systems listen for. The listening systems may react immediately or may delay their reaction until their next update.
2. Systems set properties in components that other systems read as a trigger for them to act. The properties may be simple booleans or strings, or they may be event or message objects. The ‘speaking’ system sets the property and the ‘listening’ systems react to the property value. The ‘speaking’ system will reset the property on the next update loop to stop the systems reacting to it more than once.
In many ways this second option is just a special case of the general architecture. In the example, the MoveSystem alters the entity’s position property and the RenderSystem reacts to that change by drawing the entity in the new position. This is communication between systems. That’s why I favour the second option.
Richard | 14th February 2012 at 08:56
Really thanks Richard! Now it becomes clearer to me and I can start to transfer my project to entity framework with less confusion.
Silver | 14th February 2012 at 16:28
Hi Richard, indeed games are reactive state based on services
Apologies, if I was unclear – I was not championing “object oriented” over a component framework. I was encouraging a “Type Value database + Injection” over a “StringKey Value database + Static” in respect of it’s implementation. i.e. Liskov substitution and interface segregation to allow “safe on the fly”.
E.g. static services replaced by typed (and therefore substitutable) relationships allowing “entities” to rewire their own service providers as their state unfolds.
= Entities that have the “opportunity” to self improve.
Rob | 16th February 2012 at 23:36
what about when the node has two members are same component (Class).
tamt | 23rd February 2012 at 03:42
Hi tamt
A node could only have two members of the same component if an entity has two members of the same component, and Ash doesn’t allow that. In my experience, allowing two components of the same type on an entity adds enormous complexity and no gain. If you find yourself wanting two components of the same type on the same entity, the right solution is usually either
1. Split the entity into two entities.
2. Define a component that contains a collection of objects.
3. Define two similar but different components to represent the difference between the two components you want to add to the entity.
Richard | 23rd February 2012 at 09:05
thanks Richard, i am trying use your entity framework in my working project.
tamt | 24th February 2012 at 03:13
Regarding events, the purest method is to apply the signal-slot messaging paradigm everywhere, and never allow any entity or component to directly access each other’s state. This is effectively the architecture of Smalltalk systems, retailored to game entities. It adds a lot of weight when implemented in pure fashion, but possibilities exist to carve back performance by merging components, or possibly applying Haxe macros to lighten messages at compile time.
Instead of allowing pointers into data structures, at the moment when components are added, they have the option of attaching event listeners to the entity. The entity is essentially only a listener container now, since the listeners redirect from the entity to a specific component node(solving multiple components per entity). The components have to reach each other through messaging, too. Queries for properties, state changes, etc. all run over the messaging protocol.
Messages are full objects containing a caller, target and a data payload, and when sent, the listener can produce a return value(synchronous response) or send another message to the caller, possibly via some other entity(asynchronous). This opens up the flexibility to filter, redirect, and queue events before they hit the endpoint listener.
Extrapolating this, you may end up with a special World entity that represents all the Systems; its listeners are the point of access for all global state, and also the way to advance time(post an event to tick frames). The ordering of events occurs within World’s tick listener, and can be refactored from “big main loop” to more distributed concepts as necessary.
The outcome of this architecture is a massive decomposition, since now aggregate state is encapsulated by customized protocols, instead of by customized data structures – a distinction that starts small but ends with big consequences.
James Hofmann | 10th March 2012 at 20:49
Hi,
thank you for this post! It gave me an ideas and answers I was missing.
However I feel skeptical if implementation can not be done ‘cleaner’… or more intuitive.
So I accept the challenge to try and meet render loop requirements in framework I am working on, but from the different angle.
Keep a good work!
Deril | 21st March 2012 at 10:00
I have been studying Entity/Component systems for some time now. But it was not until I read this article that it finally clicked for me. Thank you for that.
On the issue of entities having more than one component of the same type, you spoke of having a component acting as a collection of objects. What if the objects in that collection were components themselves, so that the container would be some kind of meta-component as it were. Would this be a viable approach in your opinion?
Damion Murray | 21st March 2012 at 23:13
[...] What is an Entity Framework [...]
Game entity management system – part 2 « IceFall Games | 7th April 2012 at 02:23
Nice explanation.
Could you add this to the Entity Systems wiki? There’s a page collating the different approaches, with a template for adding new ones and adding links to source code implementations:
http://entity-systems.wikidot.com/es-approaches
Each impl then has sub sections for:
– list of concepts in the ES
– list of classes in the ES
– descriptions of each claass
e.g: http://entity-systems.wikidot.com/rdbms-with-code-in-systems
adam | 22nd April 2012 at 13:16
I have been dabbling with entity bases systems for a short time and was intrigued by your concept of node. Could you explain the purpose/benefit of collecting components from entities into Nodes as opposed to having Systems operate on Entities directly?
Ben | 25th April 2012 at 16:36
Hi Ben
The nodes contain the entities for a particular system, but also contain strongly typed references to the components of that entity that are required by the system. This provides faster lookup and use of these components at runtime. As an added bonus it also provides strict typing and code completion within the IDE and compiler, which helps the developer.
In some languages it’s not necessary, particularly where tools like generics are available, but in Actionscript the improvements are significant and worthwhile.
Richard | 1st May 2012 at 10:00
What I like about the notion of nodes is that there is this explicit one-to-one relationship between a system and the type of node it manipulates. For me it makes the concept of a system acting on specific collections of state (i.e. subsets of components associated with an entity) more concrete.
Even with the benefits of generics I would favor this approach just for the clarity it offers.
Damion | 1st May 2012 at 22:14
I really like the idea, but my fear is removing entities when there already thousands. Wouldn’t you need to search through each system and find the component owned by the removed entity?
Also, how would you think to store components in an entity in c++? A linked list of enums and components? We have no such “Dictionary.”
David | 5th May 2012 at 16:40
Hi David
When you remove an entity, you also remove it from all the node-lists it’s in. That is all. There are various ways to make that more efficient, including using bitmasks to indicate the components in an entity and in a node.
As for the container in C++, if you give each component an integer identifier (perhaps corresponding to the bitmask mentioned above) then any container that can map from that index to an object would do. A hash-map might be best – many STL library implementations have been extended to include a hash-map implementation.
Richard | 6th May 2012 at 10:48
I guess I just feel like removing an entity would be really slow with lots and lots of entities, even if you used a bitmask.
David | 6th May 2012 at 17:33
If I have two entities A and B.A is B’s child.How can I handle these relation in some system’s update?
For example A’s position depand on B’s position.
And this relation is dynamic ,every entity can add/remove child everytime.
If I use traditional objectcontainer,this problem can be sloved by tree structure.
Dairectx | 24th May 2012 at 03:15
Hi Dairectx
Entities can still have references to other entities – the entity reference would be a property of a component. So A may have a component with a property children which is an array of entities, or B may have a component with a property parent which is an entity.
Although sometimes there are other solutions such as shared components, for example if B’s position is dependent on A’s position, then A and B could share a single position component.
Richard | 24th May 2012 at 08:41
Hey Richard,
I’ve written an Entity System in haXe over the last six months, that is sadly not (yet?) open-source. It uses a few haXe features to give a significant performance improvement. I’d be happy to discuss these offline and/or collaborate with you on a framework if you go that way.
Best,
Alec
Alec McEachran | 31st May 2012 at 19:27
I’ve been implementing my own entity component system in c++, but I’ve run into a bit of a problem. I hate to ask another question, but how would you go about handling invisibility?
I’d like to have an invisibility component. If the invisible flag of the invisibility component is true, the sprite should not be rendered. Simple enough, right?
Unfortunately, I’ve found this kind of breaks the system. If I add the invisibility component to the RenderSystem’s RenderNode, everything that wants to be rendered must be able to be invisible. That doesn’t make sense. Or does it?
Thanks!
David | 2nd June 2012 at 15:41
@David: IMHO to make something invisible means to make it not renderable. So you just need to remove RenderSystem from such entity. That rather should not be a part of your framework in general, that’s some functionality of concrete game. Alternatively, what about extending RendererSystem and adding some code to render ‘invisible’ entity?
@Richard: Excellent post
. But there’s one thing that is bothering me. It’s the usage of “Component” term. As for me, structures that contains some data only should be rather named as value objects/models. Even in PushButton engine, “Component” means something more than bare data structure (i.e. HeroControllerComponent could manage keyboard input and change position/angle stored inside this component). Not to mention, what “Component” means in UI programming (it’s rather mix of view, model and controller layers). I’m not as experienced programmer as you, so I’m asking – what are roots of this “Component” term?
Maciek | 5th June 2012 at 23:30
@Maciek: I use the term component because it is a common term in this context within entity systems. The origins are the component as a constituent part of the entity – i.e. the general english language meaning of a component as a constituent part of something.
I agree that there is potential for confusion within software development and had I invented the whole entity architecture I’d have been inclined to use a different term, like Ingredient or Element. But given the term is now a standard within entity systems it makes sense to use it in Ash.
Richard | 6th June 2012 at 10:39
@David: As Maciek says, you either make visibility a feature of renderable objects and so add a visible property to the render component, or you remove the render component from the entity to prevent rendering it.
There is one other option, but I would not recommend it in your example, and that is within the render system to test whether the entity has an invisible component (in Ash this would be node.entity.has( Invisible ) ).
Richard | 6th June 2012 at 10:44
But the players should have the ability to go invisible. Invisibility should be coordinated across a server/client, and thus should be seperate from the RenderSystem. Maybe the RenderNode should have an optional parameter?
Speaking of which, how would I go about networking entities? Should each component have a networkable flag? Tweening may become an issue as well.
David | 6th June 2012 at 22:42
I am very curious how to add to such architecture something like Tweener? I can imagine some solutions but all of them make it less comfortable in use than traditional way.
Kuba | 2nd July 2012 at 22:43
[...] http://www.richardlord.net/blog/introducing-ash 2. http://www.richardlord.net/blog/what-is-an-entity-framework 3. [...]
Games And Entity Systems | Shaun Smith | 4th August 2012 at 19:25
[...] Systems are the future of MMOG development, Entity Systems. Then Richard Lord has made a very good blog post with code example using his own framework : Ash. And finally, Shaun Smith’s experience using [...]
Aymeric Lamboley » An entity/component system’s attempt using Box2D | 9th August 2012 at 15:31
hi,it’s a good framework,but not easy to use.there are so many properties should be set in code.if you make a tool,can translate a xml to a game with your famework,it will be better.
?? | 12th October 2012 at 03:14
[...] What is an Entity Component System? [...]
Box Hacker » Blog Archive » Using an entity component system in AS3 | 23rd October 2012 at 17:38
[...] Also check out Richard Lords post with a practical example here [...]
Entity Systems | Tom Davies | 7th November 2012 at 11:58
[...] What is an entity framework [...]
Game Architecture | Tom Davies | 7th November 2012 at 12:01
[...] liest du mal folgende Artikel im Bezug auf Klassenhirachie und Spieleentwicklung durch: What is an entity system framework for game development? Why use an entity system framework for game development? Sind sehr interessant und das Entwicklen [...]
Von OOP zu MVC - Flashforum | 12th December 2012 at 19:14
[...] my game, and I’m using an entity system based off of Mr. Lord’s post which you can find here. To summarize, I have four different components: Components which hold data, Nodes which hold [...]
The Problem of Identity | RedIrony | 26th December 2012 at 04:14
[...] What is an Entity Framework? [...]
Useful Links « Paige Ashlynn | 27th December 2012 at 06:30
I have two versions of getComponent function, one check for inexistent components (used by systems that can act in a variety of entities even if not all have the same component set, like AI), the other, the fast one, allow memory violation if you try to access an inexistent component. System that access components this way, have an interface to get notified when an entity changes its component set (removal or addition of components) and then recheck the entity and if it has no more the required components by that system the entity get removed from the system, but these systems never check for components during game loop, because that would make them run slow.
Peggy V. Wiggins | 8th January 2013 at 16:41
I am trying using starling tween for animating some of the entities and I am able to find the best way to integrate tween with rendering and animating system as used in Asteroids example. So the scenarios is,
- There is an Inputsystem which handles all inputs and delegates to input nodes.
- Input nodes depending on the input will perform some action like move to the clicked point, change state or animate.
Any help on how to integrate the animation/tween with ASH will be really helpful
LostSoul | 16th January 2013 at 14:15
Some documentation explaining how “families” work would be very useful, I am unable to glean from the code how exactly systems gain reference to an entity’s relevant node when added/created.
bob | 27th January 2013 at 14:37
An Entity contains a dictionary of Components.
A Node contains references to an Entity’s relevant components.
A System works on Nodes.
The Engine contains the Entities and the Systems.
In the Asteroids example:
You create the Engine and add the needed Systems.
You create the Entities with needed Components, and add them to Engine. Then….?
I can’t find where in the code the Entities’ nodes are created and passed on to the Systems. The unmentioned ComponentMatchingFamily class does something like this, but it doesn’t communicate with any System.
Also, since one needs to check an Entity’s components before creating/adding the node to a System…. Why bother using Nodes? Couldn’t the Systems keep references of the Entity’s needed components instead of using Nodes to do exactly that?
One final question, the limited info on entity systems seem to suggest that in a c# environment the components would be structs (which don’t exist in java) and not classes as in the c# version of Ash, is that correct?
-Thank you
bob | 28th January 2013 at 10:42
[...] What is an entity system framework for game development? [...]
Tinkering With Ash - MikeCann.co.uk - mikey see, mikey do! | 14th February 2013 at 18:31
[...] I have been learning both Java and the entity component system of program. I found an awesome site that has describes this. The author Richard Lord also has used ActionScript to create an [...]
Entity Component Systems | Chad Miller's Software Blog | 1st March 2013 at 02:28
Hi, thanks for this article, it is very inspiring.
I have the feeling I tried to picture this for a long time, but things has always been blurry and unclear.
Now it is crystal clear thanks to your explanations. I tried to implement this in C#, lurking the core Ash action script source code at the same time. It was not easy because I do not know ActionScript at all, so I struggle to understand really how nodes and components reacts each other.
Now I have something that works: a very simple application with a thin core engine that respect this architecture and makes some balls bouncing everywhere using Farseer Physics Engine and WPF.
As it has opened a door to me, I will try to make something more interresting in the future.
Laurent | 30th March 2013 at 21:53
I finally managed to get something working in C#. It is a start and a lot of things has to be done.
To see what has been done so far, have a look on https://github.com/grumly57/TryEngine
Laurent | 5th April 2013 at 13:35
[...] to the rescue with Ash. It’s an Actionscript3 entity component game engine. He also wrote an extremely detailed blog post outlining the difference between an inheritance-based design and an ent…, with a ton of code snippets so you can see the implementation [...]
Entity Component Systems - A Practical Example | wasted potential | 26th April 2013 at 04:42
Richard, excellent article. This is probably the best article on ECS I’ve seen to date. However, there is one thing that has me puzzled. In the article, you remove the Data Classes (RenderData, MoveData), to have the components in the entities themselves. That I understood. But then you reintroduce the Data Classes as Nodes (Why? I thought they went away.), then kinda gloss over Nodes’ implementation in the detail you gave everything else. Could you expand on the Nodes and why and how you use them?
Da Gamer | 14th May 2013 at 21:28
@Da Gamer
Before removing the data classes the entity was composed of the data classes and the data classes were composed of components. I remove the data classes because they are not needed for the entities – the entities can and should be composed of the components themselves.
However, the data classes are also the aggregating object that combines components for use by the systems. This requirement is still present, sort of, which is why they are reintroduced as nodes, but only for use by the systems, they are no longer part of the entities.
We could not reintroduce the nodes and instead provide each system directly with a collection of entities that have all the necessary components for that system, and the system could fetch each component from each entity as required. But all the component look-ups and casting would be much slower than using the nodes. It can be made a lot faster with a language that supports generics but ultimately the nodes are just more efficient and they simplify the systems since everything in the node is statically typed.
Richard | 14th May 2013 at 21:59
Leave a Comment comment policy
XHTML: you can use these tags - <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>Subscribe to the comments via RSS Feed