Snake Game using HTML, CSS and JavaScript With Source Code

Thumbnail

Introduction :

The Snake Game project is a classic implementation of the iconic Snake arcade game using a combination of HTML, CSS, and JavaScript. This web-based adaptation aims to deliver a nostalgic gaming experience, allowing users to control a snake that grows longer as it consumes randomly placed food items. The project leverages fundamental web technologies to create an interactive and visually engaging game interface. User interaction is facilitated through both keyboard controls and on-screen arrow icons. The player can change the snake’s direction by pressing the arrow keys or by clicking the corresponding arrow icons. This dual-input approach enhances accessibility, catering to users with different preferences.

The HTML file serves as the structural foundation for the Snake Game, defining the layout and key elements. The game board is enclosed within a wrapper, providing a centralized and visually appealing display. Game details, such as the current score and high score, are prominently featured at the top. The play board, where the snake and food elements are dynamically generated, occupies the central portion. Additionally, controls for navigating the snake are represented by arrow icons, enhancing user interaction. The core functionality of the Snake Game is implemented through JavaScript. The game initializes with the snake positioned on the board and the first food item randomly placed. As the game progresses, the snake’s position is updated based on user input or automatic movement. The game dynamically handles collisions, ensuring that the snake grows in length upon consuming food and triggering a game over condition if it collides with the walls or itself. The scoring mechanism is implemented, tracking the player’s score and updating the high score stored in local storage.

Explanation :

HTML Structure:

  • The HTML file defines the structure of the Snake Game. It includes a <div> wrapper that encompasses the entire game interface, providing a central container for the game elements.
  • The <h1> tag with the “Snake Game” title is centered at the top of the wrapper, acting as a prominent heading for the game.
  • The game details section (<div class="game-details">) includes <span> elements for displaying the current score and high score.
  • The actual play board is represented by the <div class="play-board"> element, where the snake and food elements will be dynamically generated.
  • The controls section features four arrow icons (<i>) corresponding to the arrow keys, providing a visual representation of the controls.

CSS Styling:

  • Global styling is applied using the * selector to reset margin, padding, and box-sizing properties, ensuring a consistent appearance across different elements.
  • The overall styling of the game is achieved through a combination of flexbox and grid layout properties. The wrapper employs flex properties to center its contents.
  • The game details section (<div class="game-details">) has a distinctive color scheme, and the text is styled for clarity and visibility.
  • The play board (<div class="play-board">) utilizes a grid layout to create a 30×30 grid for the snake and food elements.
  • Specific styles are applied to the food and snake head elements, differentiating them visually from the background and each other.
  • The controls section (<div class="controls">) is hidden by default but becomes visible on smaller screens, enhancing the game’s responsiveness.

JavaScript Game Logic:

  • JavaScript is responsible for implementing the game’s core logic. The script begins by selecting essential elements from the HTML, such as the play board and score displays.
  • Variables are declared to store information about the game state, including the snake’s position, velocity, and the current score.
  • Functions like updateFoodPosition handle the positioning of the food item, and handleGameOver manages the game-over scenario.
  • The changeDirection function allows users to control the snake’s movement using keyboard input or on-screen arrow buttons.
  • The main game loop (initGame) updates the snake’s position, checks for collisions, handles scoring, and renders the updated game board.
  • Local storage is utilized to store and retrieve the player’s high score between game sessions.

User Interaction:

  • User interaction is facilitated through keyboard controls (arrow keys) and on-screen arrow icons. The changeDirection function captures key presses and adjusts the snake’s velocity accordingly.
  • On-screen arrow icons are associated with the data-key attribute, providing a convenient way to identify the intended direction.

Source Code :

HTML (index.html)

				
					



  
  <title>Snake Game JavaScript</title>
  
  
  
  




  <div class="wrapper">
    
      <h1>Snake Game</h1>
    
    <div class="game-details">
      <span class="score">Score: 0</span>
      <span class="high-score">High Score: 0</span>
    </div>
    <div class="play-board"></div>
    <div class="controls">
      <i data-key="ArrowLeft" class="fa-solid fa-arrow-left-long"></i>
      <i data-key="ArrowUp" class="fa-solid fa-arrow-up-long"></i>
      <i data-key="ArrowRight" class="fa-solid fa-arrow-right-long"></i>
      <i data-key="ArrowDown" class="fa-solid fa-arrow-down-long"></i>
    </div>
  </div>




				
			

CSS (style.css)

				
					
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&amp;display=swap');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Open Sans', sans-serif;
}
body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: #aaaaaa;
}
.wrapper {
  width: 65vmin;
  height: 70vmin;
  display: flex;
  overflow: hidden;
  flex-direction: column;
  justify-content: center;
  border-radius: 5px;
  background: #0854d7;
  box-shadow: 0 20px 40px rgba(52, 87, 220, 0.2);
}
.game-details {
  color: #B8C6DC;
  font-weight: 500;
  font-size: 1.2rem;
  padding: 20px 27px;
  display: flex;
  justify-content: space-between;
}
.play-board {
  height: 100%;
  width: 100%;
  display: grid;
  background: #000000;
  grid-template: repeat(30, 1fr) / repeat(30, 1fr);
}
.play-board .food {
  background: #37ff00;
}
.play-board .head {
  background: #fbff00;
}

