Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Snake Game using HTML5 Canvas

In this article we will discuss about the development of the famous Snake Game using HTML5 only.

These days I'm working on HTML5 especially HTML5 Canvas, so I decided to make some games using the HTML5 Canvas. The Canvas is one of the best features of HTML5 and you can create beautiful designs using it. In this article, I have tried to make a very old game example which was very popular and we all played many times especially in old cell phones specifically in Nokia handsets. Now you might be have a question like why should I read this article? Right? The answer is after reading this article you will get idea about how we are going do game development using HTML5.

While developing any kind of game through any language, you have to be very clear idea about it. Need to prepare logic as what you are going to do and how you can represent your idea turns into game.

We used the HTML5 Canvas and a little jQuery to create our "Snake Game".

About Snake Game

It is a grid based game where the player plays as a snake and has to eat his food. Every time you eat food you grow by one unit and a new food appears at the end. If you hit a wall or yourself you lose the game. And when player loses we will restart the game or end the game.

Canvas Coordinate System

Below diagram Figure1 is screen-based coordinate systems. The 2d rendering context in canvas is no different; it uses a standard Cartesian coordinate system, with the origin point (0, 0) at the top left. Moving to the right will increase the value of thexaxis, while moving downward will increase the value of theyaxis. One pixel on screen is equal to one unit in coordinate systems (in majority of cases)

(0, 0)

X

Y

Figure 1: Canvas Coordinate System

Concept of the Game

Initially a small sized snake appears on screen which keeps running. Players can change direction of snake using arrow keys to move up, down, left and right. Length of snake increases after eating randomly appearing food item. Increasing length of snake adds difficulty to the game over time.

Getting Started

Firstly you want to define Canvas object in body of html markup with its size. Define size whatever you want. The width and height attribute is necessary to define the size of the canvas.

There are two ways for defining canvas object either you can directly use <canvas> object or you can create using dynamically through JavaScript.

Here we can create canvas with width 500 and height 500 using <canvas> element

  <html>
         <head> 
  <title> Snake Game </title>
  </head>
  <body>
  <canvas id=”SnakeCanvas” width=”500” height=”500”></canvas> 
  </body>
  </html>
  

However, the canvas element has no drawing abilities of its own (it is only a container for graphics) - you must use a script to actually draw the graphics. So you need to use method getContext().

The getContext() method returns an object that provides methods and properties for drawing on the canvas.

The getContext("2d") object, which can be used to draw text, lines, boxes, circles, and more - on the canvas.

There is another option where you can create canvas object dynamically using DOM with the help of JavaScript like below.

  var myCanvas = document.createElement(‘canvas’);
  myCanvas.width = 400;
  myCanvas.height = 500;
  

Here you need to take reference of our body tag where we need to put this canvas object. For this purpose we are going to use document.getElementByTagName() method.

  var myBody = documemt.getElementByTagName(“body”)[0];
  

Finally we need to use appendChild() method to add / append our canvas object to the body like this:

  myBody.appendChild(myCanvas); 
  

The complete code

  var myCanvas = document.createElement(‘canvas’);
  myCanvas.getContext(“2d”);
  myCanvas.width = 500;
  myCanvas.height = 500;
  var myBody = documemt.getElementByTagName(“body”)[0];
  myBody.appendChild(myCanvas); 
  

Excellent!!!

Now if you run any one option from above in browser you will see a blank page only and the reason is we haven’t draw anything on canvas yet!

So let’s start for drawing something on our defined canvas.

Now we are going to use little bit jQuery code in <script> tag.

