JavaScript Snake Game with Source Code

JavaScript Snake Game with Source Code

The JavaScript Snake Game is created in JavaScript using html and css platform. This Snake Game in JavaScript is a desktop web application. Basically, tutorials and guides for creating code are included in the project. Also, the project provides code creation tutorials and guides. The project is also open source, where users can download and edit zips as required.

This simple mini project for JavaScript snake game code is complete and totally error free and  also includes a downloadable Source Code for free, just find the downloadable source code below and click to start downloading. Before you start to click the download now first you must click the Run Quick Scan for secure Download.

In addition, this snake game using JavaScript is a basic snake game like the typical one that we normally play. Users can switch the controls from their desktop to the left arrow key, right right arrow key, up arrow key and down arrow key. Otherwise, you can lose the match until the snake reaches the boundary.

I have here a suggested list of Best JavaScript Projects with Source Code Free to download and I’m sure this can help you to improve your skills in JavaScript programming and web development as a whole.

Anyway if you want level up your knowledge in programming especially JavaScript Programming, try this new article I’ve made for you Best JavaScript Projects With Source Code For Beginners 2021.

To start creating a Javascript Snake Game with Source Code, make sure that you have any platform in creating a JavaScriptbootstrap, and HTML installed in your computer, in my case I will use Sublime Text.

JavaScript Snake Game with Source Code

Time needed: 5 minutes

Here’s the Steps on how to create a JavaScript Snake Game with Source Code

  • Step 1: Open Sublime Text.

    First, after installing sublime text IDE, click “open” to start.
    Open Sublime For Javascript Snake Game

  • Step 2: Create a HTML file.

    Next, click “file” and select “save as” and named it “index.html
    create index.html for Javascript Snake Game with Source Code

  • Step 3: Create a JavaScript file.

    Then, click “file” and select “save as” and named it “snake.js
    create snake.js for Javascript Snake Game with Source Code

  • Step 4: Create a CSS file.

    Last, click “file” and select “save as” and named it “style.css
    create style.css for Javascript Snake Game with Source Code

  • Step 5: The actual code.

    Finally, You are free to copy the code given below and paste to your different file created.

Code for the index.html in Snake Game in JavaScript

In the code given below, which is the code contains the interface of the application. This code will show the form that will be use in html.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-title" content="Snake Game">
  <title>Itsourcecode Snake Game</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Press+Start+2P">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css">
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div id="app" class="app">
    <div class="start-screen animated bounceIn">
      <h3>Itsourcecode Snake Game</h3>

      <div class="options">
        <h3>Choose Difficulty</h3>
        <p class="end-score"></p>
        <button data-difficulty="100" class="active">Easy</button>
        <button data-difficulty="75">Average</button>
        <button data-difficulty="50">Hard</button>
      </div>

      <button class="play-btn">Play</button>
    </div>

    <canvas></canvas>

    <div class="score">0</div>
  </div>

  <script src="./snake.js"></script>
</body>
</html>

After adding the code, you may test the code. The output should look like as shown below.(Snake Game in Javascript)

Code for the style.css Snake Game in JavaScript

In the code given below, which is the code contains the interface design of the application. This code will show the form that will be use for designing.

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  font: normal 15px 'Press Start 2P', cursive;
  overflow: hidden;
  color: red;
  background: black;
  user-select: none;
}

a {
  text-decoration: none;
}

.app {
  text-align: center;
}

.app .score {
  display: none;
  position: fixed;
  bottom: 0;
  right: 0;
  font-size: 65px;
  padding: 20px;
}

.app .start-screen {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 600px;
  height: 350px;
  margin: -175px 0 0 -300px;
  padding: 25px;
  background: blue;
  color: white;
  border: 5px solid #2B331B;
  z-index: 1;

}

.app .start-screen h2 {
  font-size: 50px;
  margin: 0;
}

.app .start-screen button {
  border: 3px solid #2B331B;
  background: none;
  cursor: pointer;
  color: inherit;
  outline: 0;
}