.controls {
  display: none;
  justify-content: space-between;
}
.controls i {
  padding: 25px 0;
  text-align: center;
  font-size: 1.3rem;
  color: #B8C6DC;
  width: calc(100% / 4);
  cursor: pointer;
  border-right: 1px solid #171B26;
}

@media screen and (max-width: 800px) {
  .wrapper {
    width: 90vmin;
    height: 115vmin;
  }
  .game-details {
    font-size: 1rem;
    padding: 15px 27px;
  }
  .controls {
    display: flex;
  }
  .controls i {
    padding: 15px 0;
    font-size: 1rem;
  }
}
				
			

JavaScript (script.js)

				
					const playBoard = document.querySelector(".play-board");
const scoreElement = document.querySelector(".score");
const highScoreElement = document.querySelector(".high-score");
const controls = document.querySelectorAll(".controls i");

let gameOver = false;
let foodX, foodY;
let snakeX = 5, snakeY = 5;
let velocityX = 0, velocityY = 0;
let snakeBody = [];
let setIntervalId;
let score = 0;

// Getting high score from the local storage
let highScore = localStorage.getItem("high-score") || 0;
highScoreElement.innerText = `High Score: ${highScore}`;

const updateFoodPosition = () =&gt; {
    // Passing a random 1 - 30 value as food position
    foodX = Math.floor(Math.random() * 30) + 1;
    foodY = Math.floor(Math.random() * 30) + 1;
}

const handleGameOver = () =&gt; {
    // Clearing the timer and reloading the page on game over
    clearInterval(setIntervalId);
    alert("Game Over! Press OK to replay...");
    location.reload();
}

const changeDirection = e =&gt; {
    // Changing velocity value based on key press
    if(e.key === "ArrowUp" &amp;&amp; velocityY != 1) {
        velocityX = 0;
        velocityY = -1;
    } else if(e.key === "ArrowDown" &amp;&amp; velocityY != -1) {
        velocityX = 0;
        velocityY = 1;
    } else if(e.key === "ArrowLeft" &amp;&amp; velocityX != 1) {
        velocityX = -1;
        velocityY = 0;
    } else if(e.key === "ArrowRight" &amp;&amp; velocityX != -1) {
        velocityX = 1;
        velocityY = 0;
    }
}

// Calling changeDirection on each key click and passing key dataset value as an object
controls.forEach(button =&gt; button.addEventListener("click", () =&gt; changeDirection({ key: button.dataset.key })));

const initGame = () =&gt; {
    if(gameOver) return handleGameOver();
    let html = `<div class="food"></div>`;

    // Checking if the snake hit the food
    if(snakeX === foodX &amp;&amp; snakeY === foodY) {
        updateFoodPosition();
        snakeBody.push([foodY, foodX]); // Pushing food position to snake body array
        score++; // increment score by 1
        highScore = score &gt;= highScore ? score : highScore;
        localStorage.setItem("high-score", highScore);
        scoreElement.innerText = `Score: ${score}`;
        highScoreElement.innerText = `High Score: ${highScore}`;
    }
    // Updating the snake's head position based on the current velocity
    snakeX += velocityX;
    snakeY += velocityY;
    
    // Shifting forward the values of the elements in the snake body by one
    for (let i = snakeBody.length - 1; i &gt; 0; i--) {
        snakeBody[i] = snakeBody[i - 1];
    }
    snakeBody[0] = [snakeX, snakeY]; // Setting first element of snake body to current snake position

    // Checking if the snake's head is out of wall, if so setting gameOver to true
    if(snakeX  30 || snakeY  30) {
        return gameOver = true;
    }

    for (let i = 0; i &lt; snakeBody.length; i++) {
        // Adding a div for each part of the snake&#039;s body
        html += `<div class="head"></div>`;
        // Checking if the snake head hit the body, if so set gameOver to true
        if (i !== 0 &amp;&amp; snakeBody[0][1] === snakeBody[i][1] &amp;&amp; snakeBody[0][0] === snakeBody[i][0]) {
            gameOver = true;
        }
    }
    playBoard.innerHTML = html;
}

updateFoodPosition();
setIntervalId = setInterval(initGame, 100);
document.addEventListener("keyup", changeDirection);
				
			

Output :

Output

Find More Projects

Complain Management using Python with a Graphical User Interface (GUI) Introduction: The Complain Management using Python program designed to manage complaints effectively …

COVID 19 Hospital Management Using Python [Django Framework] Introduction: The COVID-19 Hospital Management is a Python-based application that tracks web applications for Hospitals. …

Drawing Ganesha Using Python Turtle Graphics[Drawing Ganapati Using Python] Introduction In this blog post, we will learn how to draw Lord Ganesha …

Contact Management System in Python with a Graphical User Interface (GUI) Introduction: The Contact Management System is a Python-based application designed to …

KBC Game using Python with Source Code Introduction : Welcome to this blog post on building a “Kaun Banega Crorepati” (KBC) game …

Basic Logging System in C++ With Source Code Introduction : It is one of the most important practices in software development. Logging …

More HTML CSS JS Projects
Get Huge Discounts