Fork me on GitHub

Power in the Scene

Now that we have a working game engine with entities it is time we start to build a little more management into the game engine. In this tutorial we will be adding a scene manager into the game engine so that we can swap scenes out quickly without having to do a lot of work. Before we do this you may be wondering why would I want to change the game engine design since we have a really good working game engine? The answer for this is more of an example. Making a game is more than providing a fun game to your players but a way to either show off their high score, connect with other players, start a new game, maybe even continue an existing game. The list is endless and in a way we will use scenes to manage the different options a player may wish to choose to do in our game. This is kind of leading into building a game menu.

Before we start we need to define what the scene will take over from the game engine and how it will manage all these requirements.

  • Manage entities which will require adding and removing entities.
  • Manage the draw process for all game entities
  • Manage the update process for all game entities

This should be a good start to the scene class and as we find more needs we will can come back and make those modifications. Start by opening a command prompt and running the grunt watch command. Once grunt is up and running we can now start working on our game engine again. Open your favorite JavaScript code editor, for me it is Visual Studio. Create a new file under src/js/core and call it scene.js. Here is the base code for the scene class:

function Scene(cfg) {
	var me = this;

	me.init = function (cfg) {
		Object.assign(me, cfg);
	};

	if (cfg !== undefined) {
		me.init(cfg);
	}
}

This is a fairly straight forward definition of the scene class. Now we will want to move all the entity tools from the game engine into the scene class. This was when we add entities to the game engine it will add them to the current scene.

We need to setup the game engine to now support a scene system. To do this we will need to add some tools to the game engine to manage the scene system. We will start by adding a scene variable to the engine class. There are a couple of different methods we could use to manage our scenes.

One approach would be to create a stack so we push a scene onto the stack and always ass the newest scene. This makes it easy to change between states and then return to old states without having a lot of developer programming. This will be an approach we will upgrade to later.

The other approach which is way easier to implement in the game engine is to just have one scene and make the developers manage the scene states. Open the engine.js file and add this one variable definition to the engine class:

	///// Define all ening values that are not settable 
	me._isRunning = false;
	me._entityList = [];
	me._entNextId = 0;
	// Current game scene
	me._scene = null;

The lines in bold are new lines and the other were provided so you know where to put the _scene variable. For now we just set the _scene value to null because later when we add the scene management code we will do some engine magic. The first function we are going to modify is the add function. Right now the add function is adding any entity to the _entity list but since we deleted those lines we will want to add our entity to the current scene. Here is the modified add function code:

	me.add = function (ent) {
		me.getScene().add(ent);
	};

This really reduced the add function. But before you do this to your code make sure to copy and save the add function because we will reuse it in the scene file. This one line calls a game engine function which we haven’t created just yet called getScene. This function main use is to manage the scene system and return a valid scene to our developers. We could have written this same line of as me._scene.add(ent) but this will limit us from checking for a valid scene so we don’t use direct access to our scene object and instead abstract it to a function. Here is the code for the accessor method to get our current scene:

	me.getScene = function () {
		if (me._scene == null) {
			me._scene = new Scene({ parent: me });
		}

		return me._scene;
	};

In this function we check to see if we have a valid scene. If there isn’t one we go ahead and create one. Then after that is all done we just return the current scene object. Now back to the previous code segment and the add part of the scene object. This function doesn’t exists just yet so we will need to go back to the scene.js file and add a few variables and the add function. Here is the update code:

function Scene(cfg) {
	var me = this;

	me._entityList = [];
	me._nextId = 0;
	me._MAXID = 2000000; // Max entity id in scene

	me.init = function (cfg) {
		Object.assign(me, cfg);
	};

	me.add = function (ent) {
		// Make sure we have a valid entity
		if (ent !== undefined && ent !== null) {
			ent.id = me._nextId;
			me._nextId = (me._nextId + 1) % me._MAXID;
			ent.parent = me;
			if (me._entityList.push !== undefined) {
				me._entityList.push(ent);
			} else {
				// Going to add the entity to our list the old fashion way
				me._entityList[me._entityList.length + 1] = ent;
				console.log('Entity added the old fashion way');
			}
		}
	};

	if (cfg !== undefined) {
		me.init(cfg);
	}
}

