In my last blog, I had posted the game of Snake that I developed as my first attempt in HTML5 programming and all I can say is... it was fun!
In this tutorial, I will show you how to use the basic features of HTML5 and get the simple game of Snake up and ready within a couple of hours, even if you are a beginner. All you require is some basic logic and any experience with programming is a huge plus. However, I must also admit here that this is more of a JavaScript work than HTML5, as it just uses the canvas and a couple more elements.
Okay, so let's begin!
First things first - Create a HTML file. Open your favorite editor, copy the snippet below and save it with a name as per your liking. I'll stick with "index.html".There is no different file extension for a HTML5 document. It simply uses one subtle and welcoming change in the "DOCTYPE" declaration (welcoming as its easy to remember compared to that from HTML4) and the browser will understand that it is HTML5.
Code Snippet
<!DOCTYPEHTML>
<html>
<head>
</head>
<body>
<divid="wrapper">
<h1>Snake</h1>
<divid="score">Score:0 Level:1</div>
<canvaswidth="300"height="400"id="canvas">
</canvas>
<divid="control">Controls: W = Up; A = Left; S = Down; D = Right</div>
</div>
</body>
</html>
Lets now look at what we have written here:
<!Doctype HTML> -As I mentioned above,a very simple and neat way to tell your HTML5 enabled browser that it will be accessing a HTML5 document. Then there is a regular <head> tag followed by the <body> tag
In the body of the page, we first define a div named "wrapper" which essentially will include everything that we are about to display. Note that this is not required in our example. Then we create a div to display the game score and the level. As you'll find out later, we will also use this to inform the player if the game is over.
Then comes the main component, "Canvas", the most essential HTML5 component for that can be used for rendering graphs, game graphics, or other visual images on the fly. HTML5 defines a set of functions for drawing various shapes, creating paths, shades and gradients with help of JavaScript to display them within the Canvas. For the purpose of this tutorial, I have defined canvas with width as 300, height as 400 and id = "canvas".
Lastly, we define another div to help user with the controls or any other message that we may want to display to user related to controls during gameplay or afterwards.
Now the fun part, the JavaScript for the game.
We'll start with defining all the global variables that we'll require during our game. The script goes into the <head> tag of the html file.
Code Snippet
var context;
var width = 300;
var height = 400;
var snakeLength = 3; var level = 1; var sqSize = 10;
var bodyX = new Array(150, 150-sqSize, 150-2*sqSize);
var bodyY = new Array(200, 200, 200);
var vX = new Array(1, 1, 1); var vY = new Array(0, 0, 0); var rX;
var rY;
var score = 0;
var scoreDiv;
var eaten = true;
var gameOver = false;
var controlsDiv;
</script>
Comments accompanying the variables are self explanatory, for those having any confusion hold on for few minutes till you reach the code where they are used and it should get clear to you. Still have any doubt, ping it to me.
Another neat feature of HTML5, in case you haven't notices till now is <script> tag, which no longer requires to be specified with type attribute.
Now let's have a look a look at couple of drawing APIs for HTML5. Below we define 3 functions:
- To draw the canvas boundary in order to mark our playing area
- To draw the points (squares) for the snake body
- Draw our snake
Code Snippet
function drawCanvasBoundary()
{
context.fillStyle="#FFF";
context.fillRect(0,0,width,height);
context.fill();
context.strokeStyle="#000";
context.strokeRect(0,0,width,height)
}
function drawPoint(x,y)
{
context.fillStyle = "#000";
context.fillRect(x,y,sqSize, sqSize);
context.fill();
context.strokeStyle="#FFFFFF";
context.strokeRect(x,y,sqSize, sqSize);
}
function drawSnake()
{
for(var i=0; i < snakeLength; i++)
drawPoint(bodyX[i],bodyY[i]);
}
Here we essentially use 2 functions from the HTML5 APIs - strokeRect and fillRect and customize them using the corresponding style attributes viz. strokeStyle and fillStyle. But what are these functions for? Well as the name suggest, strokeRect is to draw a rectangle and fillRect first draws the rectangle and then fills it with the color specified in its attributes. Does this remind you of anything familiar?? MSPaint??
So over here we have defined that we need a white background for our playarea and snake has to be displayed in black color squares with white borders to give the impression of the digital displays of our older mobiles.
Now that we have written the drawing functions, let us display our canvas and snake.
Code Snippet
function init()
{
context = document.getElementById("canvas").getContext("2d");
drawCanvasBoundary();
drawSnake();
}
window.addEventListener("load", init, true);
The init function first gets the "game context", 2D in this case (Canvas supports 3D as well!). This context is required to tell our browser, where all the commands needs to be executed. Then we make function calls for the 2 draw functions we previously defined. Lastly, we tell the browser to execute our init function whenever the page gets loaded with the help of addEventListener command. Now reload your page and you should see the following output:

