Blog

Snake Game Tutorial with HTML5 Canvas & Javascript

Snake Game using HTML5 and Javascript

Today we am gonna show you how to make a game using only HTML5 and JavaScript. Though it may seem like a strenuous task, but really it’s all about getting started.

So let’s begin making a classic well-known “SNAKE GAME” which everyone would be quite familiar with. Before beginning lets just have a small intro of ‘What’s a Canvas’?

What is HTML Canvas?

The HTML <canvas> element is used to draw graphics, on the fly, via scripting (usually JavaScript).The <canvas> element is only a container for graphics. You must use a script to actually draw the graphics. Canvas has several methods for drawing paths, boxes, circles, text, and adding images.

How To Play:

It is very similar to the basic snake game we are used to playing but with a higher difficulty level.

Total Lives – 3
Blue Dot – To be Eaten
Red Dot – Reduces Life
Black Walls – If hit, Game Ends!

Play Game

 

Here is the markup code:

<h3>Press 'P' to Play &nbsp; Press 'Spacebar' to Pause &nbsp; Press 'R' to Restart</h3>

<div  style="border:3px solid brown; float: left; height: 500px">
<canvas id="canvas" width="500" height="500"></canvas>
</div>

So the frame for your game is ready. Now let’s add script file to our project. Add script code as follows:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type = "text/javascript "> </script>
<script src="snake.js"></script>

First Script file is for adding jQuery script and other one is GAME’s main script file. Here I have name the file as snake.js. Now let’s come to core part of the game that is coding.
Here is the startup code for game which is to be written in file snake.js:

$(document).ready(function () {

Here are some variables and  required Canvas stuff. Variables such as cell width, direction, food and score are stored in a variable for easy control. Last variable is an array of cells to make up the snake:

var canvas = $("#canvas")[0];
var ctx = canvas.getContext("2d");
var w = $("#canvas").width();
var h = $("#canvas").height();
var cw = 10;
var d;
var food;
var score;
v
ar snake_array;

Now lets add some functions.
These function can be used to pause, restart, and resume the game. Here are conditions on keypress:

$(document).keydown(function (e) {
var key = e.which;
if (key == "32")
pause();
else if (key == "80")
play();
else if (key == "82") {
init();
play();
}
})

Game can be paused by pressing key “Spacebar”.
Game can be resumed again by pressing key “P”.
Game can be refreshed by pressing key “R”.
The function below is for Play or Resuming Play after pausing the game and to move the snake using a timer which will trigger the paint function  every 60ms:

function play()
{
if (typeof Game_Interval != "undefined")
clearInterval(Game_Interval);
Game_Interval = setInterval(paint, 60);
allowPressKeys = true;
}

function pause()
{
clearInterval(Game_Interval);
allowPressKeys = false;
}

The function below is for initiating the game and displaying score:

function init()
{
d = "right"; //default direction
play();
create_snake();
create_food(); //Now we can see the food particle
score = 0;
}
init();

This function will create the snake:

function create_snake()
{
var length = 5; //Length of the snake
snake_array = []; //Empty array to start with
for (var i = length - 1; i >= 0; i--)
{
//This will create a horizontal snake starting from the top left
snake_array.push({x: i, y: 0});
}
}

Lets create the food now. Through this function food will be created randomly on the area of canvas. This will create a cell with x/y between 0-49. Because there are 50(500/10) positions across the rows and columns:

function create_food()
{
food = {
x: Math.round(Math.random() * (w - 20) / cw),
y: Math.round(Math.random() * (h - 20) / cw),
};
}

Lets paint the snake now.To avoid the snake trail we need to paint the BG on every frame for which we have to paint the canvas. Then we will write movement code for the snake. The logic is simple: Pop out the tail cell and place it infront of the head cell. After storing head position of snake in variables we will increment it to get the new head position. Then we will add proper direction based movement.If Snake goes out of the frame then resetting the head position. We will write exit condition instead of resetting the position.

After doing this add the game over clauses now. Add the code for body collision if the head of the snake bumps into its body, the game will restart.

Then we will write the code to make the snake eat the food. The logic is simple If the new head position matches with that of the food, Create a new head instead of moving the tail:

function paint()
{
//Lets paint the canvas now
ctx.fillStyle = "white";
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = "black";
ctx.strokeRect(0, 0, w, h);
//The movement code for the snake to come here.
var nx = snake_array[0].x;
var ny = snake_array[0].y;
//These were the position of the head cell.
if (d == "right")
nx++;
else if (d == "left")
nx--;
else if (d == "up")
ny--;
else if (d == "down")
ny++;

if (nx == -1)
{
nx = w / cw - 1;
} else if (nx == w / cw)
{
nx = 0;
}
if (ny == -1)
{
ny = h / cw - 1;
}
else if (ny == h / cw)
{
ny = 0;
}


if (check_collision(nx, ny, snake_array))
{
//restart game
alert("Game Over Your score is " + score);
init();
play();
return;
}


if (nx == food.x && ny == food.y)
{
var tail = {x: nx, y: ny};
score++;
//Create new food
create_food();
}
else
{
var tail = snake_array.pop(); //pops out the last cell


tail.x = nx;
tail.y = ny;
}
//The snake can now eat the food.
snake_array.unshift(tail);
//puts back the tail as the first cell
for (var i = 0; i < snake_array.length; i++)
{
var c = snake_array[i];
paint_cell(c.x, c.y);
}
/
/Lets paint the food
paint_cell(food.x, food.y);
//Lets paint the score
v
ar score_text = "Score: " + score;
ctx.fillText(score_text, 5, h - 5);
}

Lets create a generic function to paint cells  

function paint_cell(x, y)
{
ctx.fillStyle = “blue”;
ctx.fillRect(x * cw, y * cw, cw, cw);
ctx.strokeStyle = “white”;
ctx.strokeRect(x * cw, y * cw, cw, cw);
}

Here is the function of checking whether head of snake is colliding:

function check_collision(x, y, array)
{
//This function will check if the provided x/y coordinates exist in an array of cells or not
for (var i = 0; i < array.length; i++)
{
if (array[i].x == x && array[i].y == y)
return true;
}
return false;
}

Lets add the keyboard controls now:

$(document).keydown(function (e) {
var key = e.which;
//We will add another clause to prevent reverse gear
if (key == "37" && d != "right")
d = "left";
else if (key == "38" && d != "down"
d = "up";
else if (key == "39" && d != "left")
d = "right";
else if (key == "40" && d != "up")
d = "down";
})
})

Not just this, if you want to make your game a little more interesting then you can add new element like poison in your game or partial wall on the boundaries. So let’s add poison function. But do remember poison should be near food otherwise the game wouldn’t become interesting.

Here is the code for creating a poison:

function create_poison1()
{
if (food.x >= 48) {
minx = 47 + 1;
maxx = 47 + 2;
miny = food.y + 1;
maxy = food.y + 2;
}
else if (food.y >= 48) {
minx = food.x + 1;
maxx = food.x + 2;
miny = 47 + 1;
maxy = 47 + 2;
}
else {
minx = food.x + 1;
maxx = food.x + 2;
miny = food.y + 1;
maxy = food.y + 2;
}
minx = food.x + 1;
maxx = food.x + 2;
miny = food.y + 1;
maxy = food.y + 2;
poison1 = {
x: Math.round(getRandomArbitrary_x(minx, maxx)),
y: Math.round(getRandomArbitrary_y(miny, maxy)),
};
}
function getRandomArbitrary_x(min, max) {
return Math.random() * (max - min) + min;
}
function getRandomArbitrary_y(min, max) {
return Math.random() * (max - min) + min;
}

Now the only thing is where to call this function in your game and what will be the purpose of poison. Over here I am giving you the code for creating 1 poison. You can create as many poisons as you want just keep in mind to have correct conditional values so that it does not collide with either boundary or with the food itself.  

Here are few things you can do, for example:

  1. You can keep one variable as life and you can decrease that variable, also can even decrease the size of snake as snake eats the poison.
  2. You can end the game when snake eats the poison.

Suppose for example you choose option number “1” then you can write your code like this.

That is on eating the poison variable life should decrease:

if ((nx == poison1.x && ny == poison1.y) || (nx == poison2.x && ny == poison2.y))
{
var tail = snake_array.pop();
tail = snake_array.pop();
tail.x = nx;
tail.y = ny;
life--;
//Create new food
create_food();
create_poison1();
create_poison2();
}

And in function where we have clauses of ending the game we will add if statement life==0 as shown :

if (check_collision(nx, ny, snake_array) || life == 0)

Not only this you but you will also have to paint the cell for poison as we had painted for food. Code for painting that cell is as shown:

function paint_cell_poison(x, y)
{
ctx.fillStyle = “red”;
ctx.fillRect(x * cw, y * cw, cw, cw);
ctx.strokeStyle = “white”;
ctx.strokeRect(x * cw, y * cw, cw, cw);
}

For Printing the Life in your canvas you can write the following code:

var life_text = “Life:” + life;
ctx.fillText(life_text, w – 50, h – 5);

 

Code for creating partial Walls

First of all we have to take 2 arrays for vertical and horizontal walls as wall_arrayv and  wall_arrayh respectively.

Here is the code for creating partial walls at the boundaries of game.

Creating a vertical wall

function create_wall_vertical() {
var length = 10;
wall_arrayv = []; //Empty array to start with
randomy = Math.round(getRandomArbitrary_y(1, 40));
randomx = Math.round(getRandomArbitrary_x(1, 50));
if (randomx < 25) {
randomx = 0;
}
else {
randomx = 49;
}
wall_arrayv.push({x: randomx, y: randomy});
wall = wall_arrayv.pop();
for (var i = length - 1; i >= 0; i--)
{
wall_arrayv.push({x: wall.x, y: wall.y + i});
}
}

Creating a horizontal wall

function create_wall_horizontal() {
var length = 10;
wall_arrayh = []; //Empty array to start with
randomx = Math.round(getRandomArbitrary_y(1, 40));
randomy = Math.round(getRandomArbitrary_x(1, 50));
if (randomy < 25) {
randomy = 0;
}
else {
randomy = 49;
}
wall_arrayh.push({x: randomx, y: 49});
//here I have taken constant y because I want the wall to appear only at the bottom and not at top
wall = wall_arrayh.pop();
for (var i = length - 1; i >= 0; i--)
{
wall_arrayh.push({x: wall.x + i, y: wall.y});
}
}

Now just make a call to these functions in init() function so that wall could appear. We also have to change our game end clauses so that when snake hits the wall game should get over.

if (check_collision(nx, ny, snake_array) || life == 0 || check_collision(nx, ny, wall_arrayv) || check_collision(nx, ny, wall_arrayh))


Priyanka

About Priyanka Thakur

A stylist by heart, and a blogger by choice. Though, fashion and food are her long-abiding passions, she spends a considerable amount of time researching and experiencing the latest marketing trends. And when not stalking the world of digital ecstasy, she’s probably found travelling or hunting for an undiscovered boutique.

Read More from Priyanka Thakur

Leave a Reply:

  1. pam_Designer says:

    Hey! Can you provide with a tutorial for tetris in JS?

Leave a Comment:

Your email address will not be published. Required fields are marked *

Word on the street

Anmol & his bunch of designers at 42Works surpassed all my expectations — be it design, speed or delivery. His organisation has certainly been the best experience I have encountered with outsourcing. I will certainly recommend them again. They are now my “Go-To-Guys” for all projects.
Dan TaylorVenture CapitalistKilmacolm, United Kingdom
42works

We Love Listening to You

With whom do we have the pleasure of speaking?

Pleasure to meet you, . What business are you from?

How can we help you?

What’s on your mind? Tell us a bit about your project.

Have a current website or reference link?

Any estimate on the budget for your project/campaign?

Great, Where shall we email you?

And how about your phone number?

How did you find us?