So the bold code is all the new code in the class. The first couple of variables are just data structures we will use to maintain our entities in the system. I added a new variable call MAXID so that we can allow developers to change the max identifier for an entity if they go beyond 2 million entities. The add function shouldn’t be to new, we have use the code from the old add entity in the game engine class. The difference in this code block is now we use a few new variable names and the MAXID is used for the increment instead of it being hard coded.

Our engine can properly add entities to a scene but that is about it. If we fire up the previous tutorial html file it would run but nothing would happen. This is because the draw and update functions still are looking at the _entityList locally and not the scene. We can easily change this by adding an update and draw function to the scene class and then referencing them in the game engines draw and update functions. So add these two functions to the scene class:

me.draw = function (ctx) {
		if (me._entityList.length > 0) {
			for (var i = 0; i < me._entityList.length; ++i) {
				me._entityList[i].engineDraw(ctx);
			}
		}
	}

	me.update = function (deltaTime) {
		if (me._entityList.length > 0) {
			for (var i = 0; i < me._entityList.length; ++i) {
				me._entityList[i].engineUpdate(1.0);
			}
		}
	};

Next go back to the game engine and modify the draw and update function to look like this:

	me.draw = function () {
		if (me.getScene() !== null) {
			me.ctx.clearRect(0, 0, me.world.canvasSize.x, me.world.canvasSize.y);
			me.getScene().draw(me.ctx);
		}
	};

	me.update = function () {
		if (me.getScene() !== null) {
			me.getScene().update(1.0);
		}
	};

In both the draw and update function we want to make sure there is a valid scene before we try and process the scenes. Now that these two methods have been updated we should be able to run our HTML file and see the game engine start animating our box.

The last change we need to make before we can call this done is changing the remove function in the game engine and adding a remove function to the scene file. Since we are already in the scene file we will have the remove function so that it will now call the current scene to remove the entity.

	// Remove entity from scene
	me.rm = function (id) {
		var ent = null;
		if (me.getScene() !== null) {
			ent = me.getScene().rm(id);
		}
		return ent;
	};

Keep the old code because we will be reusing it in the scene class. The old remove function would return the entity object that was found or null if it wasn’t. So we create the ent variable and set it to null which will be the default value. Next we test for a valid scene before trying to call the remove function. If the remove function is successful from the scene it passes the entity back and stores it in our local entity variable.

Now we will need to add a new rm function in the entity class so open the entity.js file and add these lines of code:

	me.rm = function (id) {
		var ent = null;
		// Check if the id is valid
		if (id !== undefined && id !== null) {
			// Brute force our way through the list
			for (var i = 0; i < me._entityList.length; ++i) {
				if (me._entityList[i].id === i) {
					ent = me._entityList.splice(i, 1);
				}
			}
		}

		return ent;
	};

And there we have it the engine is now setup to use a scene object. This will help us build the many different parts of a game that isn’t really part of the game but is needed to give players ways to manage their game experience.

Enhancing the Scene with a Stack

One enhancement we are going to do is originally we talked about the two different ways to use the scene variable in the game engine. The first method I talked about was complicated but we have time in this tutorial so we will make a few simple modifications to help preserve and manage our game states.

First before we jump into any code we need to understand how a stack works. Stack data structures works like a pile of books. The last item put onto a stack of books will be the first book you have to take off the stack before you can get to any other book. We call this a last in first out data structure or LIFO. This particular data structure is a great to use as a game state management tool and as we develop games it will become very handy to have in our tool box.

If you have look into JavaScript it doesn’t have a specific data structure called a stack. Why is that? The Array data object is very flexible and honestly this is the only data structure we need. It already has the tools we need to manage a stack built in. The biggest tool we will use is the push and pop array methods. This does mean we need to make sure our browsers are semi up to date using at least the em5 script engine.

In order for the engine to be able to manage a scene stack we will need to change a few variables and functions. The _scene variable will change from being a null value to being a blank array. Since we don’t have a lot of different data objects we will use the good old trusty array. Next we will need to modify the getScene and addScene functions to support a stack based approach. After that we will need a way to remove the current scene object from the engine so we will add a popScene function. Oddly enough the pop part of the function is referring to the pop function we will use in the array to remove the last element in the array.

Now with all that explained here is the first line of code we will change:

	// Current game scene
	me._scene = [];

