Home/Blog/Programming/JavaScript Snake game tutorial: Build a simple, interactive game
JavaScript Snake Game Tutorial
Home/Blog/Programming/JavaScript Snake game tutorial: Build a simple, interactive game

JavaScript Snake game tutorial: Build a simple, interactive game

10 min read
May 05, 2025
content
Basic understanding of JavaScript and HTML.
HTML setup
CSS styling
JavaScript logic
Steps to building a snake game
Step 1: Initialize the game canvas and context
Step 2: Game variables
Step 3: Start/Restart the game
Step 4: Ending the game
Step 5: Direction control
Step 6: Collision detection
Step 7: Eating food
Step 8: Game loop
Step 9: Draw the game
Step 10: Event listeners and initialization
Putting it all together
Wrapping up and resources
Keep reading about JavaScript and web dev

Become a Software Engineer in Months, Not Years

From your first line of code, to your first day on the job — Educative has you covered. Join 2M+ developers learning in-demand programming skills.

Remember the classic Snake game?

Let’s bring it to life with JavaScript!

This tutorial will guide you in building a simple, interactive Snake game using HTML, CSS, and JavaScript. You’ll have a fun game and a better grasp of core web development concepts by the end.

We’ll break the code into three parts: HTML for the structure, CSS for styling, and JavaScript for game logic. The game will be interactive and will include a few cool features, such as:

  • Click to start: The game will prompt you to click the canvas to start or restart the game.

  • Score display: The score will be displayed on the canvas, and the final score will appear when the game ends.

canvasAnimation-image
1 / 3

Basic understanding of JavaScript and HTML. #

Let’s dive in!

HTML setup#

In the index.html file, we will set up the game’s basic structure. We’ll use a <canvas> element for rendering the game and link the external CSS and JavaScript files for styling and logic.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<link rel="stylesheet" href="style.css"> <!-- Link to external CSS file -->
</head>
<body>
<canvas id="gameCanvas" width="600" height="400"></canvas>
<script src="index.js"></script> <!-- Link to external JS file -->
</body>
</html>
The basic HTML structure for the Snake game

In the HTML code above:

  • Lines 7 and 12: We include separate CSS and JavaScript files for a cleaner structure.

  • Line 10: This canvas is the area where the game is drawn.

CSS styling#

The style.css file will contain the basic styling to center the canvas on the screen and give the game a clean look.

body {
text-align: center;
margin: 0;
padding: 0;
background-color: #222;
color: white;
font-family: Arial, sans-serif;
}
canvas {
margin-top: 50px;
border: 2px solid white;
background-color: black;
display: block;
margin-left: auto;
margin-right: auto;
}
Basic CSS to make the game visually appealing

In the CSS file above:

  • Center the canvas: We center the canvas in the middle of the page.

  • Background and text styles:  We set the background and text colors for better contrast.

JavaScript logic#

In the index.js file, we define the game logic, including the snake’s movement, food generation, collision detection, and game state management (e.g., starting, ending, and restarting the game). We also add the functionality to show the score and the “Click to Start” message.

There are certain key features that every snake game has, such as:

  • Snake movement: The snake continuously adds new head segments based on the arrow key input.

  • Food generation: Food is randomly placed on the canvas, and when the snake eats it, the snake grows.

  • Collision detection: The game ends if the snake hits the wall or itself.

  • Score display: The score updates as the snake eats food, and the final score is shown at the end of the game.

Steps to building a snake game#

Let’s implement these key features of a snake game step-by-step:

Step 1: Initialize the game canvas and context#

The first thing we need to do is access the canvas and set up the 2D drawing context. The canvas will be where we draw the snake and food, and the context (ctx) will be used to perform the drawing operations.

// Get the canvas and context
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
Setting up the canvas element and the 2D drawing context

Here, we grab the <canvas> element and set up the 2D drawing context—where all the game visuals (snake, food, score) will be rendered.

Note: If you’re ready to dive even deeper into HTML5 canvas, consider taking your skills to the next level. The “HTML5 Canvas From Noob to Ninja: An Interactive Deep Dive” course on Educative offers a comprehensive exploration of canvas—from advanced drawing techniques to optimizing animations for game development. This interactive course provides hands-on challenges and real-world projects that will help you unlock the full potential of Canvas.

