JavaScript Snake Game Tutorial – Develop a Simple Snake Game

Work on real-time JavaScript Snake game project and become a pro

Snake game is an interesting JavaScript project for beginners. Snake game is a single-player game, which we’ve been playing for a very long time. The game mainly consists of two components – snake and fruit. And we just need to take our snake to the food so that it can eat and grow faster and as the number of fruits eaten increases, the length of snake increases which makes the game more interesting. While moving if the snake eats its own body, then the snake dies and the game ends. Now let’s see how we can create this.

Stay updated with latest technology trends
Join DataFlair on Telegram!!

JavaScript Project Prerequisites

To implement the snake game in JavaScript you should have basic knowledge of:

1. Basic concepts of JavaScript
2. HTML
3. CSS

Download Project Code

Before proceeding ahead please download source code of Snake Game: Snake Game in JavaScript

Steps to Build the Project – JavaScript Snake game

1. Create Html file

HTML builds the basic structure. This file contains some basic HTML tags like div, h1, title, etc. also we’ve used bootstrap (CDN is already included).

index.html:

Code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DataFlair Snake game</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <link rel="stylesheet" href="static/style.css">
</head>
<body>
    <div class="container">
        <div class ="Jumbotron">
        <h1>DataFlair Snake game using vanilla JavaScript</h1>
        
            <h2 class="btn btn-info"> 
                Score: <span class ="score"> 0 </span>
            </h2>
            
            <div class="containerCanvas">
                <canvas id="canvas" width="500" height="500" class="canvasmain"> </canvas>
            </div>
        </div>
    </div>
    <script src="static/fruit.js"></script>
    <script src="static/snake.js"></script>
    <script src="static/draw.js"></script>
</body>
</html>

We have used simple HTML tags except <canvas> tag. This new tag was introduced in HTML5, which is used to draw graphics, via JavaScript. It is nothing without JavaScript so we will use it in our JavaScript file to actually draw the board and the objects required. We’ll see its implementation in JS files.

2. Creating JavaScript file – snake.js

All work will be done by the canvas, so firstly we need to access the <canvas> in our JS file which we can easily do with querySelector.

<canvas> is blank initially, and to display anything, we need to access its context and draw, which is done by the getContext method. This method takes just one parameter, the type of context which is ‘2D’. Then we have created a background for the game using linear-gradient on canvas. Now we define block and calculate the number of rows & columns.

Code:

const canvas = document.querySelector('.canvasmain')
const ctx = canvas.getContext("2d");
const eatSound = new Audio('static/eat.wav')
const hitSound = new Audio('static/hit.wav')
const dirSound = new Audio('static/dir.wav')

//providing bg color
var grd = ctx.createLinearGradient(0,0,500,0)
grd.addColorStop(0,'green');
grd.addColorStop(1,'lightgreen');
ctx.fillStyle = grd;
ctx.fillRect(0,0,500,500); 

//size of one unit or one box
const boxScale = 20; 

//no of rows and columns
const rows = canvas.height/boxScale;
const columns = canvas.width/boxScale;

var snake;

//this calls itself
(function InitialSetUP() {
    snake = new snake();
    fruit = new fruit();
    fruit.locate();
    initialInterval = 200;

    window.setInterval( function(){
        ctx.clearRect(0,0, canvas.width, canvas.height);
        ctx.fillStyle = grd;
        ctx.fillRect(0,0,500,500); 
        fruit.drawFruit();
        snake.move();
        snake.drawSnake();

        if(snake.eat(fruit)){
            fruit.locate();
            initialInterval-=5;
        }

        snake.collision();
        document.querySelector('.score').innerText=snake.score;
    },initialInterval);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
}());

window.addEventListener('keydown', function(event){
    dirSound.play();
    var dir = event.key;
    snake.changeDirection(dir);
});

First function InitialSetUP() calls itself and creates a snake and fruit object which is declared in snake.js and fruit.js files respectively. Then, it calls locate method on fruit which provides a random location to the fruit.

window.setInterval executes its code after every “initialInterval”. We can change this to change the difficulty level of the game. It does all major tasks like moving the snake after the unit time (initialInterval) and checking if the snake eats the fruit and if it does, then locating its new position and checking collision, updating score all these functions are defined in other JS files.

If the snake eats fruit we will decrease the initialInterval by 5 so that the difficulty keeps increasing. And last, we add an event listener to change the direction of the snake on key-down.

3. Creating our next JavaScript file – snake.js

It contains just one function which is a constructor function. A constructor is a function that initializes an object. Similarly, in JavaScript, we have a special constructor function, which is used to initialize an object.

