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!

Indexes.js – When you need to find certain object properties fast

The result of this article is: indexes.js

Prerequisites: none

Introduction

As mentioned in my article on component-based game design you sometimes need to find the same certain object properties very often and thus very fast.

The result of this article is the class Indexes.js, and that class helps you do just that.

Usage mockup

var entities = {
	0: {... entity object ...},
	1: {... entity object ...},
	2: {... entity object ...},
	3: {... entity object ...},
	4: {... entity object ...},
	...
};
 
// We pass the "indexee" to the constructor
var idx = new JST.Indexes(entities);
 
// When adding an index we supply a name and a callbackfunction that returns either true or false
idx.add("ai", function(key, value) {
	return typeof value.ai !== "undefined";
});
 
// We fetch the index like this:
var entitiesWithAiComponent = idx.get("ai");
 
// And can process them in our gameloop like this:
for (var entityId in entitiesWithAiComponent) {
	var entity = entitiesWithAiComponent[entityId];
	// Update the ai for this entity
}
 
// If we add an entity...
entities[5] = someNewEntity;
 
// ... We can update...
 
// ... a certain index for a certain item
idx.updateIndexItem("ai", 5);
 
// ... a certain index (for all items)
idx.updateIndex("ai");
 
// ... a certain item (for all indexes)
idx.updateItem(5);
 
// ... all indexes for all items
idx.update();

The result

View the sourcecode on github

Timeloop.js – Running a function repeatedly (The Gameloop)

The result of this article is: timeloop.js
Prerequisites: none

Introduction

In this article I will explore how to create a gameloop in javascript. I will focus on the core idea: How to run a certain function repeatedly. The result of this article is the timeloop.js class. So at the end of the article we will have created a reusable class that does just that.

So what is a gameloop? There are a lot of good articles on gameloops already so I will not describe myself. This is a good one:

http://www.koonsolo.com/news/dewitters-gameloop/

While the loops in that article works very well with Java or C++ they won’t work in js so we will have to write ours differently. But more on that issue later.

Are gameloops really suitable for js-games?

Javascript works different compared to for example Java or C++. Javascript is very suitable for event driven programs and this sometimes allows you to code certain features of a program differently. Could it be that we do not need a gameloop in a javascript game?

Imagine a very turn based game. Memory for example. Such a game could probably be coded without using a game loop. It could be completely event driven. We could use the mouse “on click” events. The game advances only when the player clicks on something.

A realtime shooter with AI controlled enemies will however really need a gameloop. Because the AI enemies must act on their own even if the human player sits still and does nothing. Such a game is “time driven” and not “event driven”. The game state advances as time passes, regardless of user input.

Answer: Yes we really need a gameloop. Though for completely event driven games we do not need one.

The while loop approach won’t work

Did you read that article at koonsolo.com I linked to? In that article a while loop is used. The approach would look like this in js:

var lastRun = Date.now(); // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now as a number.
var running = true;
 
while (running) {
	var now = Date.now();
	var delta = now - lastRun;
	lastRun = now;
 
	// insert your game logic here
}

But that won’t work. It is important to understand that javascript is singlethreaded. The whileloop would be the only thing running and that would make it impossible to read keyboard input etc. Instead we have to use either window.setInterval or window.setTimeoout.

setInterval and setTimeout

As opposed to the while loop these two methods won’t cause the browser to hang. It is however important to have an indepth understanding on how they work. After reading these articles you should have “indepth understanding” 🙂

From reading these articles we get these important insights:

  • We should use setTimeout instead of setInterval. Because setInterval will stack the function calls if the game logic takes longer time to execute than the interval.
  • Both setInterval and setTimeout are inexact. We can not be sure that the callback will be executed exactly when we requested.
  • Both setInterval and setTimeout will mess up the “this” variable. We have to remember to handle that somehow.

The core of the idea

This is a minimalistic working example on how we will create our gameloop:

var lastRun = Date.now(); // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now as a number.
var minDelta = 10; // means maximum fps = 100
var loop = function() {
	// Schedule the next run
	window.setTimeout(loop, minDelta);
 
	// Find the delta and set lastRun to now
	var now = Date.now();
	var delta = now - lastRun;
	lastRun = now;
 
	// Then run the game logic
	console.log(delta);
}
loop(); // This will start the gameloop (and you console will be spammed with deltas)

Note that we calculate a delta. This is the time since the last time we ran the gameloop. As setTimout is inexact the delta will probably be a little different each time but this does not matter. We just need our game logic to take the delta into account.

An acknowledgement

This sucks but is true: Date.now() has bad precision. In the best of worlds it would have a resolution of 1ms but in reality the resolution is around 15ms. At least on windows (xp, vista and 7). I have heard the resolution is much better on Linux and Mac though.

The logic above will work anyways. Some times the delta will be larger than the truth and some times smaller. But it seems that in the long run the differences takes out each other.

Read more about Date.now() resolution in these articles if you feel like it:

Usage mockup for our Timeloop class

Lets call the class “Timeloop” instead of “Gameloop”. Because this class could be used for any form of timeloop, not only gameloops. And yeah we are creating a “class” here. I will make use of simple javascript inheritance by John Resig.

This is how I envision the usage of the Timeloop class:

// Lets say we have a "game" object that contains the function we want to run repetedly:
var game = {
	update: function(delta) {
		// Run the game logic here:
		console.log(delta)
	}
};
 
// We add a timeloop instance. The constructor will take a settings object:
game.loop = new Timeloop({
	targetFps: 60, // targetDelta should also be an alternative
	callback: game.update, // We should run game.update
	thisArg: game, // and the scope (this) should be the game object
});
 
// Start the gameloop
game.loop.start();
 
// Stop aka Pause the gameloop
game.loop.stop();
 
// Check if the gameloop is running
game.loop.isRunning(); // returns a boolean
 
// Target delta or fps can be changed later
game.loop.setTargetDelta(10); // 100 fps
game.loop.setTargetFps(100);  // 100 fps
 
// Those should have getters as well
game.loop.getTargetDelta();
game.loop.getTargetFps();
 
// We should also be able to get som benchmarking info
game.loop.getAvgDelta(); // The average of the recent deltas
game.loop.getAvgFps(); // The average of the recent fps
game.loop.getAvgExecTime(); // The average of the recent execution times of the callback.
game.loop.getBenchmarkHtml(); // Returns some html we could put in a div to see all benchmark info.

The result

View the sourcecode on github