Till now we are just displaying a static output. Now its time to add interactivity and move our snake. Lets define the functions to move snake and the controllers with their behaviors.
Code Snippet
function moveSnake()
{
for(var i=0; i < snakeLength; i++)
{
bodyX[i] += (vX[i]*sqSize);
bodyY[i] += (vY[i]*sqSize);
}
for(var i=snakeLength-1; i>0; i--)
{
vX[i] = vX[i-1];
vY[i] = vY[i-1];
}
}
function keydown(e)
{
if(e.keyCode == 65 && vX[0] != 1)
{
vX[0] = -1;
vY[0] = 0;
}
else if (e.keyCode == 87 && vY[0] != 1)
{
vY[0] = -1;
vX[0] = 0;
}
else if (e.keyCode == 68 && vX[0] != -1)
{
vX[0] = 1;
vY[0] = 0;
}
else if (e.keyCode == 83 && vY[0] != -1)
{
vY[0] = 1;
vX[0] = 0;
}
else if (e.keyCode == 13 && gameOver == true)
{
gameOver = false;
}
}
function gameProcess()
{
intervalId = setTimeout(gameProcess, 1000/(6*level));
clear();
drawCanvasBoundary();
moveSnake();
drawSnake();
}
function clear()
{
context.clearRect(0,0,width,height);
}
Okay, so we defined a lot of things here... lets take it one by one
clear() - As the comments say, this function simply clears the entire canvas which is then redrawn.
keydown(e) - Function to handle the key strokes for guiding our snake through the game, currently it only listens to "W,A,S,D" for directions and "Enter" to restart the game after it gets over. Note: I had to change controls from arrow keys to WASD and include a restart key from what I learnt from
last blog post - 1. arrow keys were moving the page up n down; and 2. to restart the game, the user had to reload the entire page.
moveSnake() - unlike any other object, different parts of Snake's body can move indirectionsdifferent than its head which forces us to keep direction coordinates for each and every body part in the Vx and Vy arrays. The motion is however constrained by that of preceding body part. So the direction vector gets simply copied downwards.
gameProcess() or the "Game Loop", every game has this which basically performs - (update-draw), (update-draw),.... repeatedly. The function sets the time for next refresh, clean the canvas, calls moveSnake to calculate the updated coordinates (the update function of game) and finally draws snake (the draw function).
Now, let's refresh the page again... what happened? there is something wrong here...
we forgot to initialize the game loop in our init function, so lets do it now.
Code Snippet
intervalId = setTimeout(gameProcess, 1000/6);
scoreDiv = document.getElementById("score");
controlDiv = document.getElementById("control");
window.onkeydown = keydown;
Add these 4 commands in the init functions and reload the page. Yippiee!!! our snake is now moving.
So where is the RAT?? lets start putting the rats in the game and make our snake eat them.
Code Snippet
function placeRat()
{
if(eaten)
{
rX = Math.floor(width*Math.random()/sqSize)*sqSize;
rY = Math.floor(height*Math.random()/sqSize)*sqSize;
if(checkFoodCollision(rX,rY))
placeRat();
else
eaten = false;
}
drawPoint(rX, rY);
};
function checkFoodCollision(x, y)
{
for (var i = 0;i<snakeLength; i++)
if(x == bodyX[i]&& y == bodyY[i])
{
return true;
}
return false;
}
function eatRat()
{
if(bodyX[0] == rX && bodyY[0] == rY)
{
eaten = true;
var newX = bodyX[snakeLength-1]-vX[snakeLength-1]*sqSize;
var newY = bodyY[snakeLength-1]-vY[snakeLength-1]*sqSize;
bodyX.push(newX);
bodyY.push(newY);
vX.push(vX[snakeLength-1]);
vY.push(vY[snakeLength-1]);
snakeLength++;
score += 10;
if((score%100) == 0)
level++;
scoreDiv.innerHTML = "Score: "
+score+" Level: "+level;
}
}
Again lets look at each function one-by-one:
placeRat() - This function uses the math library to generate a random position (x,y) coordinate on the canvas. It then checks if Snake's body is not hiding the new Rat position, if it does - it calls for generating fresh set of coordinates otherwise, it sets eaten Rat parameter to be false and draws the new Rat.
checkFoodCollision() - Function called by placeRat() to check if the new rat position is not hidden under snake's body
eatRat() - Checks if Snake's head is at the location of Rat. If yes, it raise the rat is eaten flag to tell our program to generate new rat position. Then it increments snake length and add new body part at the end. Finally it increments score and determine if the level needs to be increased as well, and then display both of them.
Also unhide the call to "eatRat()" from moveSnake() function and
Add, the call to placeRat() to gameProcess() function

