Creating games with JavaScript isn’t just an engaging project—it’s a valuable way to deepen your understanding of fundamental programming concepts while having a bit of fun. One of the simplest and most classic games to recreate is the Snake game. Despite its age, Snake still presents fascinating logic challenges involving animation, timing, collision detection, and player input. In this article, we’ll guide you through designing a simple version of Snake using HTML, CSS, and JavaScript. Our approach will be modular, structured, and easy to understand for developers with basic JavaScript knowledge.
TL;DR
In this tutorial, you’ll learn how to build a basic Snake game using HTML, CSS, and JavaScript. You’ll set up a canvas, render a snake, place food, and handle game logic like movement and collision detection. This is a solid beginner project that provides insights into game loops, user input handling, and rendering graphics in a web browser. All code is designed to be simple and understandable for new developers.
1. Project Setup
First, we’ll create the basic structure using HTML and style it minimally with CSS. The main part of the application will be a canvas element, which we’ll draw onto using JavaScript.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Simple Snake Game</title>
<style>
canvas {
background-color: #000;
display: block;
margin: 50px auto;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<script src="snake.js"></script>
</body>
</html>
This HTML creates a canvas area with a black background where our game will run.
2. Game Architecture
The main pieces of our Snake game include:
- A grid-based canvas for game rendering
- The snake, which is made up of a series of segments
- Food that appears randomly and increases the length of the snake
- A game loop that updates the screen in intervals
- Input handling to steer the snake with arrow keys
3. JavaScript Game Logic
Now let’s dive into snake.js, the core of the game. We’ll start by declaring some constants and variables to manage the game state.
Initial Setup:
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 20;
const tileCount = canvas.width / gridSize;
let snake = [
{ x: 9, y: 9 },
];
let velocity = { x: 0, y: 0 };
let food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
let score = 0;
4. Drawing the Game
Next, we’ll write a function to draw elements on the canvas including the snake and food.
function drawGame() {
moveSnake();
let gameOver = checkCollision();
if (gameOver) {
alert('Game Over! Final Score: ' + score);
document.location.reload();
return;
}
clearCanvas();
drawFood();
drawSnake();
setTimeout(drawGame, 100);
}
function clearCanvas() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function drawSnake() {
ctx.fillStyle = 'lime';
for (let part of snake) {
ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize - 2, gridSize - 2);
}
}
function drawFood() {
ctx.fillStyle = 'red';
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize - 2, gridSize - 2);
}
5. Movement and Game Logic
Here we implement the logic to move the snake, detect food collection, and manage its length increase.
function moveSnake() {
const head = { x: snake[0].x + velocity.x, y: snake[0].y + velocity.y };
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score++;
food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
} else {
snake.pop();
}
}
6. Input Handling
To control the snake, we listen for key presses and change the snake’s velocity accordingly. This prevents the snake from reversing into itself.
document.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp':
if (velocity.y === 0) velocity = { x: 0, y: -1 };
break;
case 'ArrowDown':
if (velocity.y === 0) velocity = { x: 0, y: 1 };
break;
case 'ArrowLeft':
if (velocity.x === 0) velocity = { x: -1, y: 0 };
break;
case 'ArrowRight':
if (velocity.x === 0) velocity = { x: 1, y: 0 };
break;
}
});
7. Collision Detection
To end the game, we need to check if the snake hits a wall or itself.
function checkCollision() {
const head = snake[0];
// Wall collision
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount)
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;
}
8. Start the Game
To begin the game when the page loads:
drawGame();
That’s it! You now have a working snake game written purely in JavaScript.
9. Possible Enhancements
Once you’ve successfully built the basic game, consider adding the following features:
- Score Display: Show the current score on screen dynamically.
- Levels: Increase snake speed with each food eaten to add difficulty.
- Pause and Restart: Implement buttons to restart or pause the game.
- High Scores: Store and display user high scores using localStorage.
- Mobile Controls: Add on-screen buttons for mobile users.
10. Final Thoughts
Building a Snake game from scratch using JavaScript is not only an excellent hands-on coding project, but also a way to understand key programming concepts like data structures, animation timing, and collision detection in the context of game development. With just HTML, CSS, and JavaScript, you can accomplish a nostalgic yet satisfying game that can be extended with more features as your skills grow. Whether you’re preparing for a frontend role or simply want to build something fun over the weekend, this project provides solid ground for deeper exploration into interactive design and development.
Happy coding—and watch out for those walls!
