Learn HTML5 With This Simple Avoider Game Tutorial
basix

Learn HTML5 With This Simple Avoider Game Tutorial

Tutorial Details
  • Difficulty: Basix
  • Platform: HTML5
  • Language: HTML, CSS, JavaScript
  • Estimated Completion Time: One hour
This entry is part 1 of 3 in the series HTML5 Avoider Game Tutorial

In this tutorial (the first of a series), you’ll learn the basics of HTML5 game development with JavaScript and the canvas element. You don’t need to have any programming experience, or even any HTML experience (apart from this one article). Let’s get started!


Introduction

It would be difficult to have missed the “HTML5 vs Flash” articles that have sprung up all over the web, particularly since Steve Jobs’s Thoughts on Flash last year, and Microsoft’s announcement this week that Windows 8′s web browser won’t support Flash on tablets by default. I’m not going to get into that debate here; whatever your opinion, there’s no harm in learning HTML5. Even if you know Flash, it doesn’t hurt to have another tool in your kit.

This tutorial does not require you know know Flash, or to have had any experience of programming before. In fact, everything that you need to know before you get started is explained in this single article: Get Up to Speed With HTML. That’s it! If you can follow that, you can follow this.

I’m basing this series on my Flash tutorial series, which in turn was based on an even older Flash tutorial by a guy named FrozenHaddock (to whom I am very grateful for letting me use his ideas). This isn’t a direct port of either tutorial, however; I’ll be completely rewriting the code and the explanations to suit HTML5.

A couple of notes:

  • Cross-browser compatibility is a real and important issue in web development, but we’re going to be a little selfish and focus on making sure our game works in exactly one browser: Chrome. Rest assured, we will deal with other browsers (including mobile) in other Activetuts+ tutorials, but for the time being, we’ll stick with Chrome, so that we don’t have to split our focus.
  • Clean code is more important in HTML5 than in a lot of other platforms, because the underlying programming language (JavaScript) will let you get away with a lot. So, we’re going to make sure that you get in the habit of writing decent code… eventually. We’ll be a little messy at the start, just to get things rolling and avoid making you scroll through thousands of words on “best practices” before actually getting to do anything.

In this first part of the tutorial, we’ll just be setting everything up and putting in some very basic game mechanics. Future parts will add multiple spawning enemies, high scores, menu screens, multiple levels, and all that stuff.

Enough talk – let’s get started!


Setting Up

First thing to do is create a .html file. You can use a basic text editor for this, or spend a few hundred dollars on software specifically designed for HTML development; personally, I’d stick with free software for now. Here are three recommendations: TextEdit (for Mac), Notepad++ (for Windows), and Sublime Text 2 (for Windows, OS X, and Linux). Take your pick.

Create a new file, and enter the following:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
	</head>
	<body>
	
	</body>
</html>

If you don’t understand what any of that does, read my basic guide to HTML.

Create a new folder on your hard drive called AvoiderGame, and save this HTML file inside it as game.html. If you load it right now, it’ll just show a blank white page (as you know), so put a paragraph of text in there just to make sure everything’s okay. I’ll add a link to this tutorial, but you could enter anything you like – your name and website, perhaps?

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
	</head>
	<body>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

JavaScript

Okay, now, you will not be surprised to hear that we will soon be writing some JavaScript – remember, JavaScript lets web pages do things, and that’s exactly what we need for making games. We’ll put all our JavaScript in an external file, in order to keep things tidy, and put this file in a separate folder, to keep things tidier still.

So, create a new folder, called js inside your AvoiderGame folder. Then, create a new, empty text file, and save it as main.js inside this new AvoiderGame/js/ folder.

Alter your HTML to refer to this JS file:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
	</head>
	<body>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

Note that I haven’t written src="http://active.tutsplus.com/...whatever.../js/main.js", or src="C:\AvoiderGame\js\main.js"; this way, we’re telling the HTML page, “look for a js folder in the same directory as you, and then use the main.js file that’s inside it.” It’s called a relative path.

If you want to test that this is working, put alert("Working!"); in your JS file, then load the HTML page. If you get a dialog box, everything’s okay.

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
	</head>
	<body>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

CSS

While we’re at it, let’s link an external CSS file as well; we can use it to make the text look nicer, and we might need to use CSS in the game later.

Create a new folder inside AvoiderGame called css, and then create a new, empty text file called style.css inside that. Modify your HTML like so:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

I’m going to modify my CSS file to match some styles we often use on demo pages here at Activetuts+; feel free to copy it, come up with your own, or leave yours blank:

body {
	background: #ffffff;  
	text-align: center; 
	padding: 20px; 
	color: #575757; 
	font: 14px/21px Arial,Helvetica,sans-serif;
}

a {
	color: #B93F14;
}

a:hover {
	text-decoration: none;
}

ol {
	width: 600px; 
	text-align: left; 
	margin: 15px auto
}

This tutorial isn’t about CSS, so if you don’t understand that, don’t worry about it. (If you’re curious, you can look up the meaning of those CSS attributes on W3Schools.com.)

Okay, that’s the dull setup out of the way. You can see how the page looks by clicking here, and you can download the entire source so far in a ZIP file here. Let’s create our avatar!


Get Your Head in the Game

We need an image that will represent our player’s character in this game. Use whatever you like – a photograph of your face, your Twitter avatar, a picture you’ve drawn – but make sure it has a transparent background, that it’s roughly circular, and that it’s about 30x30px.

The original tutorial on which this one is based used a skull. I’m not sure why, but I suspect it was an attempt to subvert games’ typical anti-skeleton stance; after all, under our skin, doesn’t every one of us have a skull?

I’m not one to break with tradition, so I’ll use a skull here too. You can download mine by right-clicking it, if you don’t want to make your own:

Learn HTML5 With This Simple Avoider Game Tutorial

And before you ask: yes, I am available for commission.

Whatever you choose, save it as avatar.png inside a new folder, called img inside AvoiderGame. Your folder structure now looks like this:

/AvoiderGame/
	game.html
	/css/
		style.css
	/js/
		main.js
	/img/
		avatar.png

So how do we get this into our game? If you’ve been paying attention, you’ll probably suggest this:

<img src="img/avatar.png" alt="Avatar" />

And, it’s true, that would put the avatar in our page! But it’s not what we’re going to use.

Canvas

