HTML5 Canvas Game: Panning a Background

A starry background in space used for scrolling

As promised some time ago, I finally finished the Galaxian Style HTML5 game and am now ready to write a five part tutorial series about it. The game will be written completely from scratch without any external libraries so that you can see what it takes to make a game work on the canvas. So without further ado, let the tutorials begin!

Difficulty: Medium
Languages: HTML5, JavaScript
Code: https://github.com/straker/galaxian-canvas-game/tree/master/part1

To start off this tutorial series, let me show you the final product below. It starts right away, so just hit the “Restart” button to restart play. Make sure you click inside game if the controls aren’t working (as an added bonus, see how long you can last and post your high scores below 🙂 ).

Controls: Move – Arrow keys (↓→)
Shoot – Spacebar

As you can probably tell there is some room for improvement, but we’ll cover that in part five. The key points to take away from the final product is that the game runs around 60FPS and that it runs pretty smoothly.

Now that you know what we are going to make, lets get into the tutorial.

The first step to creating our HTML5 game is understanding where it’s problems lie. We’ll start by defining a few things about the canvas and how it works so that we get the best results possible.

The first thing to note is that drawing anything on the canvas is an expensive operation. Because of this, we’ll need to reduce the amount of drawing we do for the game to ensure the best performance. There are a lot of ways we can do this, but we’ll only focus on a few of them.

For this tutorial, we’ll use the technique of multiple canvases to draw out all our game pieces. You’ll want to do this because multiple canvas elements give a significant performance boost. So we’ll be layering three canvases, one on top of the other, to create the illusion of a single game. I’ll explain why we’ll be using three canvases in later tutorials. But for now, we’ll just be using one to pan the background.

The other thing to note about HTML5 games is that poorly coded JavaScript can cause lots of problems. Poor code quality is normally bad, but it’s especially bad on the web. Thus we’ll be using a few advanced game structures and coding techniques so that our code  is well written and as quick as we can get it.

With that in mind, we can begin coding. For this tutorial, we’ll focus on getting the webpage set up and getting the starry background to pan across the screen.

We’ll first start out with the webpage.

<!DOCTYPE html>
<html>
<head>
<title>Space Shooter Demo</title>
<style>
canvas {
position: absolute;
top: 0px;
left: 0px;
background: transparent;
}
</style>
</head>
<body onload="init()">
<!-- The canvas for the panning background -->
<canvas id="background" width="600" height="360">
Your browser does not support canvas. Please try again with a different browser.
</canvas>
<script src="space_shooter_part_one.js"></script>
</body>
</html>

As you can see, it’s pretty simple. We create a canvas element and include some text inside it in case the canvas isn’t supported in a browser. All canvases will also be stacked on top of each other with the style created. Lastly, we load the JavaScript resource.

Next, we’ll write the JavaScript code. To start out we’ll create an object to hold all our images in the game. This is a great idea as you can then use one image as many times as you need without having to recreate a new image object each time.

/**
* Define an object to hold all our images for the game so images
* are only ever created once. This type of object is known as a
* singleton.
*/
var imageRepository = new function() {
// Define images
this.background = new Image();

// Set images src
this.background.src = "imgs/bg.png";
}

Since we’re only focusing on panning the background, we create only the background image and set it’s src attribute. Now we can reference the image repository object for any images we need.

The next object we’ll create is the Drawable object.

/**
* Creates the Drawable object which will be the base class for
* all drawable objects in the game. Sets up default variables
* that all child objects will inherit, as well as the default
* functions.
*/
function Drawable() {
this.init = function(x, y) {
// Default variables
this.x = x;
this.y = y;
}

this.speed = 0;
this.canvasWidth = 0;
this.canvasHeight = 0;

// Define abstract function to be implemented in child objects
this.draw = function() {
};
}

The Drawable object is a special object that all other objects of our game will inherit from. In programming terms it’s called an abstract object. An abstract object allows us to have one object that defines all the variables and functions that we need to use it, then give those same variables and functions to all objects that inherit from it so that we don’t have to duplicate any code. Plus, if we ever have to make changes to how an object should function, we only have to change it in the Drawable object and not every single object in our game.

The Drawable object has a method called init which allows us to set the x and y position of the object when it is created. It also defines the speed of the object (or how many pixels the object can move each frame), and the width and height of the object’s containing canvas. The last method, draw, does not necessarily need to be defined since it’s empty, but I like to do it anyway to remind me that this object is abstract and that I shouldn’t create an object from it.

