In this part of the tutorial, which is the final one, we’ll add some more logic to the Snake game and add food for the snake to eat.
First we’ll add logic to make sure that the snake can’t go outside the canvas area. We will also add logic so the snake can’t hit any part of it’s body.
Add a new property to the Snake object called dead.
this.dead = false;
Add a check at the first line in the Snake’s logic method. Nothing should happen if the snake has died.
// Nothing should happen if the snake is dead
if(this.dead) {
return;
}
Then add logic to the end of the method. If the snake goes outside the canvas area or if the snake hits any part of it’s body the game is over.
// Keep the snake inside bounds of the canvas area
if(this.x < 0 || this.x + Settings.objSize > Settings.canvasSize || this.y < 0 || this.y + Settings.objSize > Settings.canvasSize) {
this.dead = true;
}
// Prevent snake from hitting any part of it's body
if(this.bodyCollision(this.x, this.y)) {
this.dead = true;
}
We create a new method for the Snake object that checks if any part of the snakes body is at the the x and y position. We loop through all body objects except the head and return true if any object has the same x and y coordinates as the supplied arguments.
// Check if any part of the snakes body is located at x and y
this.bodyCollision = function(x, y) {
for(var i = 0; i < this.bodyObjects.length - 1; i++) {
var obj = this.bodyObjects[i];
if(obj.x === x && obj.y === y) {
return true;
}
}
return false;
};
It’s time to add food. Add a food property to the Game object.
food: null
Add two methods to the Game object: getRandomPosition and spawnFood.
GetRandomPosition returns a random position based on the canvas width and height. SpawnFood creates a new object that represents a food object at a random position. It will also make sure that the snake isn’t located at the position.
// Gets a random position
getRandomPosition: function() {
var xIndex = Settings.canvasSize / Settings.objSize,
yIndex = Settings.canvasSize / Settings.objSize,
x = Math.floor(Math.random()*xIndex) * Settings.objSize,
y = Math.floor(Math.random()*yIndex) * Settings.objSize;
return [x,y];
},
// Spawns a new food object at a random position.
spawnFood: function() {
var pos = this.getRandomPosition();
// Make sure it doesn't spawn on the snake
while(this.snake.collision(pos.x, pos.y) || this.snake.bodyCollision(pos.x, pos.y)) {
pos = this.getRandomPosition();
}
this.food = new Object(pos[0], pos[1], Settings.foodColor);
}
We need to change the logic of the Snake object to check if the snake has eaten a food object. Add a check at the last row of the logic method.
// Check if the snake is at the same location as a food object
if(this.collision(game.food.x, game.food.y)) {
this.hasEatenFood = true;
}
In the beginning of the logic method we reset the property.
this.hasEatenFood = false;
Add code to the Games Logic method to check if the snake has eaten food and generate new food.
if(this.snake.hasEatenFood) {
this.spawnFood();
}
Now we’ll have a look at the draw methods. First in the Game objects draw method add code to draw the food.
this.food.draw(this.context);
Change the Snake objects draw method to look like this. The method returns immediately if the snake is dead. If not a new object is added to the body. Since the body should grow by one if the snake has eaten we only remove an object if hasEatenFood is false.
// Overrides draw method - Draw all the snakes body objects on the screen
this.draw = function(context) {
if(this.dead) {
return;
}
var newObj = new Object(this.x, this.y, Settings.snakeColor), // Get a new object at the snakes current position
objToRemove;
// Add the new object to the snakes body
this.bodyObjects.push(newObj);
// Draw the new object on the screen
newObj.draw(context);
// Erase the last object
if(!this.hasEatenFood) {
objToRemove = this.bodyObjects.shift(); // Remove the last item
objToRemove.erase(context);
}
};
The game should now be more or less complete. Let’s add some final touches. Add a div element with the id message where we’ll display the current score.
<div id="message"></div>
Add a score property to the Game object.
score: 0
Change the Game objects logic method to look like this. We display the current score if the snake has eaten food. If the snake is dead we display Game over.
logic: function() {
this.snake.logic(this);
// Display game over if snake is dead or update score and spawn new food if snake has eaten
if(this.snake.dead) {
this.showMessage('Game over! Score: ' + this.score);
}
else if(this.snake.hasEatenFood) {
this.score += 10;
this.showMessage('Score: ' + this.score);
this.spawnFood();
}
}
Then add a method to the Game object to display messages.
showMessage: function(msg) {
document.getElementById('message').innerHTML = msg;
}
Now let’s add a button to reset the game. Add a button element to the page.
<button id="reset">Reset game</button>
Then add a reset method to the Game object. We clear the current interval reference to stop the main loop and reset score and message. Then we start the game again.
reset: function() {
clearInterval(this.interval);
this.score = 0;
this.showMessage('Score: ' + this.score);
this.start(this.canvas.id);
}
Finally add a handler for the reset button’s click event at the end of the document to reset the game.
document.getElementById('reset').onclick = function() {
Game.reset();
};
The game is now done. View the demo and final code here.