An img element shows a single image, loaded from a PNG or JPG (or whatever) file. The canvas tag, new to HTML5, can generate an image dynamically, made up of other, smaller images, text, primitive shapes, and so much more, if you desire. Its contents can be modified at any point, so you can give the illusion of motion – or of interaction, if you make the contents change according to what the user does.

We create a canvas in the same way that we create any other HTML element:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

…though, if you look at this, you won’t be able to see anything there. It’s invisible, so the only effect it has is to move the text down a little.

With CSS, we can give it an outline so that we can tell it apart from the background. Add this to your CSS:

canvas {
	border: 1px solid black;
}

Check it out. It’s kinda small, though; let’s make it 400px by 300px (old-school TV dimensions):

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

That’s better. Now, I said we could add images to the canvas dynamically, so let’s do that next.

Functions

Remember in the HTML guide I showed you how to make things happen when you clicked HTML elements? Here’s a quick recap:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas onclick="alert('Clicked the canvas');" width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

If you click the canvas, you’ll get a dialog box message. This is because alert() is a JavaScript function: it’s a shortcut to a few lines of code. We can write our own functions in our JS file. Open main.js and enter the following:

function alertSeveralTimes() {
	alert("Hello!");
	alert("Look, we can run several messages in a row.");
	alert("Annoyed yet?");
}

(Delete the original alert("Working!"); if you haven’t already.)

Do you see how this works? We have created a new function called alertSeveralTimes(), whose contents are inside the curly braces ({ and }). When we tell the browser to run this alertSeveralTimes() function, it will run each of the alerts in turn, one after the other.

Let’s try it out:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas onclick="alertSeveralTimes();" width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

Try it! We’ve effectively bundled up several alert() functions into one bigger function called alertSeveralTimes(), and told it to run whenever the canvas is clicked.

You might be wondering why the alert("Working!") ran as soon as we opened the page, but the alertSeveralTimes() didn’t, even though they were both in the same place (at the top of main.js). It’s because of that magic keyword function; when the browser sees this, it doesn’t think, “aha, this is some code I must run immediately!”, it thinks, “aha, this is some code I must bundle up into a new function, which I can run later!”

Anyway. Now let’s make our function do something to the canvas. Making it load an image is a little tricky, so we’ll start with something a bit simpler: changing its size.

Modifying the Canvas

One of the most amazing features of JavaScript is its ability to change the HTML of the page. Check this out; modify your JS file so that it contains this:

function changeCanvasSize() {
	gameCanvas.width = 600;
	gameCanvas.height = 800;
}

You can probably guess what this is doing: it takes the canvas element, and modifies its width and height attributes (we don’t need to use quotes around numbers in JavaScript, unlike in HTML attributes).

Except… how does it know that gameCanvas refers to the canvas that we have in our page?

Well, it doesn’t… yet. We have to make it realise that.

First, we have to give the canvas element an id (short for “identification”) attribute; this is just a name that we use so that we can refer to it in JavaScript later:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas id="gameCanvas" onclick="alertSeveralTimes();" width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

While we’re at it, let’s make the onclick attribute point to our new changeCanvasSize() function:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas id="gameCanvas" onclick="changeCanvasSize();" width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

This still isn’t quite enough. We have to let the JavaScript know that it’s dealing with an element from the HTML page (or ‘HTML document’, as it’s more correctly known):

function changeCanvasSize() {
	document.getElementById("gameCanvas").width = 600;
	document.getElementById("gameCanvas").height = 800;
}

Now, I know, this doesn’t seem entirely logical. Why is gameCanvas suddenly in quotes? Why do we use document.getElementById("gameCanvas") instead of just, say, getDocumentElement("gameCanvas"), or even document.gameCanvas? I promise, this will all become clear during the tutorial series, but for now, just go with it, please.

Test out your new code. The canvas resizes itself as soon as you click on it. Awesome!

Now, I should warn you: programmers are lazy. We hate writing the same code over and over again, and if there’s any way we can reduce the typing required, we’ll take it. So, let me introduce you to a nice shorthand way of referring to the canvas:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	gameCanvas.width = 600;
	gameCanvas.height = 800;
}

See how that works? Just as the function keyword says, “hey, wrap all this code up under the name changeCanvasSize(), please”, the var keyword says, “hey, use the word gameCanvas to refer to the HTML element with an ID of “gameCanvas”, please”. Then (in lines 3 and 4, above), we can use this new shorthand gameCanvas in please of the longer document.getElementById("gameCanvas") – because they refer to the same thing.

That’s important: we haven’t created a new canvas; we’ve just made gameCanvas refer to the existing canvas element.

However, it is possible to use var to create something new…

Click to Skull

Like I said, we’re moving towards adding an image to the (currently empty) canvas. But before we can do that, we have to load the image. And before we can do that, we have to have something to load the image into.

Modify your JS like so:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
}

(I’ve added a blank line to clearly separate the var statements from the rest.)

Here, we’re using the var keyword again – but this time, it says something subtly different: “hey, create a new Image object and use the word avatarImage to refer to it from now on, please.” The Image object is basically like a img element; the crucial difference here is, it’s not in the HTML. We’ve created this brand new element, but it’s nowhere in the HTML; it’s just floating around in the JavaScript aether. I find that a bit weird.

Just like an img element in the page, this Image is pretty much useless without setting its src, so do that next:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
	
	avatarImage.src = "img/avatar.png";
}

(Once again I’m using a blank line to keep bits of code that do different things separated from each other (like paragraphs in text), and once again I’m using a relative path to refer to a file’s location.)

So this is now loading the image, but you’ll have to take my word for it at the moment, since it’s still out there in the aether where we can’t see it. However, we can check its other attributes:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
	
	avatarImage.src = "img/avatar.png";
	alert(avatarImage.width);
}

We’re telling it to show us a dialog box containing the value of the width attribute of our image. Check it on your code and see what you get; I get 29, which is exactly right.

With just one more line of code, we can draw the avatar on the canvas:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, 0, 0);
}

Let’s break this down:

  • gameCanvas.getContext("2d"): We don’t actually draw directly on the canvas, we draw onto what’s called a “drawing context”; this lets us determine whether we want to draw in 2D or 3D. Okay, there’s no 3D context at the moment, but this is letting us plan for the future.
  • drawImage(): Pretty straightforward. This is a function that lets us draw an image onto the context of a canvas.
  • avatarImage: This is the image object we’ve got floating around in the aether, remember?
  • 0, 0: These are the coordinates at which we want to draw the image. In school, you’re taught that (0, 0) is the bottom-left of the page; on a computer, it’s the top-left (the x-axis points to the right, and the y-axis points downwards).

