How to create a Simple Snake Game in the Browser with HTML, CSS, and JavaScript
In the world of web development, the possibilities are endless. From building static websites to crafting complex web applications, developers have the tools and technologies at their disposal to create virtually anything.
One popular genre of web-based games that has been captivating audiences for decades is the classic Snake game. In this article, we will embark on a journey to create a simple yet engaging Snake game using HTML, CSS, and JavaScript.
The Snake game, originally introduced in the late 1970s, has remained a staple in the world of gaming. Its simplicity and addictive nature make it an ideal choice for beginners looking to gain hands-on experience in web development.
By the end of this tutorial, you will have a fully functional Snake game that you can share with your friends and family.
Setting the Stage: The Basics
Before we dive into the coding aspects of building our Snake game, let’s establish a clear understanding of what we’re trying to create.
In a Snake game, the player controls a snake that moves around the screen. The goal is to collect food items, which appear at random locations, to increase the snake’s length. The game continues until the snake collides with itself or the game boundaries.
Prerequisites
To follow along with this tutorial, you will need the following:
- A code editor (e.g., Visual Studio Code, Sublime Text, or any text editor of your choice).
- A modern web browser (e.g., Google Chrome, Mozilla Firefox, or Microsoft Edge).
- Basic knowledge of HTML, CSS, and JavaScript.
Building the HTML Structure
Our Snake game will start with a simple HTML structure. We’ll create a container for the game canvas, a score display, and a play button.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Snake Game</title>
</head>
<body>
<div class="game-container">
<div class="score">Score: 0</div>
<button class="play-button">Play</button>
<canvas id="gameCanvas" width="400" height="400"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
In this HTML structure, we have included a game-container
div that houses the game elements. The game canvas is represented by the <canvas>
element with the ID gameCanvas
. We also have a score display and a play button that we’ll implement later in the JavaScript code.
Styling the Game with CSS
Before we jump into the JavaScript code to make our Snake game functional, let’s add some CSS to make it visually appealing. Create a styles.css
file and link it to your HTML file.
/* styles.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.game-container {
text-align: center;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}
.score {
font-size: 24px;
margin-bottom: 10px;
}
.play-button {
background-color: #4CAF50;
color: white;
font-size: 18px;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.play-button:hover {
background-color: #45a049;
}
In this CSS code, we have styled the game container, score display, and play button. The background color, font styles, and button appearance can be customized to your preference.
Implementing the Snake Game Logic in JavaScript
Now comes the most exciting part—implementing the game logic using JavaScript. Create a script.js
file and link it to your HTML file.
// script.js
// Constants
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const gridSize = 20;
const tileSize = canvas.width / gridSize;
const initialSnakeLength = 5;
// Snake variables
let snake = [
{ x: 5, y: 5 },
// Initial snake segments
];
let dx = 1; // Initial movement direction (1: right, -1: left, 0: no movement)
let dy = 0;
let food = { x: 10, y: 10 }; // Initial food location
let score = 0;
let isPlaying = false;
let gameInterval;
// Event listeners
document.addEventListener("keydown", changeDirection);
document.querySelector(".play-button").addEventListener("click", startGame);
// Functions
function drawSnake() {
for (let i = 0; i < snake.length; i++) {
ctx.fillStyle = i === 0 ? "green" : "limegreen";
ctx.fillRect(snake[i].x * tileSize, snake[i].y * tileSize, tileSize, tileSize);
ctx.strokeStyle = "white";
ctx.strokeRect(snake[i].x * tileSize, snake[i].y * tileSize, tileSize, tileSize);
}
}
function drawFood() {
ctx.fillStyle = "red";
ctx.fillRect(food.x * tileSize, food.y * tileSize, tileSize, tileSize);
}
function moveSnake() {
const headX = snake[0].x + dx;
const headY = snake[0].y + dy;
// Check for collision with food
if (headX === food.x && headY === food.y) {
score += 10;
document.querySelector(".score").textContent = `Score: ${score}`;
generateFood();
} else {
// Remove the tail segment
snake.pop();
}
// Add new head segment
const newHead = { x: headX, y: headY };
snake.unshift(newHead);
// Check for collisions with walls or itself
if (
headX < 0 ||
headY < 0 ||
headX >= gridSize ||
headY >= gridSize ||
checkSelfCollision()
) {
gameOver();
}
}
function checkSelfCollision() {
for (let i = 1; i < snake.length; i++) {
if (snake[i].x === snake[0].x && snake[i].y === snake[0].y) {
return true;
}
}
return false;
}
function generateFood() {
food = {
x: Math.floor(Math.random() * gridSize),
y: Math.floor(Math.random() * gridSize),
};
}
function changeDirection(event) {
const keyCode = event.keyCode;
switch (keyCode) {
case 37: // Left
if (dx === 0) {
dx = -1;
dy = 0;
}
break;
case 38: // Up
if (dy === 0) {
dx = 0;
dy = -1;
}
break;
case 39: // Right
if (dx === 0) {
dx = 1;
dy = 0;
}
break;
case 40: // Down
if (dy === 0) {
dx = 0;
dy = 1;
}
break;
}
}
function startGame() {
if (!isPlaying) {
isPlaying = true;
snake = [
{ x: 5, y: 5 },
// Initial snake segments
];
dx = 1;
dy = 0;
score = 0;
document.querySelector(".score").textContent = `Score: ${score}`;
generateFood();
gameInterval = setInterval(playGame, 100);
}
}
function playGame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawSnake();
drawFood();
moveSnake();
}
function gameOver() {
clearInterval(gameInterval);
isPlaying = false;
alert(`Game over! Your score: ${score}`);
}
Let’s break down the JavaScript code:
- We start by defining constants, variables, and event listeners.
drawSnake
anddrawFood
functions are responsible for rendering the snake and food on the canvas.moveSnake
function handles the logic for moving the snake, checking for collisions, and increasing the score.- The
changeDirection
function allows the player to change the snake’s direction using arrow keys. startGame
initiates the game when the play button is clicked, resetting all variables and starting the game loop.- The
playGame
function is called repeatedly to update the game state and redraw the canvas. gameOver
is called when the game ends, clearing the interval and displaying the final score.
Styling the Snake and Food
You might have noticed that we’re using colors like “green” and “red” to represent the snake and food, respectively. To enhance the visual appeal, you can add some CSS rules to style the snake segments and food.
/* styles.css */
/* ... (previous CSS rules) */
/* Snake segments */
.game-container .snake {
background-color: green;
}
/* Food item */
.game-container .food {
background-color: red;
}
To apply these styles to our Snake game, we need to update the drawSnake
and drawFood
functions in the JavaScript code.
// Modify the drawSnake function
function drawSnake() {
for (let i = 0; i < snake.length; i++) {
const snakeSegment = document.createElement("div");
snakeSegment.className = i === 0 ? "snake head" : "snake";
snakeSegment.style.left = snake[i].x * tileSize + "px";
snakeSegment.style.top = snake[i].y * tileSize + "px";
document.querySelector(".game-container").appendChild(snakeSegment);
}
}
// Modify the drawFood function
function drawFood() {
const foodItem = document.createElement("div");
foodItem.className = "food";
foodItem.style.left = food.x * tileSize + "px";
foodItem.style.top = food.y * tileSize + "px";
document.querySelector(".game-container").appendChild(foodItem);
}
With these changes, the snake and food items will be styled using CSS classes, allowing you to apply more complex styles and animations if desired.
Conclusion
Congratulations! You’ve successfully created a simple Snake game using HTML, CSS, and JavaScript. This project not only serves as an excellent introduction to web game development but also provides a foundation for expanding and customizing the game further.
As you continue your journey in web development, consider enhancing the game with additional features like levels, high scores, and responsive design. You can also explore more advanced game development techniques and libraries to create more complex and visually stunning games.
Remember that practice is key in mastering web development, so don’t hesitate to experiment and build upon the foundation you’ve created here. Happy coding, and have fun playing your Snake game!
Photo by Florian Olivo on Unsplash