Component-based entities

Introduction

What is component based game design? Here’s a couple of good articles:

The first article will give you an overview and the second one dives more into detail and implementation alternatives.

There are some existing open projects out there:

An example system in JS

To begin with you should test this proof of concept game I created: http://game.jsteam.org

For the rest of this article I will describe the way I currently code component based games in js. I will use a different approach than DonaldHays in that gamedev forum thread and as I am kinda new to component based entities I can not guarantee that my way is the best one.

I will use a pure aggregation approach
That means that an entity only contains components. There is nothing else to an entity. An entity is simply the sum of it’s components.

My approach bears resemblance to the Gang of Four’s Strategy pattern.
Because my components will only contain state. No algorithms / functions / strategy etc, I will put that in “subsystems” instead.

I will use something similar to “the Structure of Arrays pattern” mentioned at gameprogrammingpatterns.com
The purpose of this is to be able to find all entities that contains a certain component type very fast. For example finding all entities with AI very fast.

When using my approach an entity is an object and each property of that object is a component. Say the components we have are called “visual“, “ai” and “physics“. This is what an entity for an “ai-controlled enemy robot” could look like:

// Entity for an ai-controlled enemy robot
{
	visual: {
		image: "http://example.example/robotimage.png"
	},
	ai: {
		agressive: true,
		targetEntityId: 230
	},
	physics: {
		x: 5,
		y: 10
		dir: 0,
		speed: 3.23
	}
}

Note that the robot enemy made use of all possible components. However some entities might only use a few. An “apple tree” entity would lack the ai component and could look like this:

// Entity for an apple tree
{
	visual: {
		image: "http://example.example/appletree.png"
	},
	physics: {
		x: 5,
		y: 10
		dir: 0,
		speed: 0
	}
}

All entities should have an unique id and it is probable we need to find an entity by it’s id very fast. We therefore put all entities in an object called “entities” where the key is the entity id and the value is the entity:

var entities = {
	0: {... entity object ...},
	1: {... entity object ...},
	2: {... entity object ...},
	3: {... entity object ...},
	4: {... entity object ...},
	...
}

In the gameloop update function we should first update the AI’s, then advance the physics simulation and finally draw the world. So how do we find all entities which has an AI component? We could loop through the entities like this:

for (var entityId in entities) {
	var entity = entities[entityId];
	if (typeof entity.ai !== "undefined") {
		// Update the ai for this entity
	}
}

However this is somewhat inefficient as the game loop update is run very often and the components in an entity isn’t very likely to change. A better solution would be to have an “index” (“the Structure of Arrays pattern”). Another object containing only the entities that has an AI component. If we had that we could do this:

for (var entityId in entitiesWithAiComponent) {
	var entity = entitiesWithAiComponent[entityId];
	// Update the ai for this entity
}

For this I have created the Indexes class in another article. Please read that article now.

Pseudo Game Code

This is what our game could look like:
(Note that I will make use of Timeloop.js and Indexes.js)

var game = {
	entities: {},
	nextEntityId: 0
}
 
// Index the entities
game.indexes = new JST.Indexes(game.entities);
idx.add("ai", function(entityId, entity) {
	return typeof entity.ai !== "undefined";
});
idx.add("physics", function(entityId, entity) {
	return typeof entity.physics !== "undefined";
});
idx.add("visual", function(entityId, entity) {
	return typeof entity.visual !== "undefined";
});
 
// A function to add an entity and at the same give it an id and index it
game.addEntity = function(entityObject) {
	var id = this.nextEntityId;
	nextEntityId += 1;
	this.entities[id] = entityObject;
	this.indexes.updateItem(id);
};
 
// The game must have an update function (the gameloop)
game.update = function(delta) {
	// update the AI’s
	var entitiesWithAI = this.indexes.get('ai');
	for (var entityId in entitiesWithAI) {
		var entity = entitiesWithAI[entityId];
		// * Update the ai for this entity with delta milliseconds*
	}
 
	// advance the physics simulation
	var entitiesWithPhysics = this.indexes.get('physics');
	for (var entityId in entitiesWithPhysics) {
		var entity = entitiesWithPhysics[entityId];
		// * Update the physics for this entity with delta milliseconds*
	}
 
	// finally draw the world
	var entitiesWithVisual = this.indexes.get('visual');
	for (var entityId in entitiesWithVisual) {
		var entity = entitiesWithVisual[entityId];
		// * Update the visual for this entity with delta milliseconds*
	}
}
 
// create the timeloop
game.loop = new JST.Timeloop({
	fps: 60,
	callback: game.update
	thisArg: game,
});
 
// Add some entities
game.addEntity({... entity object ...});
game.addEntity({... entity object ...});
game.addEntity({... entity object ...});
game.addEntity({... entity object ...});
...
 
// start the game
game.loop.start();

You might notice this is a kinda strange pseudo game as it does not read any user input 🙂 So it is a kinda non interactive game at the moment, But hopefully you get the idea 🙂

Strategy pattern?

Can you sense the resemblance to the Gang of Four’s Strategy pattern? All logic aka “the strategy” is in one place (the game.update function) that does not contain any state. And all the state is in the components in the entities where there is no logic / strategy at all. We have effectively separated the state and the strategy. I think this is very nice. If we would like to save the game to disk we could dump JSON.stringify(game.entities) to disc.

Introducing “Subsystems”

If we take a look at the game.update function there’s an interesting discovery to be found. Namely each component type has it’s own part in the gameloop update function. So there seems to be one “strategy” per component type. These strategies could be separated into “subsystems” like this:

game.update = function(delta) {
	// update the AI’s
	this.subsystems.ai.update(delta);
 
	// advance the physics simulation
	this.subsystems.physics.update(delta);
 
	// finally draw the world
	this.subsystems.visual.update(delta);
}

In real games such a separation will be necessary or the game.update function will contain far to much code.

Acknowledgements

I have written a few very simple games using this component based approach. But I cannot say if it will work well with larger games. My system is missing some parts that I find in the spartan framework (the Java one mentioned in the beginning of the article), namely “actions” and “events”. I am still experimenting on how to best implement those part’s in JS and I will write more when I know more 🙂

Finally I would like to ask both you and myself if my code here really is component based. I put the logic in subsystems of the game loop update function instead of putting the logic in methods in the components. So perhaps my approach should be called “entity state components and subsystem strategy based” rather than than component based 🙂

You tell me! I would love feedback on this!

Published by

Olof Larsson

Web-developer, Founder of JSTeam.org and wannabe indie game developer.