Take a look. It works! (If it doesn’t, remember that you should be viewing this in Chrome; I don’t guarantee that this will work in any other browser.)

Multiple Skulls

The drawImage() function works like a potato stamp:

It just takes the contents of the image object and clones them onto the canvas; of course, we’re dealing with pixels, not paint, but you get the idea.

This means we can add multiple skulls to the canvas, like so:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, 0, 0);
	gameCanvas.getContext("2d").drawImage(avatarImage, 100, 50);
	gameCanvas.getContext("2d").drawImage(avatarImage, 200, 130);
	gameCanvas.getContext("2d").drawImage(avatarImage, 300, 270);
}

Check it out, skull party. We can also make the skull appear in a random place each time:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	gameCanvas.width = 600;
	gameCanvas.height = 800;
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
}

Math.random() give you a random number between 0 and 1, so Math.random() * 100 gives you a random number between 0 and 100; this means that the coordinates of the new skull are anywhere between (0, 0) and (100, 100). Take a look!

But hold on – why is there only one skull at a time now? Is it something to do with it being a new function? Does the canvas get cleared every time you run a function?

No. The canvas is cleared every time you modify its height or width, even if you don’t change either. So, if we change our JS like so:

function changeCanvasSize() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
		
	

	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
}

…then we can keep adding new skulls.

In fact, let’s change the name of the function to drawAvatar(), and tidy things up a bit:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
}

Don’t forget to change the onclick attribute of canvas in your HTML:

<!DOCTYPE html>
<html>
	<head>
		<title>HTML5 Avoider Game</title>
		<script src="js/main.js"></script>
		<link rel="stylesheet" href="css/style.css" />
	</head>
	<body>
		<canvas id="gameCanvas" onclick="drawAvatar();" width="400" height="300"></canvas>
		<p>From <a href="http://active.tutsplus.com/tutorials/html5/learn-html5-with-this-simple-avoider-game-tutorial" rel="external">Learn HTML5 With This Simple Avoider Game Tutorial</a>.</p>
	</body>
</html>

Okay, now let’s get that avatar moving.


Adding Interactivity

I want to make the avatar follow the mouse. We can use the same principle that animators do: if we keep erasing the contents of the canvas, and then re-drawing the avatar at a different position, the avatar will appear to move. So all we have to do is keep redrawing the avatar at the mouse’s coordinates, and we’re set!

How do we do that, though?

A Grand Event

Judging by what we’ve done so far, you might guess that we’d add a onmousemove event attribute to the canvas (which would be triggered every time the user moved their mouse), then make it run drawAvatar(), but specifically at the mouse’s current coordinates. This is inspired, but unfortunately doesn’t really work, simply because it doesn’t offer an easy way to obtain the mouse’s coordinates.

However, it is very close to what we want to do! Take a look at this:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

This does roughly the same thing as the above suggestion; the redrawAvatar() function (which we haven’t written yet) will be called whenever the mouse moves over the canvas. But there’s one big difference.

Notice how we write redrawAvatar, rather than redrawAvatar() in the code above, whereas in our HTML page, we put drawAvatar()with “parentheses” (round brackets) – in the onclick event attribute of our canvas. The full reason for that is a little complicated to go into now (though you’ll understand by the end of the series), but it has one very important upshot: it allows us to obtain the mouse’s coordinates.

When the mouse moves, the browser creates a new object – just like when we created a new Image in our JavaScript earlier. This object has certain attributes that have something to do with the thing that triggered its creation; in this case, because the mouse moved, it contains the coordinates of the mouse. Brilliant!

So how do we access it? Well, this new object (which is called a MouseEvent, for reasons that you might be able to guess) gets passed to the redrawAvatar() function. Er, but we haven’t written that yet, so let’s do that now. Add this code to your JS file:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {

}

Aha – this time, the way we define the function is a little different: we’ve added the word mouseEvent in-between those parentheses. This is because we are expecting the browser to pass a MouseEvent object to our new function, just like when we passed the coordinates to the drawImage() function.

Since we’ve given it a name, we can access the attributes of this new object:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	alert(mouseEvent.x);
}

Test this out; you’ll have to click the canvas before anything will happen, because it’s inside that function that we make the browser start paying attention to mouse movements.

You’ll notice that the dialog box only appears when the mouse moves over the canvas element. You might also notice something odd about the number: it’s too big! I’m getting numbers of over 900, even though the width of the canvas is only 400.

This is because mouseEvent.x gives the mouse’s x-position from the edge of the page, rather than the edge of the canvas. We can use mouseEvent.offsetX to get the mouse’s x-position from the edge of the canvas:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	alert(mouseEvent.offsetX);
}

Much better!

So, to recap: addEventListener() makes the browser listen for certain events – such as the movement of the mouse – and then run a function when this event is “heard”. The browser creates a new object (like a MouseEvent), and passes it to that function.

It’s a little hard to wrap your head around, but don’t worry; we’ll be using it a lot, so you’ll get the hang of it!

Move Your Head

We’ve nearly got movement. In fact, I recommend you have a go at making the avatar follow the mouse on your own before reading further. You’ll probably come very close!

There’s one big thing that’ll trip you up, though: the word var – which, you’ll remember, you can use to set a shorthand – only “lasts” within the function in which it was defined.

This means that if you try to do, say:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	gameCanvas.width = 400;
	alert(mouseEvent.offsetX);
}

…it won’t work, because gameCanvas means nothing outside of drawAvatar()!

So, if you didn’t get it the first time, have another go.

My code is here if you want to check yours:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
}

Tada! Oh, wait, dang, I forgot to erase the canvas by changing its width or height. Cool effect, but let’s try that again:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.width = 400;
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
}

Try it out now. Success!

Wait, What Was That For?

When you take another look at your code in a few days’ time, you’re likely to have forgotten what a lot of it is for. In particular, I suspect you’ll forget why you need to resize the canvas.

Fortunately, there’s a way to remind yourself: comments.

Look at this:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.width = 400;	//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
}

The browser ignores everything on the line after a //. This means you can write whatever you like there, and it won’t be run as code. It’s called an inline comment and is very important. To help get yourself into the habit of commenting your code, go through it now and write comments after each line that you think you might have trouble understanding after a few days’ break.

