The classic Snake game is a fun and interactive way to practice your JavaScript skills. In this tutorial, we’ll build a simple Snake game using HTML, CSS, and JavaScript.
Overview
We’ll create a game where the player controls a snake that moves around the game board, eats food, and grows longer. The game ends if the snake collides with itself.
JavaScript Logic
Create a script.js file and add the following code:
const canvas = document.getElementById('game'); const context = canvas.getContext('2d'); const grid = 20; let count = 0; // Snake object let snake = { x: 160, y: 160, dx: grid, // Horizontal movement dy: 0, // Vertical movement cells: [], // Array of cells occupied by the snake maxCells: 4 // Initial length of the snake }; // Apple object let apple = { x: 320, y: 320 }; // Generate a random position for the apple function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) * grid; } // Game loop function function loop() { requestAnimationFrame(loop); // Slow down the game loop to control the speed if (++count < 4) { return; } count = 0; // Clear the canvas context.clearRect(0, 0, canvas.width, canvas.height); // Move the snake snake.x += snake.dx; snake.y += snake.dy; // Wrap the snake position on the edges (uncomment to enable wall-less mode) // if (snake.x < 0) { // snake.x = canvas.width - grid; // } else if (snake.x >= canvas.width) { // snake.x = 0; // } // if (snake.y < 0) { // snake.y = canvas.height - grid; // } else if (snake.y >= canvas.height) { // snake.y = 0; // } // End the game if the snake hits the wall if (snake.x < 0 || snake.x >= canvas.width || snake.y < 0 || snake.y >= canvas.height) { resetGame(); } // Add the new head position to the beginning of the cells array snake.cells.unshift({ x: snake.x, y: snake.y }); // Remove cells as the snake moves away if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } // Draw the apple context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid - 1, grid - 1); // Draw the snake context.fillStyle = 'lime'; snake.cells.forEach(function (cell, index) { context.fillRect(cell.x, cell.y, grid - 1, grid - 1); // Check if the snake ate the apple if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; // Generate a new apple position apple.x = getRandomInt(0, canvas.width / grid); apple.y = getRandomInt(0, canvas.height / grid); } // Check for collision with the snake itself for (let i = index + 1; i < snake.cells.length; i++) { if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) { resetGame(); } } }); } // Reset the game to the initial state function resetGame() { snake.x = 160; snake.y = 160; snake.dx = grid; snake.dy = 0; snake.cells = []; snake.maxCells = 4; apple.x = getRandomInt(0, canvas.width / grid); apple.y = getRandomInt(0, canvas.height / grid); } // Keyboard event listeners to control the snake document.addEventListener('keydown', function (e) { // Prevent the snake from reversing if (e.key === 'ArrowLeft' && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } else if (e.key === 'ArrowUp' && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } else if (e.key === 'ArrowRight' && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } else if (e.key === 'ArrowDown' && snake.dy === 0) { snake.dy = grid; snake.dx = 0; } }); // Start the game requestAnimationFrame(loop);
Explanation
Variables:
- canvas and context are used to draw on the canvas element.
- grid defines the size of each cell in the game grid.
- count is used to control the game speed.
- snake object holds the snake’s position, direction, body cells, and length.
- apple object holds the apple’s position.
getRandomInt Function:
- Generates a random integer within a specified range, multiplied by grid to align with the grid.
Game Loop (loop Function):
- Uses requestAnimationFrame for smooth animation.
- Controls the game speed by skipping frames.
- Clears the canvas each frame.
- Updates the snake’s position.
- Checks for collisions with walls.
- Adds the new head position to the snake’s body.
- Removes the tail cell if the snake hasn’t grown.
- Draws the apple and the snake.
- Checks for collisions with the apple and the snake’s own body.
resetGame Function:
- Resets the snake and apple to their initial positions and sizes.
Keyboard Controls:
- Listens for arrow key presses to change the snake’s direction.
- Prevents the snake from moving in the opposite direction instantly.
Running the Game
To run the game:
- Save the index.html and script.js files in the same directory.
- Open index.html in a web browser that supports the HTML5 canvas (most modern browsers do).
- Use the arrow keys to control the snake and try to eat as many apples as possible without colliding with the walls or yourself.
Enhancements
Here are some ideas to improve the game:
- Score Tracking: Display the player’s score based on how many apples they’ve eaten.
- Levels and Speed Increase: Increase the game’s speed as the player eats more apples.
- Sound Effects: Add sounds for eating apples and game over events.
- Graphics: Replace the simple squares with images or more intricate graphics.
- High Scores: Implement a high score table using local storage.