We are declaring some variables here for our canvas and getting values.

  var  snake_canvas  = $(“#SnakeCanvas”)[0];
  var  ctx  =  snake_canvas.getContext(“2d”);
  

If you see here, we are storing a reference of 2D context in variable called ctx, which gives us access to 2D drawing methods, one of such method is strokeRect().

ctx.strokeRect(X1, Y1, width, height) allows us to draw outlined rectangles.

The first parameter, X1 defines the starting point on the X axis; the second parameter Y1 defines the start point on the Y axis. The third, width defines the end coordinate on the X axis and the fourth, height defines the end coordinate on the Y axis.

For example, ctx.strokeRect(0, 0, 10, 10) means that it will draw an outlined rectangle starting on the pixels 0, 0 (top left) and will end on the pixels 10, 10.

Additionally, we can use the ctx.strokeStyle property to define the outline color, and ctx.lineWidth to define how thick we want the outline to be.

Now we need two more values that we defined already at the time of canvas definition called as height and width of canvas.

  var  snake_width   =  $(“#SnakeCanvas”).width();
  var  snake_height  =  $ (“#SnakeCanvas”).height(); 
  

Drawing Square

Now what I remembered from the Snake game which I usually played in my old days, Snake looks like a chain of boxes like as square.

So, we are draw square on our canvas using fillRect() method.

fillRect() method allows us to draw “filled” rectangle. Also, we can use the ctx.fillStyle property to define the filled color.

  ctx.strokeStyle = "#000000"; 
  ctx.strokeRect(0,0, snake_width, snake_height);
  ctx.fillStyle = "#ffffff";
  ctx.fillRect(0,0, snake_width, snake_height);
  ctx.lineWidth = 2;
  

Movement of Snake

Now that I know how to draw squares, I want to move that squares. It means the Snake can move up, down, left, and right direction.

To move the snake in a direction we are playing with arrows keys of our keyboard.

Here we are using JavaScript again to catch which keyboard keys being hit, and use those keys to interact with canvas.

  window.addEventListener('keydown', function(e) { 
         if (e.keyCode === 38) {
              // action when pressing Up key
              } else if (e.keyCode === 40) {
             // action when pressing Down key
             } else if (e.keyCode === 37) {
            // action when pressing Left key
            } else if (e.keyCode === 39) {
            // action when pressing Right key
            }  
  });
  

It means when we hit a key of keyboard, we want to draw new square going in that direction. To match the direction first, we need to know following

1) What’s the current position of the Snake’s head?

2) What direction do we want to go, which is given by the key press event?

So we need a variable where we set the position of our Snake’s head, and when we press any key (arrow key) of keyboard, we draw new square whose position is the offset of the direction from current position of Snake’s head.

  var pop_x = mySnakeArray[0].x;
  var pop_y = mySnakeArray[0].y;      
  

These are the position of the Snake’s head.

Please note here, mySnakeArray is an array that we are going to take it forward for creating our snake. You will get more info in next points.

Snake’s moving

Now in old days, when you play the Snake’s mobile phone game, we can control the direction of snake game using keys of mobile but we can’t control the speed of Snake’s that keep remains constant. It means we have to focus on guiding the Snake’s around the canvas area not to bump itself.

To implement this kind of functionality, we need to take below two things

1) Need one more new variable in what direction the Snake is going on

2) Make a timed loop that will execute a function to move the snake in that direction.

So, here we are creating new variable, called “direction”

  direction = “right”;
  

To move our snake in that direction we can use timer that will trigger drawSnake() method after every 200ms.

  setInterval(drawSnake, 200);
  

So here we are going to make timed loop

   if (typeof game_loop != "undefined") clearInterval(game_loop);
             game_loop = setInterval(drawSnake, 200);
  

   switch(direction){
                  case ‘up’ : pop_y--;
                   break;
                   case ‘down’ : pop_y++;
                  break;
                  case ‘right’: pop_x++;         
                  break;
                  case ‘left’ : pop_x- -;
                  break;
          }
  

Now here we get to know that Snake moving in Right direction. That is fine but it seems like that in spite of our insisting the Snake is determined to go right, here we haven’t associated keystrokes with change in direction.