Commenting may seem like a waste of time. I think a lot of new programmers assume that when they first start out; it only takes one bad experience with trying to update your own, uncommented code (or worse: someone else’s!) to convince you of its worth, though :)

Hide the Mouse

At the moment, you’ve got a big stupid mouse cursor hovering over your avatar:

Learn HTML5 With This Simple Avoider Game Tutorial

We can fix this with a little CSS. Modify your stylesheet like so:

canvas {
	border: 1px solid black;
	cursor: none;
}

In most browsers, this will make your cursor disappear when it’s on top of the canvas… but not in Chrome.

(Update 18/11/2010: Chrome now supports this! I’ll leave the rest of the text here anyway, or things will get very confusing.)

Chrome doesn’t support cursor: none;, but it does allow you to replace the cursor with a PNG file of your choice. So, you can create a PNG that’s completely transparent, put it in your img folder, and use that, like so:

canvas {
	border: 1px solid black;
	cursor: url("../img/transparentcursor.png"), none;
}

(I’ve had to put ../ at the start of the URL because, in CSS, relative paths are relative to the folder of the CSS file, not the HTML file, and “..” says, “the folder above this one”. Also, I’ve put , none after this, because it means that if any browsers don’t support using PNGs for cursors, they’ll use the none attribute instead. Can you see why I wanted to avoid focusing on cross-browser compatibility?)

Unfortunately, this doesn’t work either, because if you use a completely transparent PNG, Chrome just shows a solid black rectangle instead. Thanks, Chrome.

So, instead, I’ve made a 1x1px PNG that’s almost transparent (the single pixel is white, with an opacity of 1%). You can download it here. Copy it to your img folder, then modify your CSS stylesheet:

canvas {
	border: 1px solid black;
	cursor: url("../img/almosttransparent.png"), none;
}

Test it out. It does work, after all that effort.


Make an Enemy

We’ve accomplished a lot so far, but our avoider game still doesn’t have anything to avoid! The last thing we’ll do, in this part of the series, is create an enemy.

We need an image to represent this. Draw whatever you like, but make sure that it’s roughly circular, and about 30x30px. I’m going to take my cue from FrozenHaddock again. He picked a smiley face for his game’s enemy; I’m not sure why, but I suspect it was a comment on the over-pervasiveness of smileys in modern conversation; a yearning for the days of emotions over emoticons, where poets would pour their hearts into a single sentence of text, rather than simply typing semicolon close-parenthesis ell oh ell. Or maybe it’s just because smiley faces are easier to draw. Regardless, here’s mine:

Learn HTML5 With This Simple Avoider Game Tutorial

Call yours enemy.png and put it in the img directory.

You can probably figure out how to draw this enemy (unmoving) on the canvas – if so, give it a shot! Once again, I recommend you do this before reading on.

Here’s my solution:

function drawAvatar() {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);
	
	gameCanvas.addEventListener("mousemove", redrawAvatar);
}

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
}

Your method might be different to mine – that’s okay, as long as it works! But for consistency, please copy my method into your code.

Note that I keep the var statements at the top of their respective functions. This isn’t strictly necessary, but it keeps things tidy, so I recommend it.

Besides that, nothing here should surprise you. There’s no particular significance to the coordinates (250, 150) that I’ve chosen.

Try it out!

Putting the “Avoid” in “Avoider Game”

We’re not going to worry about making the enemy move in this part of the tutorial; that topic deserves more space than I can afford it here. But we will check for a collision between the avatar and the enemy!

First, we’ll do something simpler: we’ll consider a certain area of the screen “off-limits” and pop up a dialog box if the avatar moves into that area.

Modify your redrawAvatar() function like so:

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
	
	if (mouseEvent.offsetX < 100) {
		alert("Too far left!");
	}
}

Try it out. If your avatar goes too far to the left side of the screen, the dialog box appears.

Let’s take a closer look at the code:

if (condition) {
	outcome;
}

The if statement is a way of checking whether something has happened. It’s made up of two parts: a condition, inside the parentheses, and a result, inside the curly braces. If the condition is true, then the outcome is called.

In our case, the condition is mouseEvent.offsetX < 100. The < symbol means "less than", and remember that mouseEvent.offsetX is the cursor's horizontal distance from the left edge of the canvas. So, this is checking whether the cursor is within 100 pixels of the left edge of the canvas. If it is, then...

...the outcome is run. And in our case, the outcome is alert("Too far left!");, the dialog box function we've used a number of times.

Make sense? Okay, good, because I'm going to make it more complicated:

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
	
	if (mouseEvent.offsetX < 100 || mouseEvent.offsetY < 100) {
		alert("Too far left, or too far up!");
	}
}

In this code, we've introduced a new operator: ||. || means (and is pronounced) "or". The if statement therefore reads:

"If the mouse is within 100 pixels of the left edge of the canvas, OR the mouse is within 100 pixels of the top edge of the canvas, show the dialog box."

Try this out, and you'll see that you can't get anywhere near the top or the left of the canvas.

How about this:

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
	
	if (mouseEvent.offsetX > 150 && mouseEvent.offsetX < 250) {
		alert("Stay out of the middle!");
	}
}

The && operator means (and is pronounced) "and", and > means "greater than". So, our if statement now reads:

"If the mouse is more than 150 pixels away from the left edge of the canvas AND the mouse is less than 250 pixels away from the left edge of the canvas, show the dialog box."

Test it out, and you'll see that we effectively have an invisible "stripe" down the middle of the canvas where we can't put our mouse.

We're not restricted to just using two clauses at once; check this out:

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
	
	if (mouseEvent.offsetX > 150 && mouseEvent.offsetX < 250 && mouseEvent.offsetY > 100 && mouseEvent.offsetY < 200) {
		alert("Stay out of the center!");
	}
}

We've now effectively drawn a 100x100px box, in the centre of the canvas, where we can't put our mouse.

Can you see where we're going with this?

Rather than a 100x100px box in the middle of the canvas, we should use a 30x30px box positioned where our enemy is.

This is the last thing we're going to do in this part of the tutorial, so once again I recommend you have a go yourself. It's pretty fiddly - you'll probably want to get some paper out to draw the avatar and the enemy and label some coordinates - but you can do it if you use what you've learned so far.

My solution is below.

