Comment créer un jeu Snake en HTML, CSS et JavaScript
Bienvenue 🤗 !
Nous allons créer un jeu très populaire des années 2000 : le célèbre "Snake" que l’on retrouvait sur les Nokia 3210 et 3310.
Nous allons coder ce jeu en HTML, CSS et JavaScript.
Les personnes actuellement dans la quarantaine y ont beaucoup joué.
Mise en place du projet pour créer le jeu Snake
Nous devons créer trois fichiers dans un dossier.
project_game_snake
|-- index.php
|-- style.css
|-- script.js
Remplissez le fichier index.php
C’est le fichier le plus facile à compléter. Nous allons partir d’une structure de base, utiliser une balise <canvas>
pour dessiner jeu et ajouter du code permettant d’importer le fichier CSS ainsi que le fichier script.js
.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Jeu Snake - Nokia 3310</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>Jeu Snake (Nokia 3310)</h1>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<p id="score">Score : 0</p>
<script src="script.js"></script>
</body>
</html>
Serveur local
Pour déployer notre jeu, j’utiliserai un serveur PHP.
C’est justement pour cette raison que j’ai nommé mon fichier `index.php`.
Bien sûr, si vous le souhaitez, vous pouvez utiliser une autre méthode.
Vérifier PHP
Pour vérifier que PHP est correctement installé, ouvrez un terminal et exécutez la commande suivante.
php -v
Si PHP est installé, vous verrez s’afficher un numéro de version.
PHP 8.3.13 (cli)
Sinon, vous devrez installer PHP si vous souhaitez l’utiliser.
Lancer le serveur
Pour démarrer le serveur PHP, ouvrez votre terminal, naviguez jusqu’au dossier contenant vos trois fichiers et exécutez la commande suivante.
php -S "localhost:7777"
Le jeu sera accessible à l’adresse localhost:7777
.
Si le port 7777
est déjà utilisé, choisissez un autre port.
Lancer le jeu
Ouvrez un navigateur et dans la barre d'adresse tapez : localhost:7777
.
Voici le résultat pour le moment.
Remplissez le fichier style.css
Nous allons maintenant rédiger le contenu du fichier de style.
body {
margin: 0;
padding: 0;
background: #222;
font-family: Arial, sans-serif;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
height: 100vh;
}
h1 {
margin-top: 20px;
margin-bottom: 10px;
}
#gameCanvas {
background: #333;
border: 2px solid #fff;
display: block;
margin: 0 auto;
margin-bottom: 10px;
}
#score {
font-size: 1.2rem;
margin-bottom: 20px;
}
Nous avons modifié l'affichage de la balise <body>
, styliser l’écran du jeu et effectuer d’autres ajustements esthétiques.
Résultat
En ouvrant un navigateur et en accédant à localhost:7777
, vous pourrez voir le résultat avec le style.
Remplissez le fichier script.js
Le fichier script.js
est le plus important, car c’est grâce au JavaScript que nous allons véritablement créer le jeu.
Bien que cela soit un peu plus complexe, c’est tout à fait réalisable.
Pour vous accompagner étape par étape, je vais détailler le code.
1 - Les variable à utiliser
Nous allons débuter en définissant certaines variables essentielles.
// Récupérer le canvas et son contexte 2D
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
// Dimensions du canvas
const width = canvas.width;
const height = canvas.height;
// Taille d'une case (chaque segment du serpent et la nourriture font 20px)
const boxSize = 20;
// Vitesse du jeu en millisecondes (100 ms = 10 mises à jour par seconde)
const gameSpeed = 100;
// Le serpent : un tableau d'objets { x, y }
// On initialise le serpent avec un seul segment (la tête)
let snake = [
{ x: 9 * boxSize, y: 10 * boxSize } // Position de départ au milieu du canvas
];
// Direction initiale du serpent
let direction = "RIGHT";
// Score initial
let score = 0;
// Sélection de l'élément HTML pour afficher le score
const scoreDisplay = document.getElementById("score");
// Cette variable contiendra l'intervalle qui appelle régulièrement la fonction du jeu
let game;
2 - Créer la fonction pour dessiner un carré
Pour dessiner le serpent et la nourriture sur le canvas, il faut définir une fonction.
/**
* Dessine un carré de taille boxSize sur le canvas
* @param {number} x - Coordonnée x
* @param {number} y - Coordonnée y
* @param {string} color - Couleur de remplissage
*/
function drawBox(x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, boxSize, boxSize);
}
3 - Générer la génération de nourriture aléatoirement
Le serpent doit se nourrir en mangeant des aliments représentés par un carré, qui apparaissent à des emplacements aléatoires.
/**
* Génère une position aléatoire pour la nourriture
* @returns {Object} { x, y }
*/
function spawnFood() {
return {
x: Math.floor(Math.random() * (width / boxSize)) * boxSize,
y: Math.floor(Math.random() * (height / boxSize)) * boxSize,
};
}
// Génération d’une première nourriture
let food = spawnFood();
4 - Détecter les touches du clavier et changer la direction du serpent
On souhaite que le serpent change de direction quand on appuie sur les touches fléchées (↑, ↓, ←, →). Pour ça, on écoute l’événement keydown et on met à jour notre variable direction.
// Écoute des touches du clavier
document.addEventListener("keydown", changeDirection);
/**
* Change la direction en fonction de la touche appuyée
* @param {KeyboardEvent} e
*/
function changeDirection(e) {
if (e.key === "ArrowLeft" && direction !== "RIGHT") {
direction = "LEFT";
} else if (e.key === "ArrowUp" && direction !== "DOWN") {
direction = "UP";
} else if (e.key === "ArrowRight" && direction !== "LEFT") {
direction = "RIGHT";
} else if (e.key === "ArrowDown" && direction !== "UP") {
direction = "DOWN";
}
}
5 - Vérifier la collision du serpent avec son corps
Pour vérifier si le serpent se mord lui-même, on compare la position de la nouvelle tête avec chacune des cases de son corps. Si les coordonnées sont identiques, c’est une collision.
/**
* Vérifie si la tête du serpent (head) entre en collision
* avec un segment du corps (body).
* @param {Object} head - La nouvelle tête { x, y }
* @param {Array} body - Les segments du serpent
* @returns {boolean} true si collision, false sinon
*/
function collisionWithBody(head, body) {
for (let i = 0; i < body.length; i++) {
if (head.x === body[i].x && head.y === body[i].y) {
return true;
}
}
return false;
}
6 - Écrire la fonction principale drawGame()
Il s’agit de la fonction principale du jeu, appelée de manière récurrente.
Le rôle de cette fonction essentielle
- Effacer le canvas.
- Dessiner la nourriture.
- Mettre à jour les coordonnées du serpent (calcul de la nouvelle tête).
- Vérifier si le serpent mange la nourriture (score + création d’une nouvelle nourriture).
- Retirer la queue du serpent si pas de nourriture mangée.
- Vérifier les collisions (murs et corps).
- Dessiner chaque segment du serpent.
La fonction drawGame()
/**
* Fonction principale qui dessine et met à jour l'état du jeu
*/
function drawGame() {
// 1. Efface le canvas (toute la zone de dessin)
ctx.clearRect(0, 0, width, height);
// 2. Dessiner la nourriture
drawBox(food.x, food.y, "red");
// 3. Coordonnées de la tête du serpent (segment 0)
let snakeX = snake[0].x;
let snakeY = snake[0].y;
// Mise à jour de la position selon la direction
if (direction === "LEFT") snakeX -= boxSize;
if (direction === "RIGHT") snakeX += boxSize;
if (direction === "UP") snakeY -= boxSize;
if (direction === "DOWN") snakeY += boxSize;
// 4. Vérifier si le serpent mange la nourriture
if (snakeX === food.x && snakeY === food.y) {
// Incrémente le score
score++;
scoreDisplay.textContent = `Score : ${score}`;
// Génère une nouvelle nourriture
food = spawnFood();
// Le serpent grandit => on ne retire pas le dernier segment
} else {
// 5. On enlève le dernier segment (la queue) pour simuler le mouvement
snake.pop();
}
// Préparer la nouvelle tête
let newHead = { x: snakeX, y: snakeY };
// 6a. Collision avec les murs ?
if (
snakeX < 0 ||
snakeX >= width ||
snakeY < 0 ||
snakeY >= height
) {
// Fin du jeu
clearInterval(game);
alert(`Game Over ! Votre score est de : ${score}`);
return;
}
// 6b. Collision avec le corps ?
if (collisionWithBody(newHead, snake)) {
// Fin du jeu
clearInterval(game);
alert(`Game Over ! Votre score est de : ${score}`);
return;
}
// On ajoute la nouvelle tête au début du tableau
snake.unshift(newHead);
// 7. Dessiner le serpent
for (let i = 0; i < snake.length; i++) {
// La tête est plus claire (lime), le reste est vert
drawBox(snake[i].x, snake[i].y, i === 0 ? "lime" : "green");
}
}
7 - Démarrer la boucle de jeu
Il ne reste plus qu’à appeler la fonction drawGame()
toutes les gameSpeed
millisecondes. C’est ce qui va faire « tourner » le jeu en continu.
// Lance la boucle du jeu
game = setInterval(drawGame, gameSpeed);
Lancer le jeu Snake de Nokia 3310
Actualisez votre navigateur web (comme Google Chrome, par exemple). Le jeu devrait s’afficher.
Félicitation pour votre travail. 👍