.app .start-screen button:hover,
.app .start-screen button.active {
  background: green;
  color: #728744;
}

.app .start-screen .options {
  margin-bottom: 40px;
}

.app .start-screen .options h3 {
  margin-bottom: 25px;
}

.app .start-screen .play-btn {
  font-size: 40px;
  padding: 5px 20px;
  text-transform: uppercase
}

/* Game In Progress */
.app.game-in-progress .score {
  display: block;
}

.app.game-in-progress .start-screen {
  display: none;
}

/* Game Over */
.app.game-over canvas {
  opacity: 0.3;
}

/* @Credit: https://github.com/daneden/animate.css/ */
.animated {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}

@-webkit-keyframes bounceIn {
  from,
  20%,
  40%,
  60%,
  80%,
  to {
    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  }

  0% {
    opacity: 0;
    -webkit-transform: scale3d(0.3, 0.3, 0.3);
    transform: scale3d(0.3, 0.3, 0.3);
  }

  20% {
    -webkit-transform: scale3d(1.1, 1.1, 1.1);
    transform: scale3d(1.1, 1.1, 1.1);
  }

  40% {
    -webkit-transform: scale3d(0.9, 0.9, 0.9);
    transform: scale3d(0.9, 0.9, 0.9);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(1.03, 1.03, 1.03);
    transform: scale3d(1.03, 1.03, 1.03);
  }

  80% {
    -webkit-transform: scale3d(0.97, 0.97, 0.97);
    transform: scale3d(0.97, 0.97, 0.97);
  }

  to {
    opacity: 1;
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}

@keyframes bounceIn {
  from,
  20%,
  40%,
  60%,
  80%,
  to {
    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  }

  0% {
    opacity: 0;
    -webkit-transform: scale3d(0.3, 0.3, 0.3);
    transform: scale3d(0.3, 0.3, 0.3);
  }

  20% {
    -webkit-transform: scale3d(1.1, 1.1, 1.1);
    transform: scale3d(1.1, 1.1, 1.1);
  }

  40% {
    -webkit-transform: scale3d(0.9, 0.9, 0.9);
    transform: scale3d(0.9, 0.9, 0.9);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(1.03, 1.03, 1.03);
    transform: scale3d(1.03, 1.03, 1.03);
  }

  80% {
    -webkit-transform: scale3d(0.97, 0.97, 0.97);
    transform: scale3d(0.97, 0.97, 0.97);
  }

  to {
    opacity: 1;
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}

.bounceIn {
  -webkit-animation-duration: 0.75s;
  animation-duration: 0.75s;
  -webkit-animation-name: bounceIn;
  animation-name: bounceIn;
}

Code for the snake.js Snake Game in JavaScript

In the code given below, which is the code contains the interface function of the application. This code will show the form that will be use in html.

class SnakeGame {
  constructor() {
    this.$app = document.querySelector('#app');
    this.$canvas = this.$app.querySelector('canvas');
    this.ctx = this.$canvas.getContext('2d');
    this.$startScreen = this.$app.querySelector('.start-screen');
    this.$score = this.$app.querySelector('.score');

    this.settings = {
      canvas: {
        width: window.innerWidth,
        height: window.innerHeight,
        background: '#000000',
        border: '#000'
      },
      snake: {
        size: 30,
        background: '#FF0000',
        border: '#000'
      }
    };

    this.game = {
      // "direction" (set in setUpGame())
      // "nextDirection" (set in setUpGame())
      // "score" (set in setUpGame())
      speed: 100,
      keyCodes: {
        38: 'up',
        40: 'down',
        39: 'right',
        37: 'left'
      }  
    };

    this.soundEffects = {
      score: new Audio('./sounds/score.mp3'),
      gameOver: new Audio('./sounds/game-over.mp3')
    };

    this.setUpGame();
    this.init();
  }

  init() {
    // Choose difficulty
    // Rather than using "this.$startScreen.querySelectorAll('button')" and looping over the node list
    // and attaching seperate event listeners on each item, it's more efficient to just listen in on the container and run a check at runtime
    this.$startScreen.querySelector('.options').addEventListener('click', event => {
      this.chooseDifficulty(event.target.dataset.difficulty);
    });

    // Play
    this.$startScreen.querySelector('.play-btn').addEventListener('click', () => {
      this.startGame();
    });
  }

  chooseDifficulty(difficulty) {
    if(difficulty) {
      this.game.speed = difficulty;
      this.$startScreen.querySelectorAll('.options button').forEach(btn => btn.classList.remove('active'));
      event.target.classList.add('active');
    }
  }

  setUpGame() {
    // The snake starts off with 5 pieces
    // Each piece is 30x30 pixels
    // Each following piece must be n times as far from the first piece
    const x = 300;
    const y = 300;

    this.snake = [
      { x: x, y: y },
      { x: x - this.settings.snake.size, y: y },
      { x: x - (this.settings.snake.size * 2), y: y },
      { x: x - (this.settings.snake.size * 3), y: y },
      { x: x - (this.settings.snake.size * 4), y: y }
    ];

    this.food = {
      active: false,
      background: '#FFFF00',
      border: '#73AA24',
      coordinates: {
        x: 0,
        y: 0  
      }
    };

    this.game.score = 0;
    this.game.direction = 'right';
    this.game.nextDirection = 'right';
  }

  startGame() {
    // Stop the game over sound effect if a new game was restarted quickly before it could end
    this.soundEffects.gameOver.pause();
    this.soundEffects.gameOver.currentTime = 0;

    // Reset a few things from the prior game
    this.$app.classList.add('game-in-progress');
    this.$app.classList.remove('game-over');
    this.$score.innerText = 0;

    this.generateSnake();

    this.startGameInterval = setInterval(() => {
      if(!this.detectCollision()) {
        this.generateSnake();
      } else {
        this.endGame();
      }
    }, this.game.speed);

    // Change direction
    document.addEventListener('keydown', event => {
      this.changeDirection(event.keyCode);
    });
  }

  changeDirection(keyCode) {
    const validKeyPress = Object.keys(this.game.keyCodes).includes(keyCode.toString()); // Only allow (up|down|left|right)

    if(validKeyPress && this.validateDirectionChange(this.game.keyCodes[keyCode], this.game.direction)) {
      this.game.nextDirection = this.game.keyCodes[keyCode];
    }
  }

  // When already moving in one direction snake shouldn't be allowed to move in the opposite direction
  validateDirectionChange(keyPress, currentDirection) {
    return (keyPress === 'left' && currentDirection !== 'right') || 
      (keyPress === 'right' && currentDirection !== 'left') ||
      (keyPress === 'up' && currentDirection !== 'down') ||
      (keyPress === 'down' && currentDirection !== 'up');
  }

  resetCanvas() {
    // Full screen size
    this.$canvas.width = this.settings.canvas.width;
    this.$canvas.height = this.settings.canvas.height;

    // Background
    this.ctx.fillStyle = this.settings.canvas.background;
    this.ctx.fillRect(0, 0, this.$canvas.width, this.$canvas.height);
  }

  generateSnake() {
    let coordinate;

    switch(this.game.direction) {
      case 'right':
        coordinate = {
          x: this.snake[0].x + this.settings.snake.size,
          y: this.snake[0].y
        };
      break;
      case 'up':
        coordinate = {
          x: this.snake[0].x,
          y: this.snake[0].y - this.settings.snake.size
        };
      break;
      case 'left':
        coordinate = {
          x: this.snake[0].x - this.settings.snake.size,
          y: this.snake[0].y
        };
      break;
      case 'down':
        coordinate = {
          x: this.snake[0].x,
          y: this.snake[0].y + this.settings.snake.size
        };
    }

    // The snake moves by adding a piece to the beginning "this.snake.unshift(coordinate)" and removing the last piece "this.snake.pop()"
    // Except when it eats the food in which case there is no need to remove a piece and the added piece will make it grow
    this.snake.unshift(coordinate);
    this.resetCanvas();

    const ateFood = this.snake[0].x === this.food.coordinates.x && this.snake[0].y === this.food.coordinates.y;

    if(ateFood) {
      this.food.active = false;
      this.game.score += 10;
      this.$score.innerText = this.game.score;
      this.soundEffects.score.play();
    } else {
      this.snake.pop();
    }

    this.generateFood();
    this.drawSnake();
  }

  drawSnake() {
    const size = this.settings.snake.size;

    this.ctx.fillStyle = this.settings.snake.background;
    this.ctx.strokestyle = this.settings.snake.border;

    // Draw each piece
    this.snake.forEach(coordinate => {
      this.ctx.fillRect(coordinate.x, coordinate.y, size, size);
      this.ctx.strokeRect(coordinate.x, coordinate.y, size, size);
    });

    this.game.direction = this.game.nextDirection;
  }

  generateFood() {
    // If there is uneaten food on the canvas there's no need to regenerate it
    if(this.food.active) {
      this.drawFood(this.food.coordinates.x, this.food.coordinates.y);
      return;
    }

    const gridSize = this.settings.snake.size;
    const xMax = this.settings.canvas.width - gridSize;
    const yMax = this.settings.canvas.height - gridSize;

    const x = Math.round((Math.random() * xMax) / gridSize) * gridSize;
    const y = Math.round((Math.random() * yMax) / gridSize) * gridSize;

    // Make sure the generated coordinates do not conflict with the snake's present location
    // If so recall this method recursively to try again
    this.snake.forEach(coordinate => {
      const foodSnakeConflict = coordinate.x == x && coordinate.y == y;

      if(foodSnakeConflict) {
        this.generateFood();
      } else {
        this.drawFood(x, y);
      }
    });
  }

  drawFood(x, y) {
    const size = this.settings.snake.size;

    this.ctx.fillStyle = this.food.background;
    this.ctx.strokestyle = this.food.border;

    this.ctx.fillRect(x, y, size, size);
    this.ctx.strokeRect(x, y, size, size);

    this.food.active = true;
    this.food.coordinates.x = x;
    this.food.coordinates.y = y;
  }

  detectCollision() {
    // Self collison
    // It's impossible for the first 3 pieces of the snake to self collide so the loop starts at 4
    for(let i = 4; i < this.snake.length; i++) {
      const selfCollison = this.snake[i].x === this.snake[0].x && this.snake[i].y === this.snake[0].y;

      if(selfCollison) {
        return true;
      }
    }

    // Wall collison
    const leftCollison = this.snake[0].x < 0;
    const topCollison = this.snake[0].y < 0;
    const rightCollison = this.snake[0].x > this.$canvas.width - this.settings.snake.size;
    const bottomCollison = this.snake[0].y > this.$canvas.height - this.settings.snake.size;

    return leftCollison || topCollison || rightCollison || bottomCollison;
  }

  endGame() {
    this.soundEffects.gameOver.play();

    clearInterval(this.startGameInterval);

    this.$app.classList.remove('game-in-progress');
    this.$app.classList.add('game-over');
    this.$startScreen.querySelector('.options h3').innerText = 'Game Over';
    this.$startScreen.querySelector('.options .end-score').innerText = `Score: ${this.game.score}`;

    this.setUpGame();
  }
}

const snakeGame = new SnakeGame();
ABOUT PROJECTPROJECT DETAILS
Project Name :JavaScript Snake Game
Project Platform :JavaScript
Programming Language Used:php,javascript,html,css
Developer Name :itsourcecode.com
IDE Tool (Recommended):Sublime
Project Type :Web Application
Database:None
Upload Date:February 16, 2021

Downloadable Source Code

Summary

In summary, this 2022 JavaScript Snake Game with Source Code can be useful to students or professional who wants to learn web development using technologies like HTML, CSS and JavaScript. This project can also be modified to fit your personal requirements. Hope this project will help you to improve your skills. Happy coding!

Inquiries

If you have any questions or suggestions about JavaScript Snake Game with Source Code, please feel free to leave a comment below.

Leave a Comment