So let’s assigned direction variable with keystrokes.

  window.addEventListener('keydown', function(e) { 
         if (e.keyCode === 38 && direction !== “down”) {
                       direction = “up”;  // Up
  } else if (e.keyCode === 40 && direction !== “up”) {
                      direction = “down”;  // Down
         } else if (e.keyCode === 37 && direction !== “right”) {
  direction = “left”;        // Left
  } else if (e.keyCode === 39 && direction !== “left”) {
                      direction = “right”;       // Right
      }
  });
  

Create our Snake

Now it’s time to create our Snake using createSnake () method. Remembered, the Snake looks like a chain of square.

So, now to create a snake we need to define array of cell.

  var  mySnakeArray = []; 
  

In createSnake() method we are going to use size of snake and use of an empty array mySnakeArray to start.

  function createSnake()
  {
          var i;                               
          var snakeSize = 6;
          mySnakeArray = [];
          for (i = 0 ; i < snakeSize-1; i++)            
  }
  

This line will create a horizontal snake starting from middle left. We can change the position by giving the value of X & Y.

  mySnakeArray.push({ x : 0, y:20 });
  

Creating Food Item

Until and unless food item is not present for our Snake, How our snake become longer and how can we played the game right?

So next thing is creating food for our Snake.

To add the food item in our game, we need to do following things:

1) Create a method to draw food item on the canvas.

2) When snake eating our food item, our snake becomes longer, means the snake body will increase and again draw next food item on canvas somewhere else.

Now, we know how to draw square on canvas, but now problem is how we place food item at some random location.

This problem can solve by our Mathematical functions from JavaScript.

We used some functions from our Math Library that will create a cell with x /y.

  function generateFoodItem()
  {
       snakeFoodItem  =  {
         x: Math.round(Math.random() * (snake_width - cell_width) / cell_width),
        y: Math.round(Math.random() * (snake_height - cell_width) / cell_width),
      };
  }
  

After creating our Snake and his food Item we need to draw snake. We need to draw background on every frame to avoid snake trail.

For this function drawSnake(), we already defined his components above

  function drawSnake()
  {
        // First we need to draw on canvas – Here we used Drawing Square part
       // movement of our snake   - Here we used Movement of Snake and Snake’s Moving part
  }
  

Game Over

Now, we need to think if our snake hits the wall of our canvas, also if our snake’s head bumps into the body then we need to restart the game or else we can end the game.

  if (pop_x == -1 || pop_x == snake_width / cell_width || pop_y == -1 || pop_y == snake_height / cell_width || check_collision(pop_x, pop_y, mySnakeArray)) 
  {
  showGameOver();
  return ;
  }
  

Eat Food

We already create food item for our snake, but we need to write some code here so that our snake eat his food.

Here, the new head position matches with food then create a new head instead of moving the snake’s tail.

   if (pop_x == snakeFoodItem  .x && pop_y == snakeFoodItem  .y) {
                   var snakeTail = { x: pop_x, y: pop_y };
                   userscore++;
                   generateFoodItem ();    //This function create our snake’s food.
              }
              else {
                  var snakeTail = mySnakeArray.pop();
                  snakeTail.x = pop_x; snakeTail.y = pop_y;
              }
  

Finally our snake is able to eat his food. Now we need to return the Snake’s tail to the first cell.

For same, we are going to used unshift() method and passing snakeTail as parameter.

  mySnakeArray.unshift(snakeTail);
  

Now, in above article we are using one word called as Cell_width right? And so far we are not refer to anyone what exactly cell_width refer to?

So actually the cell_width is like one column of our grid. And in cell_width we are defined width of column.

We are going to used one variable as cell_width.

  var  cell_width = 15;
  

Now we declared our cell width; now we draw a 15px wide cell using "paintCell(k.x, k.y)".After that we will paint the food & score both:

              paintCell(snakeFoodItem.x, snakeFoodItem .y);               
              var score_text = "Score: " + userscore;
              context.fillText(score_text, snake_width-100, 20);
  

