Thursday, 19 May 2011

Game Loop for a HTML5 Game

In my last post, I showed you how to simply display an image on the canvas. But before going onto anything else, I'll show how to include a standard game loop. I'm using HTML5 games as example here, but the concept of the loop applies to most other kinds of game development.

So obviously you'd first put the canvas in the HTML, like so:
<canvas id="canvas" width="400" height="100" style="background-color: #A9A9A9;">
Browser not compatible with HTML5 canvas
</canvas>


A game loop is the normal structure a game would be built with.
First it would initiate the loop, then the loop would involve checking for user input, then all objects would be updated as required, then rendering/drawing the scene based on the object and variable values, and start again from checking user input.


This is an example of doing this in javascript:
const FPS = 30;

var playerPosX = 0;
var playerPosY = 0;

var playerImg = new Image();
playerImg.src = "http://i.imgur.com/nEYjaIe.png";

var canvas = null;
var context2D = null;
var keys = new Array();

window.addEventListener('keydown',keyDown,true);
window.addEventListener('keyup',keyUp,true);
function keyDown(evt){
 keys[evt.keyCode] = true;
}
function keyUp(evt){
 keys[evt.keyCode] = false;
}

window.onload = init;

function init()
{
 canvas = document.getElementById('canvas');
 context2D = canvas.getContext('2d');
 setInterval(runGameLoop, 1000 / FPS);
}

function runGameLoop()
{
 handleInput();
 update();
 draw();
}

function handleInput()
{
 if ((37 in keys && keys[37]) || (65 in keys && keys[65])){ //left
  playerPosX -= 2;
 }
 if ((39 in keys && keys[39]) || (68 in keys && keys[68])){ //right
  playerPosX += 2;
 }
}

function update()
{
 // Not used in this example
 // In a game with physics and logic, this is used for calculations, etc.
 // For example, in handleInput(), it could have been updating Velocity
 // rather than Position, so in this function you would update the
 // Position based on the current Velocity values
 // e.g:
 // playerPosX = playerPosX + playerVelX;
 // playerPosY = playerPosY + playerVelY;
 //
 // We will get to this kind of thing in the Simple Game Physics Article
}

function draw()
{
 context2D.clearRect(0, 0, canvas.width, canvas.height);
 context2D.drawImage(playerImg, playerPosX, playerPosY);
}


You will firstly declare all global variables, then add "event listeners" for input. For the sake of organization, I put a couple of functions right there to handle keypresses, which are called by the event listeners. These functions are called on keyDown and keyUp events, this means it will set relevant elements of an array to "true" or "false" depending on the key states, meaning we can later use this array to tell whether a key is pressed or not.

Then you'll see that when the window has been loaded, it will call the init function. Here is where we will initialize the canvas and the 2D context. Then the main point of this tutorial, it will call the runGameLoop() function 30 times a second.

In the runGameLoop() function, it will simply call 3 functions, which are the parts that will make the game actually run.

The handleInput() function checks the keys array, looking for what keys are currently pressed. If there are keys pressed that we can use (in this case, left and/or right), it will update the relevant variables. (In a more complicated script, we would usually have another function or other functions for things like movement, etc.

Then there is a call to the update() function, however it is not used in this example. In a more complicated example, all logic and calculations are handled in the update function.

Then draw() is called, which basically renders everything to the canvas, using the variables which have been manipulated through input and the logic done through update. This function is where everything in the current loop actually becomes "reality" in the canvas.

Then of course everything is repeated. But remember those 3 functions are called 30 times every second. This is why games are so responsive from input.


And it's as simple as that. With that knowledge, you can make a simple game. Here's the result of the example I just gave (use arrow keys or A and D to move left and right):
Browser not compatible with HTML5 canvas