Code:

function snake(){

    //initial position, velocity of snake
    this.x = 0;
    this.y = 0;
    this.xVelocity = boxScale;
    this.yVelocity = 0;
    this.score=0;
    this.tail = [];

    //drawing snake of size boxScale*boxScale
    this.drawSnake = function(){
        ctx.fillStyle = "#fff";

        for(let i=0; i<this.tail.length; i++){
            ctx.fillRect(this.tail[i].x, this.tail[i].y, boxScale, boxScale);
        }
        ctx.fillRect(this.x, this.y, boxScale, boxScale);
    }

    this.move = function() {
        for(let i=0;i<this.tail.length-1;i++){
            this.tail[i]=this.tail[i+1];
        }

        this.tail[this.score - 1] = {x:this.x, y:this.y};

        this.x += this.xVelocity;
        this.y += this.yVelocity;

        //x overfow
        if(this.x >=columns * boxScale )
            this.x=0;
        else if(this.x < 0 )
            this.x=(columns-1) * boxScale;

        //y overfow
        if(this.y >= rows * boxScale)
            this.y=0;
        else if(this.y < 0 )
            this.y=(rows-1) * boxScale;
    }

    this.changeDirection = function(dir) {
        switch(dir) {
            case 'ArrowRight': 
                this.xVelocity = boxScale;
                this.yVelocity = 0;
                break;

            case 'ArrowLeft': 
                this.xVelocity = -1*boxScale;
                this.yVelocity = 0;
                break;

            case 'ArrowUp': 
                this.xVelocity = 0;
                this.yVelocity = -1*boxScale;
                break;

            case 'ArrowDown': 
                this.xVelocity = 0;
                this.yVelocity = boxScale;
        }
    }

    this.eat = function(fruit) {
        if(this.x == fruit.x && this.y == fruit.y){
            this.score++;
            eatSound.play();
            return true;
        }
        return false;
    }

    this.collision = function() {
        for(let i=0;i<this.tail.length;i++)
        {
            if(this.x == this.tail[i].x && this.y == this.tail[i].y)
            {
                this.score=0;
                this.tail=[];
                hitSound.play();
                
            }
        }
    }
}

The constructor function has 6 variables, x and y coordinates of the snake, their velocity, score, and an array storing the snake’s body. Let’s discuss all functions one by one:

1. drawSnake function: It draws the block(s) of the rectangle which we call a snake of white color.

2. move function: It shifts all the elements towards front by one and then adds new head (obtained by adding velocity) which gives the visual effect of moving snake and then, it also checks overflow, and if overflow occurs then it again brings the snake to starting position. If you want you may end the game in case of overflow.

3. changeDirection function: It is a very simple function which just uses a switch statement to identify which key was pressed by the user. It updates the velocities as per the direction, as and when the direction pressed is left y-coordinate will not change and x will move backwards that’s why the ‘-‘ sign and similar in other cases.

4. eat function: It just checks the head of snake and fruit’s location if both coincide, then it updates the score, plays the required sound, and returns true, otherwise false.

5. collision function: It checks if the snake at any point eats its own body and if so it resets the score, snake body, and plays game over sound. It checks this by running a loop and checking the position of every block of the body with the snake’s head.

4. Creating last JavaScript file – fruit.js

This file also contains just one function which is a constructor function which creates a fruit object.

Code:

function fruit() {
    this.x;
    this.y;

    this.locate= function(){
        this.x = (Math.floor(Math.random() * columns-1) + 1)*boxScale;
        this.y = (Math.floor(Math.random() * rows-1) + 1)*boxScale;
    }

    this.drawFruit = function() {
        ctx.fillStyle = "#f00"
        ctx.fillRect(this.x, this.y, boxScale, boxScale);
    }
}

There is nothing much to be performed by a fruit object as we can see the file hardly contains 10 lines of code, okay okay 11. Coming back to the point, it has two variables, the 2 coordinates and just two functions.

1. locate function: This function just calculates 2 random positions in the grid using Math.random() function and stores it in the variable.

2. drawfruit function: It draws the fruit (1 x 1 square ) at the position pre-calculated by locate() with the help of fillRect function.

We do not need a separate CSS file because all the designing work is already done by <canvas> which is its biggest advantage. Thus we have successfully implemented such an interesting project in 4 easy steps. Now you can play your own snake game:

snake game

Summary

In this article, we have developed snake game with JavaScript and HTML. Although snake game is a simple javascript project but it’s good for beginners for practice.

Leave a Reply

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.