We are creating a separate function that will paint all cells.

  function paintCell(x, y) {
                  ctx.fillStyle = "green";
                  ctx.fillRect(x * cell_width, y * cell_width, cell_width, cell_width);
                  ctx.strokeStyle = "red";
                  ctx.strokeRect(x * cell_width, y * cell_width, cell_width, cell_width);
              }
  

Excellent, we are near to end of our Snake game. Now one last important point remaining. As we know, the Snake game is grid based game and for that we define canvas with 2d context, and specified a cell_width of that gird based system.

Now the point is here that we need to if the given x/y coordinates exist already in an array of cells or not.

For that we are going to define one more function which checks above condition.

              function check_collision(x, y, array) {
                  for (var i = 0; i < array.length; i++) {
                      if (array[i].x == x && array[i].y == y)
                          return true;
                  }
                  return false;
              }
  

Show Game Over

It’s nice that when we loose the game a message pops up saying "Game Over" and shows the final score To accomplish that we're going to make a new function called showGameOver(), that will look like this:

  function showGameOver()
  {
     ctx.fillStyle = '#ffffff';
     ctx.font = '16px sans-serif';
     ctx.fillText('Game Over!', ((snake_width / 2) - (ctx.measureText('Game Over!').width / 2)), 50);
     ctx.font = '12px sans-serif';
     ctx.fillText('Your Score Was: ' + userscore, ((snake_width / 2) - (ctx.measureText('Your Score Was: ' + userscore).width / 2)), 70);
  }
  

In above function, first we used fillText method to draw “filled” text on canvas. Now even though, we have used fillText method, we are making here some calculations.

The measureText() method of ctx object measures the width of given text. This basically means that, for example, ctx.measureText(“Gokul”) would return a special object called TextMetrics() that has a width property. In the case that we want to center an element in the middle of canvas we do

snake_width / 2; // which would give us a reference to the center of the canvas

And then…

ctx.measureText(“Gokul”).width / 2 //which would give us a reference to the center of the text

Then we only need to do ( snake_width / 2) – (ctx.measureText(“Gokul”).width / 2) to accurately center the text on the canvas, which is exactly what is going on here

And that’s it! We’ve made a nice Snake Game!!!!

I am providing the complete code below, please have a look and play around and have a fun playing with our old Snake Game using HTML5 Canvas and JavaScript.

