
It’s dangerous to go alone!

Creating Games with HTML5 Canvas Part 3: Controls and Objects
In this part of the tutorial we will add the snake but before we do that we’ll create a object to handle the controls of the game. In the classical snake game you turn the snake clockwise or counterclockwise. We’ll use the left and right key for this.
The first step is to create a key object to keep track of if a certain key is pressed or released. We’ll use the pressedAndReleased method to keep track of if a key is pressed and has been released since last time we checked. If the method is called and the key is pressed we set hasBeenReleased to false, this way we know that the key has been released. We’ll reset this property later in the keyup event handler. The reason is that if we only check if it’s pressed the snake will just rotate in a circle every time the game ticks and a key is pressed. By using the pressedAndReleased method we have to release the key and press it again before we can turn.
// Key object
var Key = function(keyCode) {
// This keys key code
this.keyCode = keyCode;
// Is this key pressed
this.pressed = false;
// Has this key been released
this.hasBeenReleased = true;
// Returns true if this key is pressed and has been released since the method was called last time
this.pressedAndReleased = function() {
var pressedAndReleased = this.pressed && this.hasBeenReleased;
if(this.pressed) {
this.hasBeenReleased = false;
}
return pressedAndReleased;
}
};
Now let’s add a Control object to handle keys and key events. Controls has two key properties: left and right. The init method adds handlers for the keyup and keydown events. The keydown handler sets the current key as pressed and the keyup handler sets the key as not pressed and, as mentioned earlier, sets hasBeenReleased to false. This way we keep track of if the key has been released since we last check if it was pressed. The init method will be called before the game starts to set up the key event handlers.
// Controls object
var Controls = {
// Keys used in the game
keys: {
left: new Key(37),
right: new Key(39)
},
// Init method - sets keydown and keyup handlers
init: function() {
var _this = this;
// Set keys as pressed
document.onkeydown = function(e) {
var keyCode = e.keyCode;
if(keyCode === 37) {
_this.keys.left.pressed = true;
}
if(keyCode === 39) {
_this.keys.right.pressed = true;
}
};
// Set keys as not pressed
document.onkeyup = function(e) {
var keyCode = e.keyCode;
if(keyCode === 37) {
_this.keys.left.pressed = false;
_this.keys.left.hasBeenReleased = true;
}
if(keyCode === 39) {
_this.keys.right.pressed = false;
_this.keys.right.hasBeenReleased = true;
}
};
}
};
It’s time to add the snake to the game. The snake’s body will consist of several objects so the first step is to create a base Object. It has three properties: x and y which represent the objects position and color. Since all objects in the game has the same size we won’t bother with width and height. Object also has four methods: The logic and draw method will be called from the games logic and draw methods, the erase method that fills the objects area with the background color and the collision method that checks if the object has the same location as the supplied x and y values.
// Basic object to represent a rectangle on the screen
var Object = function(x, y, color) {
// x position
this.x = x;
// y position
this.y = y;
// Fill color of the rectangle
this.color = color;
// Logic method - this is where we handle controls and check for collisions
this.logic = function() {};
// Draws object on the canvas
this.draw = function(context) {
context.fillStyle = this.color;
context.fillRect(this.x, this.y, Settings.objSize, Settings.objSize);
};
// Erases object on the canvas and replaces it with the background color
this.erase = function(context) {
context.fillStyle = Settings.backgroundColor;
context.fillRect(this.x, this.y, Settings.objSize, Settings.objSize);
};
// Check if this objects x and y position matches the supplied x and y position
this.collision = function(x, y) {
return this.x === x && this.y === y;
};
};
The Snake object inherits the Object properties and methods and also has a few of it’s own. The direction property keeps track of the snake’s current direction, bodyObjects is an array of all the Objects that represents snake body. When the snake is created we create Objects and add them to the bodyObjects array. The size of the snake is determined by the size variable. We also call the apply method of Object to set up properties inherited from Object (x, y and color).
The Snake object has a method called setDirection which is used to set a new direction depending on the supplied number. The number will be -1 or 1 depending on if we want to turn clockwise or counterclockwise.
We override logic and draw inherited from object. The logic method checks if the left or right key is pressed and released and sets a new direction. The snake’s position is then changed depending on the direction.
The draw method adds a new object at the snake’s position and calls it’s draw method to display it on the screen and then erases the last object of the snake. This way the snake moves forward.
// Snake object
// inherits Object
var Snake = function(x, y, color, size) {
// Possible directions of the snake
var directions = [ 'left', 'up', 'right', 'down' ];
// The current direction
this.direction = 'right';
// The snakes body
this.bodyObjects = [];
// Add the snakes body objects
for(var bodySize = size - 1; bodySize >= 0; bodySize--) {
this.bodyObjects.push(new Object(x - bodySize * Settings.objSize, y, Settings.snakeColor));
}
// Call the base object to initalize inherited settings
Object.apply(this, arguments);
// Sets a new direction depending on the supplied direction and number (-1 or 1 depending on which way to turn)
this.setDirection = function(n) {
// Get index of the current direction
var index = directions.indexOf(this.direction);
// Get the new index
index += n;
// Reset to first or last index if the index is out of bounds of the array
if(index >= directions.length) {
index = 0;
} else if(index < 0) {
index = directions.length - 1;
}
this.direction = directions[index];
};
// Logic method - this is where we handle controls and check for collisions
this.logic = function() {
// Check pressed keys and change direction
if(Controls.keys.left.pressedAndReleased()) {
this.setDirection(-1);
} else if(Controls.keys.right.pressedAndReleased()) {
this.setDirection(1);
}
// Set new position from direction
switch(this.direction) {
case 'left':
this.x -= Settings.objSize;
break;
case 'up':
this.y -= Settings.objSize;
break;
case 'right':
this.x += Settings.objSize;
break;
case 'down':
this.y += Settings.objSize;
break;
};
};
// Overrides draw method - Draw all the snakes body objects on the screen
this.draw = function(context) {
var newObj = new Object(this.x, this.y, Settings.snakeColor), // Get a new object at the snakes current position
objToRemove = this.bodyObjects.shift(); // Remove the last item
// Add the new object to the snakes body
this.bodyObjects.push(newObj);
// Draw the new object on the screen
newObj.draw(context);
// Erase the last object
objToRemove.erase(context);
};
};
// Snake inherits Object
Snake.prototype = new Object;
Now all we need to do is add a few settings and make a few changes to the Game object created in the previous part. In the init method we’ll create the snake.
var Game = {
canvas: null, // Reference to the canvas element
context: null, // Reference to the context
interval: null, // Reference to the main game loop
score: 0, // The current score
snake: null, // Reference to the snake
// Init method to set up the game
init: function(canvasId) {
// Set start position at center of the canvas
var startX = Settings.canvasSize / 2,
startY = Settings.canvasSize / 2;
// Set up canvas
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.canvas.width = Settings.canvasSize;
this.canvas.height = Settings.canvasSize;
// Set up context
this.context.fillStyle = Settings.backgroundColor;
this.context.fillRect(0, 0, Settings.canvasSize, Settings.canvasSize);
// Create the snake
this.snake = new Snake(startX, startY, Settings.snakeColor, 4);
},
// ...
};
In the logic method we call the snake’s logic method and in the draw method we call the snake’s draw method.
// The logic method - this is where we handle controls and check for collisions
logic: function() {
this.snake.logic();
},
// Draws all objects on the canvas
draw: function() {
this.snake.draw(this.context);
},
View demo and final code here.
In the next part we’ll add collision detection and some food for the snake to eat.
Creating Games With HTML5 Canvas Part 2: The Game Loop
In the previous example we used the onkeydown event to animate objects. This works fine in many cases but when you want to be able to control the speed of the game an keep things nice you probably want to create a game loop. Let’s create an object called Game to handle the loop.
var Game = {
canvas: null, // Reference to the canvas element
context: null, // Reference to the context
interval: null, // Reference to the main game loop
score: 0, // The current score
// Init method to set up the game
init: function(canvasId) {
// ...
},
// The logic method - this is where we handle controls and check for collisions
logic: function() {
// ...
},
// Draws all objects on the canvas
draw: function() {
// ...
},
// The main loop
main: function() {
this.logic();
this.draw();
},
// Starts the game by calling the main method with setInterval
start: function(canvasId) {
var _this = this;
_this.init(canvasId);
_this.interval = setInterval(function() { _this.main(); }, 100);
}
};
As you can see the Game object has five methods:
- The init method is where we will do everything we need to do before the game stars.
- The logic method is where we check for collisions and handle movement.
- The draw method will draw all the different objects on the screen.
- The main method is the main loop of the game. It basically calls the logic method to update all objects and then calls draw to display them on the screen.
- The start method is called when we want to start the game. It calls the init metod to set up the game and then calls the main method with an interval of 100 milliseconds. If you take a look at the setInterval method you will see I do a little odd trick there. If I would simply call this.main we would lose our scope and this would no longer be a reference to the Game object but the global window object. By calling _this.main and wrap it in a function we create a closure and we keep the reference to our Game object.
We’ll have a closer look at the init method but before we do that let’s create a Settings object for some of our global settings.
var Settings = {
canvasSize: 400, // Size of the canvas, same for with and height
backgroundColor: 'black', // Background color of the context
};
Then we add some code to the init method to set up the canvas element and fill it with the background color.
init: function(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.canvas.width = Settings.canvasSize;
this.canvas.height = Settings.canvasSize;
this.context.fillStyle = Settings.backgroundColor;
this.context.fillRect(0, 0, Settings.canvasSize, Settings.canvasSize);
}
And finally we call the start method and pass the ID of a canvas element on the page as argument to run the game. A black rectangle should be displayed on the page. Amazing!
Game.start('game-canvas');
View the demo and have a look at the final code here.
In the next part is where the fun starts. We’ll create a Control object and add the snake.
Creating Games With HTML5 Canvas Part 1: Drawing and animating
In this tutorial we will create the classic game Snake with the HTML5 canvas element. This is the first part where I’ll go through the basics of drawing with the canvas element and also how to create simple animations.
The canvas element was added in HTML5 and it can be used for rendering graphic elements on the fly. Start of by adding a canvas element to your page.
<canvas id="game-canvas" width="300" height="300"></canvas>
The canvas element has different contexts that are used for drawing. We will use the 2D context. You can access the context like this:
var canvas = document.getElementById('game-canvas');
var context = canvas.getContext('2d');
Now that we have a context it’s time to draw something on it, let’s make it a simple rectangle. To set the visual style of the rectangle we need to use the fillStyle property of our context and specify a color. You can use several different formats for the color like RGB, hex or just a name. We use the fillRect method to draw the rectangle and pass x position, y position, width and height as arguments.
context.fillStyle = 'red'; context.fillRect(20, 20, 100, 100);
Simple enough, let’s move on to animating. We’ll use the DOM onkeydown event to animate the rectangle when we press the arrow keys. The x and y value are changed depending on which button that is pressed. After the x and y values are changed we have to check that they are inside the canvas area to prevent the rectangle from moving outside of the canvas.
The onkeydown handler will be called over and over again for as long as a button is pressed.
var canvas = document.getElementById('game-canvas'), // Our canvas element
context = canvas.getContext('2d'), // 2D context of the canvas
x = 50, // x position of the rectangle
y = 50, // y position of the rectangle
rectSize = 100, // size of the rectangle
canvasSize = 300, // size of the canvas
speed = 10; // animation speed of the rectangle
document.onkeydown = function(e) {
// switch the pressed keys code to determine which direction to move
switch(e.keyCode) {
// left
case 37:
x -= speed;
break;
// up
case 38:
y -= speed;
break;
// right
case 39:
x += speed;
break;
// down
case 40:
y += speed;
break;
}
// make sure we cannot move outside the canvas area
// left side
if(x < 0) {
x = 0;
}
// right side
if(x + rectSize > canvasSize) {
x = canvasSize - rectSize;
}
// top
if(y < 0) {
y = 0;
}
// bottom
if(y + rectSize > canvasSize) {
y = canvasSize - rectSize;
}
// clear and draw the rectangle
drawRect();
}
We create a method that clears the context by calling the clearRect method and then draws the rectangle. If you want to optimize performance you should clear only the area that is changed (the previous position of the rectangle) but clearing the entire context will do fine in this example.
function drawRect() {
// clear the entire context
context.clearRect(0, 0, canvasSize, canvasSize);
// draw the rectangle at x,y position
context.fillStyle = 'red';
context.fillRect(x, y, rectSize, rectSize);
}
And we are done. View the demo and have a look at the final code here.
If you want to read more about the Canvas element I would recommend Mozilla’s Canvas tutorial.
jQuery.disable() plugin
This is a plugin that is used to disable form elements. Options can be passed to the disable method to determine when the element should be enabled again.
Examples:
// Simple usage
jQuery('#myButton').disable();
// Disable element and set a css class
jQuery('#myButton').disable({ cssClass: 'disabled' });
// Disable element and enable after X seconds
jQuery('#myButton').disable({ enableAfterSeconds: 5 });
// Disable element and enable once an AJAX call is completed
jQuery('#myButton').disable({ enableOnAjaxComplete: true });
// Disable element and enable once an AJAX call is successful
jQuery('#myButton').disable({ enableOnAjaxSuccess: true });
// Disable element and enable once an AJAX call is successful and returns a specific text
jQuery('#myButton').disable({ enableOnAjaxSuccess: true, responseText: 'great success' });
// Disable element and enable once an AJAX call is successful and restrict to a specific URL
jQuery('#myButton').disable({ enableOnAjaxSuccess: true, ajaxUrl: 'http://my.ajax.service/' });
Stockholm Half Marathon 2011
Yesterday I ran the Stockholm Half Marathon. It was the first time I participated in the race and my time goal was 1 hour and 35 minutes.
The weather was really nice, perfect temperature and I felt strong the whole race. I had some cramps in my belly for a while after drinking to fast but I managed to tough it out and finished the race in 1:32:06. And by that I beat my old record by 8 minutes and 30 seconds.
Using HTML data attribute as configuration
Lately when I’ve been working with HTML5 I’ve started to use the data attribute as configuration for JavaScript modules (a Google map for instance). Often you need to pass values from the back end to these modules. If there’s a lot of data you might want to fetch the data from a web service with AJAX but in many cases it will be faster to just render them on the page.
The basics
The data attribute is a custom attribute added in HTML5 where you can store any additional information you need for an element. It’s used like this:
<a data-mydata="Hello world"></a>
Values can then be accessed with JavaScript like this:
var a = document.getElementsByTagName('a')[0];
var myData = a.getAttribute('data-mydata');
// or like this (doesn't work in older browsers)
var myData = a.data.mydata;
jQuery.data() and data attribute
jQuery’s data method now maps against HTML data attributes. You can access data attributes with jQuery like this:
var myData = $('a').data('mydata');
// or like this
var data = $('a').data();
var myData = data.mydata;
Using data attribute as configuration
Let’s say I want to display a google map on my site. But it should display slightly different on each page. I could use the data attribute on the map element to configure the map display like this:
<div class="map" data-showcontrols="true" data-lat="-34.397" data-lng="150.644" data-zoom="7"></div>
And then get the settings with jQuery and display the map:
$('div.map').each(function() {
var data = $(this).data(), // Get the data from this element
options = { // Create map options object
center: new google.maps.LatLng(data.lat, data.lng), // Set center from the specified lat and lng
disableDefaultUI: data.showcontrols || false, // Show or hide default controls
zoom: data.zoom || 10, // Set zoom level from specified zoom or default to 10
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Create and display the map
var map = new google.maps.Map(this, options);
});
CSS3/jQuery Slideshow
I’ve been working on a simple slideshow that uses CSS3 transitions and transformations. You can see a demo of it here (works best in Firefox).
This is what the HTML looks like.
<ul class="album">
<li><img src="http://flickholdr.com/400/280/london" /></li>
<li><img src="http://flickholdr.com/400/280/losangeles" /></li>
<li><img src="http://flickholdr.com/400/280/tokyo" /></li>
<li class="active"><img src="http://flickholdr.com/400/280/newyork" /></li>
</ul>
Here’s the CSS. Each list item is rotated 5 degrees. The active list item is set to 0 degrees. Then we have the “slide” class that uses the translate transformation to move the item 150 pixels down and to the right. I also set the opacity to 0 to fade out the image.
.album {
position: relative;
margin: 0;
padding: 0;
list-style: none;
}
.album li {
margin: 0;
padding: 0;
position: absolute;
z-index: 1;
border: 4px solid #fff;
-ms-transform:rotate(5deg);
-webkit-transform:rotate(5deg);
-moz-transform:rotate(5deg);
z-index: 100;
opacity: 1;
}
.album li.active {
-moz-transition: all 0.5s ease-in;
-webkit-transition: all 0.5s ease-in;
transition: all 0.5s ease-in;
-webkit-transform:rotate(0deg);
-moz-transform:rotate(0deg);
transform:rotate(0deg);
z-index: 200;
}
.album li.slide {
-moz-transition: all 1s ease-in;
-webkit-transition: all 1s ease-in;
transition: all 1s ease-in;
-moz-transform: translate(150px,150px);
-webkit-transform: translate(150px,150px);
transform: translate(150px,150px);
opacity: 0;
z-index: 300;
}
.album li img {
display: block;
}
This is the jQuery code which basically adds the class “slide” to the clicked item and the class “active” to the next item.
$(function() {
$('ul.album li.active').live('click', function() {
/* There's a reason i call the prev item "next" and last "first".
I'm doing everything backwards since the last item has the highest z-index */
var $this = $(this), // the clicked item
$next = $this.prev('li'), // the next item
$firstItem = $this.siblings().last(); // the first item
// Reset if we are at the last item
if(!$next.length) {
$next = $firstItem;
}
// Throw away the clicked item
$this.addClass('slide').removeClass('active');
// Display the next item
$next.addClass('active');
// Reset the clicked item after 1 second
setTimeout(function() { $this.removeClass('slide'); }, 1000);
});
});
Flipping images with HTML canvas
I’ve put together a demo of how you can flip images with the HTML5 canvas element over at jsFiddle.
The basic idea is to set the scale of the canvas to -1 in the direction we want to flip the image. This will draw the image inverted but the image will be outside of the visible canvas area. So we need to set the position of the image to -100% of the image width or height, depending on which direction we want to flip it.
This is the basic function that rotates the image horizontally and vertically.
function flipImage(image, ctx, flipH, flipV) {
var scaleH = flipH ? -1 : 1, // Set horizontal scale to -1 if flip horizontal
scaleV = flipV ? -1 : 1, // Set verical scale to -1 if flip vertical
posX = flipH ? width * -1 : 0, // Set x position to -100% if flip horizontal
posY = flipV ? height * -1 : 0; // Set y position to -100% if flip vertical
ctx.save(); // Save the current state
ctx.scale(scaleH, scaleV); // Set scale to flip the image
ctx.drawImage(img, posX, posY, width, height); // draw the image
ctx.restore(); // Restore the last saved state
};