Build a JavaScript Snake Game

The Snake game is a classic and fun project to build using JavaScript. In this guide, we’ll walk through creating a simple Snake game from scratch. We’ll use HTML5 Canvas for rendering and JavaScript for game logic.

What is the Snake Game?

The Snake game involves controlling a snake that moves around the screen. The goal is to eat food to grow longer, while avoiding walls and self-collision. The game ends when the snake hits a wall or itself.

Step 1: Set Up the HTML Structure

First, create an HTML file with a canvas element where the game will be drawn.

<!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>
    <style>
        canvas {
            border: 2px solid black;
        }
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            background-color: #f0f0f0;
        }
        #score {
            font-size: 20px;
            margin: 10px;
        }
    </style>
</head>
<body>
    <div id="score">Score: 0</div>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <script src="snake.js"></script>
</body>
</html>

Step 2: Create the Game Canvas

In the JavaScript file, get the canvas context and set up initial variables.

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');

// Game variables
let snake = [
    { x: 200, y: 200 },
    { x: 190, y: 200 },
    { x: 180, y: 200 }
];
let food = { x: 100, y: 100 };
let direction = 'right';
let score = 0;
let gameLoop;

// Grid size
const gridSize = 10;
const tileCount = canvas.width / gridSize;

Step 3: Handle User Input

Listen for keydown events to change the snake’s direction.

document.addEventListener('keydown', changeDirection);

function changeDirection(event) {
    const LEFT_KEY = 37;
    const RIGHT_KEY = 39;
    const UP_KEY = 38;
    const DOWN_KEY = 40;

    const keyPressed = event.keyCode;
    const goingUp = direction === 'up';
    const goingDown = direction === 'down';
    const goingRight = direction === 'right';
    const goingLeft = direction === 'left';

    if (keyPressed === LEFT_KEY && !goingRight) {
        direction = 'left';
    }
    if (keyPressed === UP_KEY && !goingDown) {
        direction = 'up';
    }
    if (keyPressed === RIGHT_KEY && !goingLeft) {
        direction = 'right';
    }
    if (keyPressed === DOWN_KEY && !goingUp) {
        direction = 'down';
    }
}

Step 4: Implement the Game Loop

The game loop updates the game state at regular intervals.

function gameUpdate() {
    const head = { x: snake[0].x, y: snake[0].y };

    switch(direction) {
        case 'up': head.y -= gridSize; break;
        case 'down': head.y += gridSize; break;
        case 'left': head.x -= gridSize; break;
        case 'right': head.x += gridSize; break;
    }

    // Check for collisions
    if (head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) {
        gameOver();
        return;
    }

    // Check for self-collision
    for (let i = 0; i < snake.length; i++) {
        if (head.x === snake[i].x && head.y === snake[i].y) {
            gameOver();
            return;
        }
    }

    snake.unshift(head);

    // Check if food is eaten
    if (head.x === food.x && head.y === food.y) {
        score += 10;
        scoreElement.textContent = `Score: ${score}`;
        generateFood();
    } else {
        snake.pop();
    }

    gameLoop = setTimeout(gameUpdate, 100);
}

Step 5: Draw the Game

The draw function renders the snake and food on the canvas.

function draw() {
    // Clear canvas
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Draw snake
    snake.forEach((segment, index) => {
        ctx.fillStyle = index === 0 ? 'red' : 'green';
        ctx.fillRect(segment.x, segment.y, gridSize - 2, gridSize - 2);
    });

    // Draw food
    ctx.fillStyle = 'blue';
    ctx.fillRect(food.x, food.y, gridSize - 2, gridSize - 2);
}

Step 6: Generate Food

Generate new food at random positions.

function generateFood() {
    food.x = Math.floor(Math.random() * tileCount) * gridSize;
    food.y = Math.floor(Math.random() * tileCount) * gridSize;
}

Step 7: Game Over

Handle game over scenario.

function gameOver() {
    clearTimeout(gameLoop);
    alert(`Game Over! Score: ${score}`);
    // Reset game
    snake = [
        { x: 200, y: 200 },
        { x: 190, y: 200 },
        { x: 180, y: 200 }
    ];
    direction = 'right';
    score = 0;
    scoreElement.textContent = `Score: ${score}`;
    generateFood();
    gameLoop = setTimeout(gameUpdate, 100);
}

Step 8: Start the Game

Initialize the game by calling the gameUpdate function.

startGame();

function startGame() {
    gameLoop = setTimeout(gameUpdate, 100);
}

Frequently Asked Questions

Q: Why does the snake move automatically?

A: The game loop updates the snake’s position at regular intervals, creating the illusion of movement.

Q: How does the snake grow?

A: Every time the snake eats food, a new segment is added to the front of the snake array without removing the last segment.

Q: Why does the game end when the snake hits itself?

A: Self-collision is detected by checking if the snake’s head collides with any part of its body.

Q: How can I make the game faster or slower?

A: Adjust the setTimeout interval in the gameUpdate function.

Conclusion

You’ve now created a fully functional Snake game using JavaScript and HTML5 Canvas. This project demonstrates fundamental concepts like event handling, game loops, and collision detection. Try modifying the code to add features like different levels, power-ups, or a high score system!

Index
Scroll to Top