Listing 1. Snake.html

  <!DOCTYPE html>
  <html>
  <head>
      <title>Snake Game</title>
      <style type="text/css">
          body { margin: 0 auto; padding : 0; }
          #SnakeCanvas { position: absolute;  top:0; bottom: 0; left: 0;  right: 0;  margin:auto;}
      </style>
      <!-- jQuery CDN Link -->
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js" type=”text/javascript”></script>
      <script type = "text/javascript">
          $(document).ready (function () {
              var snake_canvas = $("#SnakeCanvas")[0];
              var ctx  = snake_canvas.getContext("2d");
              var snake_width  = $("#SnakeCanvas").width();
              var snake_height = $("#SnakeCanvas").height();
   
              var cell_width = 15;
              var direction;
              var snakeFoodItem;
              var userscore;
              var mySnakeArray;
              var level = 0;
   
             function startPoint() {
                direction = "right";
                  createSnake();
                  generateFoodItem();
                  userscore = 0;
                 if (typeof game_loop != "undefined") clearInterval(game_loop);
                  game_loop = setInterval(drawSnake, 200);
              }
              startPoint();
              function createSnake() {
                var i;
                  var snakeSize = 6;
                  mySnakeArray = [];
                  for (i = 0; i<snakeSize-1;i++) {
                      mySnakeArray.push({ x: 0, y: 20 });
                  }
              }
   
              function generateFoodItem() {
                snakeFoodItem= {
                      x: Math.round(Math.random() * (snake_width - cell_width) / cell_width),
                      y: Math.round(Math.random() * (snake_height - cell_width) / cell_width),
                  };
               }
   
              function drawSnake() {
                  ctx.fillStyle = "#000000";
                  ctx.fillRect(0, 0, snake_width, snake_height);
                  ctx.strokeStyle = "ffffff";
                  ctx.strokeRect(0, 0, snake_width, snake_height);
                ctx.lineWidth = 2;
   
                 var pop_x = mySnakeArray[0].x;
                 var pop_y = mySnakeArray[0].y;
   
         switch(direction)   {
                  case 'up' : pop_y--;
                  break;
                  case 'down' : pop_y++;
                  break;
                  case 'right': pop_x++;         
                  break;
                  case 'left' : pop_x--;
                  break;
                }
   
                if (pop_x == -1 || pop_x == snake_width / cell_width || pop_y == -1 || pop_y == snake_height / cell_width || check_collision(pop_x, pop_y, mySnakeArray))        {
               showGameOver();
                      return;
                }
   
                   if (pop_x == snakeFoodItem.x && pop_y == snakeFoodItem.y) {
                      var snakeTail = { x: pop_x, y: pop_y };
                      userscore+=10;      
                      generateFoodItem();
                      if((userscore %100) == 0) {  level +=1; }       
                  }
                  else {
                      var snakeTail = mySnakeArray.pop();
                      snakeTail.x = pop_x; snakeTail.y = pop_y;
                  }
   
                  mySnakeArray.unshift(snakeTail);
                   for (var j = 0; j < mySnakeArray.length; j++) {
                      var k = mySnakeArray[j];
                  
                      paintCell(k.x, k.y);
                  }
   
                  paintCell(snakeFoodItem.x, snakeFoodItem.y);
                 
                  var score_text = "Score: " + userscore;
                 var score_level = "Level : " + level;
                 ctx.font = '15px sans-serif';    
                  ctx.fillText(score_text, snake_width-250, 20);
                  ctx.fillText(score_level, snake_width-100, 20);
              }
   
             function paintCell(x, y) {
                  ctx.fillStyle = "green";
                  ctx.fillRect(x * cell_width, y * cell_width, cell_width, cell_width);
                  ctx.strokeStyle = "red";
                  ctx.strokeRect(x * cell_width, y * cell_width, cell_width, cell_width);
              }
   
              function check_collision(x, y, array) {
                  for (var i = 0; i < array.length; i++) {
                      if (array[i].x == x && array[i].y == y)
                          return true;
                  }
                  return false;
              }
  window.addEventListener('keydown', function(e) { 
         if (e.keyCode === 38 && direction !== "down") {
                       direction = "up";         // Up
         } else if (e.keyCode === 40 && direction !== "up") {
                      direction = "down";  // Down
         } else if (e.keyCode === 37 && direction !== "right") {
               direction = "left";        // Left
         } else if (e.keyCode === 39 && direction !== "left") {
                      direction = "right";              // Right
         }
         });
   
         function showGameOver()
         {
            ctx.fillStyle = '#ffffff';
            ctx.font = '16px sans-serif';
            ctx.fillText('Game Over!', ((snake_width / 2) - (ctx.measureText('Game Over!').width / 2)), 50);
            ctx.font = '12px sans-serif';
            ctx.fillText('Your Score Was: ' + userscore, ((snake_width / 2) - (ctx.measureText('Your Score Was: ' + userscore).width / 2)), 70);
         }
         });
      </script>
  </head>
  <body>
         <canvas id="SnakeCanvas" width="500" height="500"></canvas>
  </body>
  </html>
  

So, the results of the game can be seen in Figures 2, 3 and 4.

Figure 2. Start screen

Figure 3. The game playing

Figure 4. Game over screen

Conclusion

This article has given you the idea about how to build a game application with HTML5 Canvas and JavaScript. In brief, we learned about canvas, its properties, its coordinate system, and specifically we learned about Game development by an example of snake game.

Hope you liked the article. See you in next article.



Experience: A total 6 years of experience in front end development applications using Html5,CSS3,JavaScript, jQuery, AngularJS..In addition, 6 years of experience in teaching as well. Degree: M.Sc.in Computer Science.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login