function redrawAvatar(mouseEvent) {
	var gameCanvas = document.getElementById("gameCanvas");
	var avatarImage = new Image();
	var enemyImage = new Image();
	
	avatarImage.src = "img/avatar.png";
	enemyImage.src = "img/enemy.png";
	gameCanvas.width = 400;		//this erases the contents of the canvas
	gameCanvas.getContext("2d").drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
	gameCanvas.getContext("2d").drawImage(enemyImage, 250, 150);
	
	//my avatar is 30px wide and the enemy is at x=250, so I have to check whether mouseEvent.offsetX is within 30px
	//either side of x=250 (i.e., from 220 to 280)
	//similarly, since my avatar is 33px tall, I have to check whether mouseEvent.offsetX is within 33px ABOVE y=150
	//but since enemy is only 30px tall, I also check whether mouseEvent.offsetX is within 30px BELOW y=150
	//therefore, I check from (117 to 180)
	if (mouseEvent.offsetX > 220 && mouseEvent.offsetX < 280 && mouseEvent.offsetY > 117 && mouseEvent.offsetY < 180) {
		alert("You hit the enemy!");
	}
}

Try it out here!


Next Time

That's it for the first part of the tutorial. In the next part, we'll get that enemy moving, and we'll add more of them, so that this can start to be a real game!

In the meantime, why not experiment with what you've learned? You could try adding multiple (unmoving) enemies yourself, perhaps with different graphics. Or you could add several avatars on screen at once, all following the mouse in different ways. What happens if you use something like mouseEvent.offsetX + 100 or 300 - mouseEvent.offsetY in your call to gameCanvas.getContext("2d").drawImage()?

I hope you've enjoyed this so far. If anything's not clear, please ask about it in the comments :)