Now that we have a base object, it’s time to create the background object that will handle panning an image.

/**
* Creates the Background object which will become a child of
* the Drawable object. The background is drawn on the "background"
* canvas and creates the illusion of moving by panning the image.
*/
function Background() {
this.speed = 1; // Redefine speed of the background for panning

// Implement abstract function
this.draw = function() {
// Pan background
this.y += this.speed;
this.context.drawImage(imageRepository.background, this.x, this.y);

// Draw another image at the top edge of the first image
this.context.drawImage(imageRepository.background, this.x, this.y - this.canvasHeight);

// If the image scrolled off the screen, reset
if (this.y >= this.canvasHeight)
this.y = 0;
};
}
// Set Background to inherit properties from Drawable
Background.prototype = new Drawable();

The Background object sets the speed of the panning background to 1 pixel per frame, then defines the draw method. In the draw method, we update the y position of the object (since our background is panning from top to bottom) then draw it to the canvas. We also redraw the same image above itself to give the illusion of an infinite scrolling background. Lastly, the method checks to see if the y position of the image has gone off the screen and will reset it if it has to continue the panning.

To set up the Background object to inherit from the Drawable object, we use the prototype functionality. Prototype is a bit confusing at first, but it isn’t too hard to get. Basically we’re telling the Background object to copy all the information from the Drawable object. This is how we can do inheritance in JavaScript.

As a side note, this article talks about how to mimic Object Oriented Programming in JavaScript.

With the basic structure of the game complete, it’s time to create the final object that will handle the entire game.

/**
* Creates the Game object which will hold all objects and data for
* the game.
*/
function Game() {
/*
* Gets canvas information and context and sets up all game
* objects.
* Returns true if the canvas is supported and false if it
* is not. This is to stop the animation script from constantly
* running on older browsers.
*/
this.init = function() {
// Get the canvas element
this.bgCanvas = document.getElementById('background');

// Test to see if canvas is supported
if (this.bgCanvas.getContext) {
this.bgContext = this.bgCanvas.getContext('2d');

// Initialize objects to contain their context and canvas
// information
Background.prototype.context = this.bgContext;
Background.prototype.canvasWidth = this.bgCanvas.width;
Background.prototype.canvasHeight = this.bgCanvas.height;

// Initialize the background object
this.background = new Background();
this.background.init(0,0); // Set draw point to 0,0
return true;
} else {
return false;
}
};

// Start the animation loop
this.start = function() {
animate();
};
}

The Game object has only two methods. The init function first grabs all the canvas elements from the webpage. It then checks to see if the canvas is supported by looking at the canvas.getContext function. The function returns true if the current browser supports the canvas and returns false if it does not.

If the canvas is supported, the Game will set information about the canvas to the Background object. This way, the background object knows which canvas to use and it’s dimensions. Next, it creates a background object and gives it it’s starting position. Lastly, the Game returns true signifying that the canvas is indeed supported and that the Game can continue.

The start method just starts the animation loop and is called after the init function returns true. If the canvas is not supported on older browsers, this method is never called so that unneeded system resources aren’t used on a function that can’t do anything.

With the Game object finished, the only thing left to do is create the animation loop.

/**
* The animation loop. Calls the requestAnimationFrame shim to
* optimize the game loop and draws all game objects. This
* function must be a gobal function and cannot be within an
* object.
*/
function animate() {
requestAnimFrame( animate );
game.background.draw();
}

/**
* requestAnim shim layer by Paul Irish
* Finds the first API that works to optimize the animation loop,
* otherwise defaults to setTimeout().
*/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame   ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();

The animate function is the game loop and all it does is draw the background object. To animate the game, the animate function calls the requestAnimFrame shim created by Paul Irish. A game loop shouldn’t be created using the window.setTimeout as it isn’t optimized for 60FPS. Modern browsers have created their own highly optimized game loop functions, and this shim finds the first one that works and uses it. It will default to window.setTimeout if nothing else works.

The final piece of code is to create the game object and run it.

/**
* Initialize the Game and starts it.
*/
var game = new Game();

function init() {
if(game.init())
game.start();
}

And that’s it! You should now have a panning starry background on the canvas.

The HTML5 canvas has great potential for gaming. To create a canvas game, we must first understand the weaknesses of the canvas and browsers so that we can plan our game accordingly. Once our game is planned out, we can begin to create the structure of the game using what we have learned and ensure that our code is written to avoid these pitfalls.

This tutorial created the basic structure that the rest of the game will utilize and allowed us to pan a background across the canvas.