This is probably the simplest change to the game engine which is converting the _scene variable to be an empty array. Scroll down till you find the getScene function definition and here are the changes we will make to this function:

	me.getScene = function () {
		if (me._scene.length === 0) {
			me.addScene(new Scene());
		}

		return me._scene[me._scene.length - 1];
	};

The code in bold show the changes made to this function. I removed the direct connection to the _scene variable so now the only thing adding scenes to the data structure is the addScene function. I like to do this so that we have one place that manages the adding scenes to the game engine. After that we had to make a change to how we return the current scene. Since we are treating the _scene variable as a stack we want to return the last element in the array.

So far not so bad. A lot of this was done with the ground work we had previously started which makes adding more complicated features easier to handle. Now we need to update the addScene function:

	// Add a new scene and return the existing one
	me.addScene = function (scene) {
		var old = me._scene[me._scene.length - 1];
		scene.init({ parent: me });
		me._scene.push(scene);
		return old;
	};

To maintain the functionality of the add function we needed to make sure the current scene is returned which is why we take the last element of the array and store it in the “old” variable. The next new line in bold is how we add the new scene to the stack using the array function push. Again this was an easy change.

The last part of the change we need to do is add a popScene function.

// Remove top scene from stack
	me.popScene = function () {
		if (me._scene.length > 0) {
			return me._scene.pop();
		}
	};

This function should look fairly straight forward in that all we are doing is checking to make sure there is something to remove from the array and returning that for the developer to use later. If not nothing will happen.

With all this change to the game engine it doesn’t seem like anything has changed. This is the point of this tutorial. With these major changes they will enhance future projects but not break our current project. There are times that we can make changes like this and most users will never see a difference. But then there are times the current system will not be able to manage a new feature so we will have to break the compatibility.

Let’s see what all this hard work can do for us. For this example we will scene how we can use the scene objects to create two scenes and then use the mouse click to flip between our scenes. Add this code to your html file between the script tags:

window.onload = start;
		var backScene;
		var game;
		function start() {
			game = new GEngine({
				world:{
					canvasSize: { x: 400, y: 300 },
					fullWindow: true
				},
				canvasId: 'theEngine',
				fps: 60
			});
			var scene = new Scene();
			var box = new EntityRect({
				color: '#ff0000',
				translate: {
					position: {x: 300, y: 150}
				},
				drawPivotPt: true
			});
			box.pivot.x = 0;
			box.update = function (dt) {
				var newRot = (this.translate().rotation() + 0.5) % 360;
				this.translate().rotation(newRot);
			};

			scene.add(box);

			// Add current scene to game engine
			game.addScene(scene);

			scene = new Scene();
			box = new EntityRect({
				color: '#0000ff',
				translate: {
					position: { x: 300, y: 150 }
				},
				drawPivotPt: true
			});
			box.update = function (dt) {
				var newRot = (this.translate().rotation() + 0.5) % 360;
				this.translate().rotation(newRot);
			};
			scene.add(box);
			backScene = scene;

			game.run();
		}

		function swapScene() {
			var scene = backScene;
			backScene = game.popScene();
			game.addScene(scene);
		}
		window.onclick = function(e){
			e.preventDefault();
			swapScene();
		};

There is a lot of new code. If you think I forgot to update the second box your kind of right. I didn’t highlight this code since it was mostly a copy of the previous section of code with the only real differences is the pivot point and the box color.

The first section of new code is the definition of the game variable and the backScene. We will need access to the game engine so I decided a global definition would make my life easier. Please don’t do something like this in a production game it will only cause you headaches. The other variable will be a storage for the inactive scene.

Now we will define our own scene instead of letting the game engine create it. Because of the way we change the game engine and also mimicked those methods in the Scene class we can swap out any place we add an object to the game engine with directly adding it to the scene object. Make changing this code a snap! After we are all done making the scene we now define a second scene and add in a second box the scene the second scene. When we are done with the second scene instead of adding it to the game engine we stick in the backScene global variable.

Unfortunately this doesn’t show off the magic in the scene stack but you should get the idea of how this works. On your own try and change the code so that instead of swapping the scene you take advantage of the stack and just add and remove the second scene.

Another great exercise is to change it from waiting for a click to automatically change the scene every 5 seconds. Try it out and let me know what you do to make it work.