(One other quick note: at the moment, your code should work just fine on your own computer, but won't work if uploaded to the web. My demos work online, because I did a sneaky trick. Don't worry, I'll explain how to solve this in a future part of the tutorial.)


Other parts in this series:HTML5 Avoider Game Tutorial: Multiple Moving Enemies»

  • Joseph

    Can Anyone please explain to me why HTML5 / CSS3 are called “Web Standards” If None of the Browsers have consistent #implementations?

    Our workshop relies a lot on Flex development for specific applications (usually large-scale enterprise) and we are counting on Adobe to provide the Best-Solutions for such use cases.

    “Flash is for the high end projects. HTML5 for all and everyone.”

    And As Long Flash does specific things Better than HTML5, and Cannot do without. Flash is a necessity.

    Flash is at least 8 years ahead in API capabilities, it creates a clear path for HTML.

    You always need a platform that needs to proceed on it’s own. Dosen’t need years for standardization. Always Current. and thats why Flash is a necessity.

    Me seeing a fly in effect, built in HTML5 and the community goes “woooo”… makes me wonder – Really? we built these 10 years ago.

    The internet is relatively new. Lots of unknowns to be part of the internet.

    Creating applications in the browser, is an added advantage, but having full, interactive apps will need latest inputs and APIs part of that new ecosystem.

    Flash today in 2011, is a necessity, and more capable to delivering as much as HTML5 and better in rich use cases.

    • http://www.snorkl.tv Carl

      I agree with Joseph 100%. Flash by it’s long history, massive install-base, and widespread usage is more of a “web standard” than or any specialty CSS3 element. Following the advice of the standards’ committees and browser creators it’s taken what, 15 years to put a drop-shadow on a div? or have control over opacity? And multiple browsers have their own specific way of doing it.

      HTML5 has a lot of promise and I love what it’s doing as far as increasing the beauty of page-layout and adding functional interactive features.

      For the types of immersive, interactive, and dynamic data-driven multimedia experiences that Flash excels in, its going to be a long time before any technology can deliver the same results with such consistant support across broswers / platforms.

      All that aside, thank you for creating this tutorial. As a Flash Developer it is very interesting to see some canvas tutorials that are accessible to a wide audience. I’m a firm believer in using the right tool for the job and appreciate having the resources to dabble in many things.

      Its great to get a glimpse of how things are done on the other side of the fence.

      Best,

      Carl

      • http://michaeljameswilliams.com/ Michael James Williams
        Author

        Cheers Carl! I’m with you; Flash is the standard (if we ignore those pesky iDevices) and it doesn’t look like HTML5 is going to usurp it any time soon. But, like you say, it has promise, and that’s worth looking into.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Oh, I agree; I’m pro-Flash (on the web, anyway). HTML5 is nowhere near ready to replace it in all cases (though I’d say it’s certainly a better tool in a lot of places where Flash used to be the king). Still, it’s interesting to see what HTML5 can do, right?

      • http://www.snorkl.tv carl

        ‘Still, it’s interesting to see what HTML5 can do, right?”

        Yes, definitely. HTML5 can add great features to sites / tools like facebook, twitter, gmail, flickr and heck it does a fine job of replacing Flash for most image galleries. There are plenty of places where it works great and it wouldn’t even make sense to use flash. There are some mind-blowing things happening on that chromeexperiements.com site that make my jaw drop.

        As one commenter has pointed out about the “workflow”… even in this simple example you are using 3 languages. HTML5 is pretty much useless by itself. 99% of the time HTML5 means HTML5 + javascript + css. This is not a criticism of you or your article. I’ve been in web dev long enough to know that just getting a static layout to render consistently in the current browsers is a fine art that I have much respect for… but little patience.

        From one Flash dev to another…

        A lot of my defense and passion for Flash stems from the fact that it is a singular platform / technology that empowers people to bring their artwork to life with very little technical overhead. Flash is a creative powerhouse. Sure it can be abused, but many folks can tackle it pretty easily, create amazing things, and publish them to a format that is widely available.

        It’s just sad that one person in particular has decided that all the 100s of thousands of animations, e-learning materials, visualization tools, interactive comics, video players, games, and generative artworks etc are now somehow “invalid”.

        I just hate to see people discouraged from creating fun and wonderful things because its now the “in thing” to use 3 languages that combined are far more troublesome than ActionScript alone.

        I don’t mean to de-rail your comments or start a Flash v HTML5 war.
        It’s quite clear that was not the intent of your article.

        This was a great tutorial. I know the work that goes into something like this. I encourage you to keep this series going. There is obviously a need for this type of stuff in the community and I look forward to the next one.

        Sincerely,

        Carl

      • http://michaeljameswilliams.com/ Michael James Williams
        Author

        ‘I’ve been in web dev long enough to know that just getting a static layout to render consistently in the current browsers is a fine art that I have much respect for… but little patience.’

        Seconded. I do not envy web designers. I’ll probably stick to canvas (and maybe SVG) for a while ;)

        ‘I just hate to see people discouraged from creating fun and wonderful things because its now the “in thing” to use 3 languages that combined are far more troublesome than ActionScript alone.’

        Yeah, Flash is still king for a lot of things. The problem is with the general public’s perception of it, as you alluded to. It’s hard to predict where things will be in a year or two.

        Conversely, though, I do see people (not yourself) rejecting HTML5/JavaScript because of its status as a Flash competitor, and I think that’s just as sad.

        ‘This was a great tutorial. I know the work that goes into something like this. I encourage you to keep this series going. There is obviously a need for this type of stuff in the community and I look forward to the next one.’

        Thanks so much :)

    • http://kodehurtsmybrain.com Kyle

      Hey Joseph, as another Flash Developer i totally agree with what your saying. Flash is leading the way and always will because its a privatized product whereas HTML5 has the problem of ‘too many cooks in the kitchen’ and this is why its taken the HTML standard (and i used the word ‘standard’ loosely) so long to progress the the point its at now.

      The problem remains however, that flash content is not on iOS and this becomes a major concern for clients. I myself run an online store and 20% of our traffic is from iOS devices, so you can see how important it is that that 20% user base will be able to experience the site the same of the rest of the users. Thus we made the choice to have no flash content on the site. Technologies like jquery etc help deliver some life and animation to the site but overal it just needs to reach the maximum target audience.

      Flash will always be leaps and bounds ahead of delivering interactive content above anything else, and for sites that want an engaging user experience you cant go past flash, but for other sites, especially e-commerce theres no denying that HTML and jquery is the way to go.

      and as Carl stated above its about the right tool for the right job.

      I think HTML5 will just help add a little more “glitter” i think to the more boring and lifeless sites like e-commerce etc

  • Alex

    I can’t get the demo to run in either Chrome or Firefox.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Did you click the box? I should have mentioned that!

  • Yop

    not working :/

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks, but… more info please! What browser are you using? How exactly is it not working? Does anything happen when you click the box?

  • http://www.ama-media.com Ali

    All this .. to do that !! .. what a horrible workflow for such simple stuff .. thanks, i’ll stick with flash for now !

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Please remember this tutorial is aimed at absolute beginners; the equivalent AS3 tutorial took just as long to get to roughly the same concepts. There’s actually very little code you need to write here: a couple of dozen lines, if that.

      When AS3 was new, AS2 developers attacked it for the same sort of reasons. “You have to make classes? You can’t just write onEnterFrame()? What a long-winded workflow!”

      I do not think this is the best way to judge a platform.

    • marcos

      relax, html5+canvas is EZ, its the tutorial that isnt really good, all messy and not straight-forward

  • ste

    There seems to be some negativity in the comments on the recent batch of html tuts posted on this site. I’m just posting to say that I’m looking forward to this series. Please keep them coming Activetuts

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks, much appreciated :) Anything in particular that you want to see?

  • Kevin

    Nice tutorial, I definitely learned more than I thought I would.
    I wanted to take a look at making it work in Firefox.

    http://jsfiddle.net/Pezfish/VKMyT/

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Very nice!

  • http://csso.ru romapad

    Very nice tutorial! Thanks!

  • Mupkoo

    Great job! I enjoyed your tutorial even thou I am not a beginner. Loved your humor too, and I’m not gonna do a smily face…

    Now a couple of things… I really love flash, but I am really keen on all that canvas staff too. All I want to say is that we don’t need any boudaries. We should develop apps the way we want to, the way we love. I am not gonna stop learning new things about AS3, but I will learn new things about HTML5 too

    One last thing – if this was Flash based app, I wouldn’t be able to enjoy this tutorial, because I am reading it on an iPad…

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Cheers Mupkoo :) I’m curious – does the demo run in the iPad browser?

      • http://www.electricmayhemsolutions.net Adrian

        FYI just had a quick play, the demo doesn’t work in Safari on the iPad (not entirely surprising)
        Nor does it work in Opera Mini on the iPad

        You can have fun just randomly adding skulls to the canvas every time you click within the canvas though

  • venkatnarayanb

    Hi Michael,

    Thanks for the tutorial. This could be done in less than 5 mins with AS3 in flash. I don’t understand why people think HTML5 is anyway better than flash, but that being said Adobe needs to work on making flash run well on all mobile devices. Playbook can handle flash just like a desktop computer. Your article is beautifully written and I hope to see more articles on both HTML5 and flash.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      It can be done in less than five minutes with HTML5, too: the tut is just super-decompressed to make it easier for beginners :)

      Unfortunately, it’s not up to Adobe to get Flash running on all mobile devices; they can’t do anything about getting it to run on iOS. I wish it ran better on my Android phone, though.

  • http://www.electricmayhemsolutions.net Adrian

    Nice tut, easy to follow. I look forward to seeing the next installment in this series

    “Out of the box” I got this working in both Chrome and Safari (not surprisingly) though a couple of steps along the way didn’t give me the result I was after, but the end result is perfect! Time to work on my skull and smiley face …

  • Rennan

    Hi Michael, first of all, congrats for the post. I like is so bad.

    But i have a question:

    I clicked at canvas many times and i realized that a ghost of enemy image appears (I know its a delay of drawing method). Can i solve it at HTML5?

    Regards,

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Good question, Rennan! Does it help if you remove the line:

      gameCanvas.getContext("2d").drawImage(avatarImage, Math.random() * 100, Math.random() * 100);

      …? Or is that a different issue?

  • Spirit

    Nice tutorial! I enjoyed most of the parts, my only complain is that it’s totally beginners’ focused lol. I mean, most of the people here on Activetuts are Flash devs and could see a lot of similarities in the JS code with AS3: Image() is a like a Sprite(), mouseEvent and even the addEventListener syntax. In my case, I’m a beginner in HTML5, but not a beginner in coding. So, my question is: is it possible get the cleaner code version that can be done in less than 5 minutes? Perhaps posting it at the end of the tutorial saying something like “This is for you beginner but it could also be done cleaner and shorter this way…”

    Just curious to see if JS can be worked just like a class in AS3. For us, non-beginners in coding, I think it’d be better.

    Anyways, it was a fantastic and sweet written tutorials! And definetively will be expecting the next parts!

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks, Spirit!

      Yes, there are a lot of similarities. However, that’s kind of a gotcha: JavaScript doesn’t reeeaally have classes in the sense that we know from AS3. (That’s an important topic that should perhaps have its own article in the future.)

      I would rather not put two versions of the tutorial on the same page, but maybe once I’ve written a few more parts of this series I could write a condensed version that combines all the parts into one article, for those more familiar with coding – or for those familiar with AS3 who want to know the difference.

  • Bram

    Oh awesome Michael! This brings me back :D

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      :D

  • Mike

    Your code is too bad to use for learn something. Read books.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks for your constructive criticism.

      • Dengke Sha

        Haha yes very “constructive”.

  • Bram

    Tell us Mike, enlighten us here. What’s wrong with it?

  • Dengke

    Hi Mike,

    I just wanted to say great tute even if it’s a bit on the basic side – although it’s definitely helpful to beginners, and I like how you leave out best practices at the start (best practices really used to put me off tutes when I first started doing them). Making the reader playing around with the code a lot (and not just jumping to the final code the first time) is also a great way to learn, so great work with that.

    I did want to point out an inconsistency in your tute though. In the part where you said:

    function changeCanvasSize() {
        gameCanvas.width = 600;
        gameCanvas.height = 800;
    }
    

    will not work, I ran it in Chrome and it did. A new fix by Chrome?

    Also, will we find out how to solve the compatibility issues? And is there a better way of clearing the canvas like gameCanvas.clear()?

    Cheers!

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Hi Dengke, thanks for your comment :)

      I agree; best practices enforced too early are not usually helpful.

      That’s interesting; I don’t think I ever tested that code to make sure it wouldn’t work! I must admit, I didn’t realise that gameCanvas would access the canvas without you having to use getElementById(); I’m not sure whether this is unique to Chrome or whether I’ve just read that getElementById() is necessary so many times that I’ve become convinced that it must be!

      …I just looked into this further (e.g. here, here, and here) and it seems that this didn’t used to work in all browsers (Firefox and Safari, in particular), which is presumably where I picked up the habit. But now it’s part of the HTML5 standard, although evidently this allows for some pretty bad coding habits. Hmm. Not sure whether to alter the tutorial or not.

      Anyway, thanks for bringing this up – I learned something!

      I haven’t decided whether to cover cross-browser compatibility within this tutorial or in a side tutorial, but it will be covered! Although I’m not planning on doing backwards compatibility (sorry, IE6 users) – Activetuts+ is going to be more about the cutting-edge browser technologies.

      About clearing the canvas: in some browsers you must set it to a different width/height and then back to its current on, to be correct; you can also use gameCanvas.getContext("2d").clearRect(0, 0, width, height); but this has potential problems to do with transformation matrices that I don’t want to get into just yet.

  • Niche93

    All hail! The legend is back!

    I read your AS3 tutorial AGES ago it seems, and I have since coded many different things and followed countless other tutorials, and each time I would compare them to your well-written, cheerful, and understandable tutorial, and not once did I find one that was as easy to follow. I loved that thing and it brought me into coding.
    Now I might learn HTML5 just because I want to read and enjoy your tutorial.

    Yes, you just witnessed fanboyism for a tutorial writer. Move along.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Awesome! Thanks so much for your kind words :)

  • Rob Macy

    Thanks for the great TUT!!! I also learned AS3 with your help (using avoider and others). I am anxiously awaiting the next installment!!

    Rob

  • Rennan

    I can´t wait for the next part!!!

  • http://lolcake.com Ibrahim

    Thanks so much for doing this. Very helpful, and you explain things very well to a beginner like me.

  • Elise

    Wow, this is really fun. Okay, honestly a bit too difficult for me, and I may never get it to work. But, your explanations are excellent and I have so much more understanding. Thank you!!

  • http://www.infyways.com/ Mark William

    Nice collections. Really very helpful tutorial for Bigners. Such a important tutorial.
    Thank you for sharing.

  • http://razworks.com Razworks

    Michael, thanks for sharing this. Most complex development starts out as very simple tests, just like your code examples. So the Mike who commented that your code is ‘too bad to use for learn something’ is quite mistaken. And Joseph’s comment that “Flash is a necessity” is also quite mistaken. Flash has basically been depreciated technology for almost 2 years now. Adobe knows it, and that is why they officially announced they are abandoning Flash on mobile and new Internet devices. Therefore, Flash is clearly not a necessity. However, what is resoundingly clear is that HTML5 is the future…at least for the present.

  • http://blog.geminilearning.com David Jumeau

    Thanks for putting up this tutorial. I think it is a very good way for even an experienced Flash Dev to understand HTML5 under the hood. In this way, I can be more clear when using HTML5 and Flash. Good thing you mentioned that we should test under Chrome, I can’t get it to work on Firefox. But alas, I believe that you will be mentioning about cross-browser issues at a later tutorial. I would assume that there are other Javascript libraries that would handle this issue correct?

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks David!

      Oh yeah, there are certainly libraries that make cross-browser stuff easier – heck, maybe even make the JS easier in the first place. I just don’t want to split the focus of this tutorial.

  • http://www.akhbar-tech.com ahmad

    good tutorial , thank you very much , but html 5 without javascript is nothing

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      I think, generally, when people talk about HTML5 they mean “the HTML5 elements, plus JavaScript and some CSS[3] too”.

      • Tom W.

        This is true.

  • Cameron Stout

    Thanks for the tutorial! It is definitely helping me since I am trying to learn coding in HTML5 (Flash is too expensive and it won’t work on my netbook due to the resolution). But I am having issues. I am using Chrome and the game is not working. I have gotten to the part of the tutorial where you added the alertSeveralTimes function. When I clicked on the link to your file, it worked perfectly fine. But when I put it in, the canvas didn’t have a border around it and when I clicked on the canvas, no messages popped up. AND the webpage was not centered. Here is my game.html file (copy and pasted from my notepad).

    HTML5 Avoider Game

    From Learn HTML5 With This Simple Avoider Game Tutorial.

    Here is my style.css file:

    body {
    background: #ffffff;
    text-align: center;
    padding: 20px;
    color:#575757;
    font:14px/21px Arial,Helvetica,sans-serif;
    }

    a {
    color:#B93F14;
    }

    a:hover {
    text-decoration: none;
    }

    ol {
    width: 600px;
    text-align: left;
    margin: 15px auto
    }

    canvas {
    border: 1px solid black;
    }

    And lastly here the text of my main.js file:

    function alertSeveralTimes() {
    alert(“Hello!”);
    alert(“Look, we can run several messages in a row.”);
    alert(“Annoyed yet?”);
    }

    Could you please help me figure out what went wrong? Also, when I downloaded your zip files the first time you put the download on the tutorial, the download would not work on my computer, yet your webpage link DID.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Hey Cameron,

      I’m not sure why this is happening. Unfortunately our comment system has stripped out all your HTML so I can’t see it. Send me an email via this form and I’ll take a look – though it probably won’t be until after the holidays now.

  • Jonas

    Wow… great tut….

    Can’t believe how much code this needs… I’ve been off from mini game dev. for some years – latest I used Flash as2 in wich this could be made from literally 10 lines of code…

    Is this the way to make online cross platform games today?? Im aware that flash is almost dead, but isn’t there another tool like flash that’ll simplify things for a stupid newbie like me??

  • jpb867

    Absolute beginner here. I knew visualbasic and understand the general principles of programming. I find your tutorials to be great. Please keep them coming.

    When I completed the tutorial I tried to add a few things on myself. One think that bothered me was when the cursor was at the extreme right or bottom of the canvas it went out of view. I thought this code would adjust the location of my cursor so it would never go off the canvas but its not working. Again, absolute beginner here… I am sure there is a more efficient way to write this code..

    if (mouseEvent.offsetX > 400 – 30 && mouseEvent.offsetY > 300 – 30) {
    gameCanvas.getContext(“2d”).drawImage(avatarImage, 370, 270);
    else if (mouseEvent.offsetX > 400 – 30) {
    gameCanvas.getContext(“2d”).drawImage(avatarImage, 370, mouseEvent.offsetY);
    else if (mouseEvent.offsetY > 300 – 30) {
    gameCanvas.getContext(“2d”).drawImage(avatarImage, mouseEvent.offsetY, 270);
    else gameCanvas.getContext(“2d”).drawImage(avatarImage, mouseEvent.offsetX, mouseEvent.offsetY);
    }

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Hey JPB, glad you’re enjoying them! Is this the exact code you used? It looks like the logic is right, but you’re missing the closing curly braces before each “else” and “else if”.

  • TomTom

    Okay not bad. I am still looking at html5 from a beginners view but, i have to say, it looks a lot like js and good old html4 or less, or am I missing something? there doesnt seem to be a use for using when i could have used , Will it not do the same thing if I replace the div

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      No; at this very basic level, you’re right, there’s not much different from HTML4 apart from the canvas element.

  • Matt

    Great tutorial for beginners like me :)

    But there is one slight problem I can’t figure out that’s kinda bugging me. Everything was fine until we tried drawing the image on the canvas. It’s supposed to work so you click on the canvas once and it draws the skull in the top-left corner. For some reason, when I run my code (which is exactly the same as it is written in the tutorial) on my computer (using Chrome), I have to click on the canvas twice to make the image appear. But then, strangely, if I refresh the page, it works like it’s supposed to – I only have to click it once and the image appears. I know this is a really small issue, but I’d like to know why this keeps happening. Any ideas?

    • Joe

      I have this same issue. Also curious why it occurs.

      • Jon

        If you look at the page source. The java script file he is actually different then the one he is teaching us too use. I just got the image to appear on the first click because I looked at the java script page source and copied what was done there.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      I think this is due to caching – the browser has to load the skull image before it can draw it, and when you click the first time there’s not enough time for it to do so, so it just fails silently. But when you refresh the page, it already has the skull cached from before, so it can draw it.

      There’s a little more detail about this in either the second or third part of the tutorial. I just skimmed past it in this one and hoped no-one would notice ;)

  • Alan

    Hello!

    Here’s one detail about canvas: If you set width and height on CSS, it stretches the content. To avoid this, use width and height attributes directly on canvas tag.

    About the Flash x HTML5 discussion, I’m a bit lost. I’m a web developer (with xhtml1.0, php, mysql) and I was trying to find something to study/make games. After try a few things, I found your Avoider tutorial using AS3. When I finished, I came here to see how HTML5 works, and it’s promissing… Now I don’t know what to study anymore… =/

    Despite that, thanks for writing these great tutorials.

    Alan.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Thanks for the canvas tip!

      As for which language to pick, it really depends on what you want to do. HTML5 is still a way off being a really strong platform for games, I think; Flash is generally faster, has more relevant libraries, and (perhaps most importantly) has a great gamedev community and support for people trying to make money with their games. There is no HTML5GameLicense.com yet. But if you’re just looking to extend your current skills into game development because you’re interested in it, HTML5 could be a fine choice.

  • Geoff

    Hello

    I have just downloaded the files and couldn’t get the enemy image to appear. Have just realised that it is named Enemy.png but the name is enemy.png in the js file …

    Cheers

    Geoff

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      Hey Geoff,

      Whoops, my mistake. Thanks for letting me know; I’ve fixed the ZIP contents :)

  • Tjardo

    Just one thing: exactly what part here is HTML 5? I see a game solely made in javascript…

    —– Flash vs HTML5 —–
    Even though Steve Jobs made all kinds of claims (some of them completely false, too), the real reason Apple won’t support Flash is because they are too cheap to pay Adobe for getting the rights to use Flash on their devices. That, and their attitude of feeling the greatest and wanting to dominate the market in every way.

    While Steve Jobs said a con of Flash being “it doesn’t support mobile devices”, it’s really certain devices (cough*Apple devices*cough) that don’t support Flash instead. Exactly the other way around.

    I’m absolutely not against HTML5, but it shouldn’t be a replacement of Flash just because Apple wants it like that.

  • Rizza Louise

    This page is all messed up. Why is that.

    • http://michaeljameswilliams.com/ Michael James Williams
      Author

      How so?

      • Anonoymouse

        Needs wordwrap bad

  • Tom W.

    Hey dude! Loved the tutorial. It took it at the right pace, and taught you in such a way that with each bit you did a new thing would happen and you would understand a new concept. I have done lots of programming before but have never gone into HTML5 from a game dev standpoint before. Your tutorial was perfect! And realy showed respect to newbies in the right way, and being 12 is not often I find that people get that right with me. (I am not saying that your tutorial is for kids, we cool). So yeah, thanks a lot! I will be moving onto the next tutorials right now!

    Thanks.