Cover
HTML5 Canvas: From Noob to Ninja - an interactive deep dive

Kirupa is an MIT grad who works at Microsoft as Senior Program Manager. He has been tinkering with web technologies since 1998. He works on the Edge browser team where he gets to sink his teeth into the cutting-edge web technologies. HTML5 is taking over the browsers and one of the coolest things in HTML5 is the canvas - the immediate mode drawing surface you have in HTML for bringing pixels to life using JavaScript. It is used to create games, graphs, and animations. This is an extensive course with interactive playgrounds (so you don't have to install anything). The course can be divided into four parts. 1. Understand basics of Canvas and compare it with DOM. 2. Learn how to draw shapes. 3. Take a deep dive into canvas transformations and animations. 4. Explore advanced mouse and keyboard handling to create truly interactive applications using canvas. If none of what I just wrote makes sense, then the content here is just what you need 😀 . Let's get started.

9hrs
Beginner
62 Playgrounds
109 Illustrations

Step 2: Game variables#

Now, let’s define some essential variables:

  • Grid size: Defines the size of each grid cell (each cell will be a square).

  • Snake: The snake will be represented as an array of objects, each holding a snake segment’s x and y position.

  • Food: The food will be a single object with x and y coordinates.

  • Direction: A direction object will store the current movement direction of the snake (right, left, up, or down).

  • Score: The score will start at 0 and increase when the snake eats food.

  • Game state: We need a flag to indicate if the game is over (isGameOver) and whether the game has started (gameStarted).

const gridSize = 10; // Size of the grid cells
let snake = [{ x: 160, y: 160 }, { x: 150, y: 160 }, { x: 140, y: 160 }];
let food = { x: 420, y: 220 };
let direction = { x: gridSize, y: 0 }; // Initial direction (moving right)
let score = 0;
let gameInterval;
let isGameOver = false;
let gameStarted = false;
Declaring variables to manage the game’s state

In the code above:

  • The gridSize determines the size of each grid cell (10 pixels by 10 pixels).

  • The snake is an array of objects representing the snake’s body. The snake starts with three segments.

  • The food is an object that defines the food’s position on the canvas.

  • The direction controls the snake’s movement. Initially, the snake moves to the right.

  • The score is set to 0 at the beginning.

  • The gameInterval will hold the interval ID for the game loop.

  • The isGameOver and gameStarted help manage the game state.

Step 3: Start/Restart the game#

We need to reset the game variables and begin the game loop to start the game. The game loop will continuously update the game state and redraw the game. We must also clear any previous game state, such as the “Click to Start” message.

// Function to start/restart the game
function startGame() {
// Initialize game variables
snake = [{ x: 160, y: 160 }, { x: 150, y: 160 }, { x: 140, y: 160 }];
food = { x: 420, y: 220 };
direction = { x: gridSize, y: 0 };
score = 0;
isGameOver = false;
gameStarted = true;
clearInterval(gameInterval);
gameInterval = setInterval(gameLoop, 100); // Start the game loop
// Remove any existing "Click to Start" message
drawGame();
}
Resetting the game state

The startGame() function initializes or resets the game variables and starts the game loop using the setInterval() method. The game loop is called every 100 milliseconds, updating the game state and redrawing the canvas. The clearInterval() method clears any previous intervals before starting a new game.

Step 4: Ending the game#

We must implement the endGame() function to handle the game over state. This function stops the game loop and sets the game state to “over.” When a collision is detected, we’ll call this function inside the gameLoop().

// Function to end the game
function endGame() {
clearInterval(gameInterval); // Stop the game loop
isGameOver = true; // Mark the game as over
drawGame(); // Draw the final state (including the "Game Over" message)
}
Stopping the game loop

In the endGame() function:

  • clearInterval(gameInterval); stops the game loop by clearing the interval.

  • isGameOver = true; marks the game over, preventing further game updates.

Step 5: Direction control#

Next, we need to allow the player to control the snake’s direction using the arrow keys. The direction control will only allow the snake to move perpendicularly (no reverse movement).

// Function to handle keyboard input
function changeDirection(event) {
if (isGameOver) return;
if (event.key === 'ArrowUp' && direction.y === 0) {
direction = { x: 0, y: -gridSize };
} else if (event.key === 'ArrowDown' && direction.y === 0) {
direction = { x: 0, y: gridSize };
} else if (event.key === 'ArrowLeft' && direction.x === 0) {
direction = { x: -gridSize, y: 0 };
} else if (event.key === 'ArrowRight' && direction.x === 0) {
direction = { x: gridSize, y: 0 };
}
}
Changing the snake’s direction

The changeDirection() function listens for keydown events and changes the snake’s direction based on which arrow key the user presses. The condition direction.y === 0 ensures that the snake cannot reverse direction. For example, if the snake is moving to the right (x is positive), pressing the left arrow (x becomes negative) will not work because the snake would collide with itself.

Step 6: Collision detection#

To ensure the game behaves correctly, we need to detect when the snake collides with walls or itself. This will stop the game and trigger the game-over state.

// Function to detect collision with walls or self
function detectCollision() {
const head = snake[0];
// Wall collision
if (head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) {
return true;
}
// Self-collision
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
return true;
}
}
return false;
}
Detecting if the snake has collided with the walls or itself