Our game of snake is almost ready, but for one last bit of work. Currently if you try to move the snake past the boundary, it will go and disappear from the skin. Also try folding snake on itself, it will do because we haven't worked on the collision/termination conditions. Lets do it now!
Code Snippet
function checkCollision()
{
if(bodyX[0] >= width || bodyX[0] < 0 || bodyY[0] < 0 || bodyY[0] >= height)
{
scoreDiv.innerHTML = "Score: "
+score+" Level: "
+level+" <b>Game Over</b>";
controlDiv.innerHTML = "Press \"Enter\" to restart";
gameOver = true;
clearTimeout(intervalId);
}
else if(snakeLength > 4)
{
if(checkSelfCollision(bodyX[0],bodyY[0]))
{
scoreDiv.innerHTML = "Score: "
+score+" Level: "
+level+" <b>Game Over</b>";
controlDiv.innerHTML = "Press \"Enter\" to restart";
gameOver = true;
clearTimeout(intervalId);
}
}
}
function checkSelfCollision(x, y)
{
for (var i = 4; i < snakeLength; i++)
if(x == bodyX[i] && y == bodyY[i])
{
return true;
}
return false;
}
We need to check for 2 different types of collision, one is snake colliding with the boundary walls and the other being, self collision.
checkSelfCollision() - This function iterates over the body parts starting from 5 (why?) and checks whether the snake's head has not collided with the body part or not.
checkCollision() - Checks if the snake has collided with the boundary, if not calls for checking selfCollision
Now, just
add a call to checkCollision before we drawSnake() in the gameProcess() function, so that the final gameProcess function looks like this
Code Snippet
function gameProcess()
{
intervalId = setTimeout(gameProcess, 1000/(6*level));
clear();
drawCanvasBoundary();
placeRat();
moveSnake();
checkCollision();
drawSnake();
}
Lastly, lets enable the control to restart the game when it gets over.
Unhide the call to restart() function from keydown() function (look at the end where we handle case for keycode 13 i.e. "Enter Key") and then add then define the restart function as below -
Code Snippet
function restart()
{
bodyX = new Array(150, 150-sqSize, 150-2*sqSize);
bodyY = new Array(200, 200, 200);
vX = new Array(1, 1, 1);
vY = new Array(0, 0, 0);
snakeLength = 3;
score = 0;
level = 1;
eaten = true;
scoreDiv.innerHTML = "Score: " +score+"Level: "+level;
controlDiv.innerHTML = "Controls: W = Up; A = Left; S = Down; D = Right";
intervalId = setTimeout(gameProcess, 1000/6);
}
And we are done!!! Complete source code can be obtained from
here
Enjoy the game
here and do write your suggestions/comments
After almost 4 years of experience varying from finance to building & running a startup... I decided to take a break, go back to college and be a (academic) student again.
However, I continue to do freelance work and am currently working on HTML5 games for Code-Heads, a UK based studio.
http://aniruddhaloya.blogspot.com