The checkCollision() function verifies if the snake’s head has hit the walls or its body. It checks for the following conditions:

  • If the snake’s head (the first segment in the snake array) goes beyond the canvas boundaries (left, right, top, or bottom).

  • Suppose the snake’s head collides with any body segments (excluding the head itself). If either of these conditions is met, the game ends.

Step 7: Eating food#

When the snake eats food, it should grow, and the score should increase. We must detect if the snake’s head is in the same position as the food.

// Function to handle food consumption
function eatFood() {
const head = snake[0];
if (head.x === food.x && head.y === food.y) {
score+=10;
snake.push({}); // Add new segment to the snake
// Generate new food location
food = {
x: Math.floor(Math.random() * (canvas.width / gridSize)) * gridSize,
y: Math.floor(Math.random() * (canvas.height / gridSize)) * gridSize
};
}
}
Checking if the snake has eaten food

The eatFood() function checks if the snake’s head eats the food.

  • It compares the head’s coordinates (snake[0]) with the food’s coordinates.

  • If the snake eats the food, the score increases by a certain amount (e.g., 10 points).

  • A new segment is added to the snake by pushing a new empty object into the snake array.

  • A new piece of food is placed randomly on the canvas by generating new x and y coordinates for the food.

Step 8: Game loop#

The game loop is the heart of the game. It will continuously update the game state, move the snake, check for collisions, and redraw the game.

// Function to update the game state and redraw the canvas
function gameLoop() {
if (detectCollision()) {
endGame();
return;
}
// Move the snake
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
snake.unshift(head); // Add new head to the snake
eatFood(); // Check if food is eaten
if (!isGameOver) {
snake.pop(); // Remove the last segment of the snake; if not, game over
}
drawGame();
}
Implementing the game loop

The gameLoop() function is called repeatedly by setInterval(). Each time it runs, it updates the game state, moves the snake, checks for collisions and food collisions, and redraws the game on the canvas. The game loop runs at regular intervals (every 100 milliseconds), giving the game smooth movement and continuous updates.

Step 9: Draw the game#

Next, we must draw the game state (snake, food, score) on the canvas each time the game loop runs. This involves clearing the previous drawing and then rendering the updated game elements.

// Function to draw the game on the canvas
function drawGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
// Draw the snake
snake.forEach((segment, index) => {
if (index === 0) {
// Draw the head in red
ctx.fillStyle = 'red';
} else {
// Draw the body in green
ctx.fillStyle = 'green';
}
ctx.fillRect(segment.x, segment.y, gridSize, gridSize);
});
// Draw the food in yellow
ctx.fillStyle = 'yellow';
ctx.beginPath(), ctx.arc(food.x + gridSize / 2, food.y + gridSize / 2, gridSize / 2, 0, Math.PI * 2), ctx.fill();
// Draw the score
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText('Score: ' + score, 10, 30);
// If the game is over, show a message
if (isGameOver) {
ctx.fillStyle = 'white';
ctx.font = '30px Arial';
ctx.fillText('Game Over', canvas.width / 2 - 85, canvas.height / 2);
ctx.font = '20px Arial';
ctx.fillText('Score: ' + score, canvas.width / 2 - 40, canvas.height / 2 + 30); // Show the score
ctx.fillText('Click to Restart', canvas.width / 2 - 75, canvas.height / 2 + 60);
} else if (!gameStarted) {
// If the game has not started, show the "Click to Start" message
ctx.fillStyle = 'white';
ctx.font = '30px Arial';
ctx.fillText('Click to Start', canvas.width / 2 - 85, canvas.height / 2);
}
}
Updating the game canvas as the game progress

The drawGame() function renders the entire game state on the canvas. It is called in every game loop iteration to update the display.

  1. Clear the canvas: Before anything is drawn, the canvas is cleared to remove any previous drawings. This is done with ctx.clearRect(0, 0, canvas.width, canvas.height) to ensure the screen is refreshed.

  2. Draw the snake: The snake is drawn segment by segment. The head is drawn in red, and the body is drawn in green. The fillStyle property is used to set the color, and fillRect() is used to draw a square for each snake segment.

    1. The color for the first segment (head) is set to red: ctx.fillStyle = 'red'.

    2. The remaining segments (body) are green: ctx.fillStyle = 'green'.

  3. Draw the food: The food is drawn as a yellow circle using ctx.arc() at the current coordinates of the food object.

  4. Display the score: The score is displayed in the top left corner of the canvas using ctx.fillText(). The text color is white, and the font size is 20px.

  5. Game over state: If the game is over (isGameOver is true), a “Game Over” message is displayed in the center of the canvas. The current score and a “Click to Restart” message are also shown.

  6. Start game message: If the game hasn’t started yet (gameStarted is false), a “Click to Start” message is shown in the center of the canvas.

Step 10: Event listeners and initialization#

This is the final part of the game setup. We set up event listeners to handle user input and interactions with the game. We also ensure the game starts by initially displaying the “Click to Start” message.

// Event listener for keyboard input
window.addEventListener('keydown', changeDirection);
// Event listener for clicking the canvas to start or restart the game
canvas.addEventListener('click', () => {
if (isGameOver) {
startGame(); // Restart the game if it's over
} else if (!gameStarted) {
startGame(); // Start the game if not started
}
});
// Initialize the game by showing the "Click to Start" message
drawGame();
Event listeners for keyboard input and clicks

We did three things in the code above:

  1. We use an event listener to detect key presses. Specifically, the keydown event is triggered whenever a key is pressed. When this event occurs, the changeDirection() function is called to handle changing the snake’s direction.

  2. An event listener is added to the canvas to detect when the user clicks it. If the game is over (isGameOver is true), clicking the canvas will restart the game by calling the startGame() function. If the game hasn’t started yet (gameStarted is false), the click will start the game.

  3. To initialize the game, we call the drawGame() function. This will show the “Click to Start” message in the center of the canvas when the game begins. The function is also invoked after setting up the event listeners to ensure the initial game state is displayed.

Putting it all together#

Now that we’ve completed each step, it’s time to combine everything into a fully functional Snake game. Below is the complete code that includes all the components we’ve discussed. Click the “Run” button to experience the game:

The complete Snake game

With everything combined, the Snake game is fully functional. You can play by controlling the snake using the arrow keys and clicking the canvas to start or restart the game.

Troubleshooting tip: If nothing is drawing on the canvas, ensure you’ve correctly linked the <script> and <canvas> in your HTML and that your JavaScript file is correctly targeting the canvas ID.

Wrapping up and resources#

Well done! You’ve learned to use JavaScript and HTML to create an interactive game. We hope you enjoyed creating a simple project.

Enjoyed building this game? Keep the momentum going! To help you on this journey, we recommend checking out the Game Development with JavaScript: Creating Tetris. This course will teach you to apply your front-end JavaScript skills to build your first game. By creating Tetris, you’ll learn game development fundamentals and build a project for your portfolio.

Frequently Asked Questions

What is the Snake game?

The Snake game is a classic arcade game where a snake moves around the screen, consuming food and growing in size. The game ends when the snake collides with the walls or itself.

What are the basic requirements for creating a Snake game in JavaScript?

How can I implement a pause feature in a Snake game?

How do I store high scores in a Snake game?


Written By:
Educative

Free Resources