Créer un jeu de serpent avec javascript
Snake est un jeu classique auquel des millions de personnes ont joué. Avez-vous déjà pensé à créer votre propre Snake Game ? Créer un jeu de serpent en utilisant HTML, CSS et JavaScript vanille est un projet amusant et éducatif qui peut améliorer vos compétences en développement Web.
Dans cet article de blog, je vais vous guider à travers les étapes de création de votre propre jeu de serpent à partir de zéro. Vous pouvez jouer à ce jeu sur un PC à l'aide des touches fléchées du clavier ou sur un appareil mobile à l'aide des touches fléchées tactiles.
Faire un jeu de serpent n'est pas seulement amusant, mais cela peut également vous aider à développer des compétences en résolution de problèmes et la capacité de décomposer des problèmes complexes en plus petits.
Codes Sources
Code HTML
Pour commencer, ajoutez les codes HTML suivants à votre fichier index.html pour créer la mise en page de base du jeu. Le conteneur "play-board" est vide maintenant, mais il sera rempli de corps de serpent et d'éléments alimentaires plus tard en utilisant du code JavaScript
<div class="wrapper">
<div class="game-details">
<span class="score">Score: 0</span>
<span class="high-score">Meilleur score: 0</span>
</div>
<div class="play-board"></div>
<div class="controls">
<i data-key="ArrowLeft" class="fa-solid fa-arrow-left-long"></i>
<i data-key="ArrowUp" class="fa-solid fa-arrow-up-long"></i>
<i data-key="ArrowRight" class="fa-solid fa-arrow-right-long"></i>
<i data-key="ArrowDown" class="fa-solid fa-arrow-down-long"></i>
</div>
</div>
Code CSS
Ensuite, ajoutez les codes CSS suivants à votre fichier style.css pour créer la mise en page du jeu Snake. N'oubliez pas que les touches fléchées de contrôle ne sont affichées que sur les petits appareils, tels que les téléphones. Si vous préférez les afficher sur tous les appareils, vous pouvez facilement modifier le code de requête multimédia.
/*Google font */ @import url('https://fonts.googleapis.com/css2?family=Open+Sans:[email protected];500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #E3F2FD;
}
.wrapper {
width: 65vmin;
height: 70vmin;
display: flex;
overflow: hidden;
flex-direction: column;
justify-content: center;
border-radius: 5px;
background: #293447;
box-shadow: 0 20px 40px rgba(52, 87, 220, 0.2);
}
.game-details {
color: #B8C6DC;
font-weight: 500;
font-size: 1.2rem;
padding: 20px 27px;
display: flex;
justify-content: space-between;
}
.play-board {
height: 100%;
width: 100%;
display: grid;
background: #212837;
grid-template: repeat(30, 1fr) / repeat(30, 1fr);
}
.play-board .food {
background: #FF003D;
}
.play-board .head {
background: #60CBFF;
}
.controls {
display: none;
justify-content: space-between;
}
.controls i {
padding: 25px 0;
text-align: center;
font-size: 1.3rem;
color: #B8C6DC;
width: calc(100% / 4);
cursor: pointer;
border-right: 1px solid #171B26;
}
@media screen and (max-width: 800px) {
.wrapper {
width: 90vmin;
height: 115vmin;
}
.game-details {
font-size: 1rem;
padding: 15px 27px;
}
.controls {
display: flex;
}
.controls i {
padding: 15px 0;
font-size: 1rem;
}
}
Code JavaScript
Enfin, ajoutez le code JavaScript suivant à votre fichier script.js pour ajouter des fonctionnalités pour le jeu du serpent. Ce code gérera la logique derrière le mouvement du serpent, manger de la nourriture, mettre à jour le score et détecter les collisions avec les murs ou son propre corps
const playBoard = document.querySelector(".play-board");
const scoreElement = document.querySelector(".score");
const highScoreElement = document.querySelector(".high-score");
const controls = document.querySelectorAll(".controls i");
let gameOver = false;
let foodX, foodY;
let snakeX = 5, snakeY = 5;
let velocityX = 0, velocityY = 0;
let snakeBody = [];
let setIntervalId;
let score = 0;
// Obtenir le meilleur score dans le localstorage
let highScore = localStorage.getItem("high-score") || 0;
highScoreElement.innerText = `Meilleure score: ${highScore}`;
const updateFoodPosition = () => {
// Passer de 1 - 30 aléatoirement
foodX = Math.floor(Math.random() * 30) + 1;
foodY = Math.floor(Math.random() * 30) + 1;
}
const handleGameOver = () => {
// Supprimer le score actuelle et afficher le popup
clearInterval(setIntervalId);
alert("GAME OVER 😭😂");
location.reload();
}
const changeDirection = e => {
// Les touches d'ordinateur
if(e.key === "ArrowUp" && velocityY != 1) {
velocityX = 0;
velocityY = -1;
} else if(e.key === "ArrowDown" && velocityY != -1) {
velocityX = 0;
velocityY = 1;
} else if(e.key === "ArrowLeft" && velocityX != 1) {
velocityX = -1;
velocityY = 0;
} else if(e.key === "ArrowRight" && velocityX != -1) {
velocityX = 1;
velocityY = 0;
}
}
// Appel de changeDirection à chaque clic de touche et transmission de la valeur de l'ensemble de données clés en tant qu'objet
controls.forEach(button => button.addEventListener("click", () => changeDirection({ key: button.dataset.key })));
const initGame = () => {
if(gameOver) return handleGameOver();
let html = `<div class="food" style="grid-area: ${foodY} / ${foodX}"></div>`;
// Vérifier si le serpent à mangé la nourriture
if(snakeX === foodX && snakeY === foodY) {
updateFoodPosition();
snakeBody.push([foodY, foodX]); // Pousser la position de la nourriture vers le corps du serpent
score++; // augmenter le score de 1
highScore = score >= highScore ? score : highScore;
localStorage.setItem("high-score", highScore);
scoreElement.innerText = `Score: ${score}`;
highScoreElement.innerText = `Meilleure score: ${highScore}`;
}
// Mise à jour de la position de la tête du serpent en fonction de la vitesse actuelle
snakeX += velocityX;
snakeY += velocityY;
// Décaler d'une unité les valeurs des éléments du corps du serpent
for (let i = snakeBody.length - 1; i > 0; i--) {
snakeBody[i] = snakeBody[i - 1];
}
snakeBody[0] = [snakeX, snakeY]; // Réglage du premier élément du corps du serpent à la position actuelle du serpent
// Vérifier si la tête du serpent est hors du mur, si c'est le cas, régler gameOver sur true
if(snakeX <= 0 || snakeX > 30 || snakeY <= 0 || snakeY > 30) {
return gameOver = true;
}
for (let i = 0; i < snakeBody.length; i++) {
// Ajout d'un div pour chaque partie du corps du serpent
html += `<div class="head" style="grid-area: ${snakeBody[i][1]} / ${snakeBody[i][0]}"></div>`;
// Vérifier si la tête de serpent a touché le corps, si c'est le cas, définissez gameOver sur true
if (i !== 0 && snakeBody[0][1] === snakeBody[i][1] && snakeBody[0][0] === snakeBody[i][0]) {
gameOver = true;
}
}
playBoard.innerHTML = html;
}
updateFoodPosition();
setIntervalId = setInterval(initGame, 100);
document.addEventListener("keyup", changeDirection);
Dans le code, vous pouvez voir que la vitesse actuelle du serpent est de 100 millisecondes, ce qui détermine la vitesse à laquelle le serpent se déplace sur le plateau de jeu. Vous pouvez facilement ajuster cette vitesse en modifiant la valeur dans la fonction "setInterval" en bas du code.
En suivant les étapes de cet article de blog, vous avez créé avec succès un jeu de serpent classique utilisant HTML, CSS et JavaScript auquel vous pouvez jouer sur n'importe quel navigateur d'appareil. J'espère que ce projet de jeu de serpent vous aidera à comprendre la manipulation du DOM, les compétences en résolution de problèmes et d'autres compétences en développement Web.
Si vous avez aimé créer votre jeu de serpent et appris quelque chose de nouveau, alors n'hésitez pas à commenter ou à lâcher une réaction en bas de ce post.
Ces jeux sont non seulement agréables à créer, mais offrent également une excellente occasion de pratiquer et d'améliorer vos compétences en JavaScript.
Si vous rencontrez des problèmes ou si votre code ne fonctionne pas comme prévu, vous pouvez copier le code complet disponible ci-dessous
Code complète
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Jeux Serpent</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
</head>
<style>
/*Google font */ @import url('https://fonts.googleapis.com/css2?family=Open+Sans:[email protected];500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #E3F2FD;
}
.wrapper {
width: 65vmin;
height: 70vmin;
display: flex;
overflow: hidden;
flex-direction: column;
justify-content: center;
border-radius: 5px;
background: #293447;
box-shadow: 0 20px 40px rgba(52, 87, 220, 0.2);
}
.game-details {
color: #B8C6DC;
font-weight: 500;
font-size: 1.2rem;
padding: 20px 27px;
display: flex;
justify-content: space-between;
}
.play-board {
height: 100%;
width: 100%;
display: grid;
background: #212837;
grid-template: repeat(30, 1fr) / repeat(30, 1fr);
}
.play-board .food {
background: #FF003D;
}
.play-board .head {
background: #60CBFF;
}
.controls {
display: none;
justify-content: space-between;
}
.controls i {
padding: 25px 0;
text-align: center;
font-size: 1.3rem;
color: #B8C6DC;
width: calc(100% / 4);
cursor: pointer;
border-right: 1px solid #171B26;
}
@media screen and (max-width: 800px) {
.wrapper {
width: 90vmin;
height: 115vmin;
}
.game-details {
font-size: 1rem;
padding: 15px 27px;
}
.controls {
display: flex;
}
.controls i {
padding: 15px 0;
font-size: 1rem;
}
}
</style>
<body>
<div class="wrapper">
<div class="game-details">
<span class="score">Score: 0</span>
<span class="high-score">Meilleur score: 0</span>
</div>
<div class="play-board"></div>
<div class="controls">
<i data-key="ArrowLeft" class="fa-solid fa-arrow-left-long"></i>
<i data-key="ArrowUp" class="fa-solid fa-arrow-up-long"></i>
<i data-key="ArrowRight" class="fa-solid fa-arrow-right-long"></i>
<i data-key="ArrowDown" class="fa-solid fa-arrow-down-long"></i>
</div>
</div>
<script>
const playBoard = document.querySelector(".play-board");
const scoreElement = document.querySelector(".score");
const highScoreElement = document.querySelector(".high-score");
const controls = document.querySelectorAll(".controls i");
let gameOver = false;
let foodX, foodY;
let snakeX = 5, snakeY = 5;
let velocityX = 0, velocityY = 0;
let snakeBody = [];
let setIntervalId;
let score = 0;
// Obtenir le meilleur score dans le localstorage
let highScore = localStorage.getItem("high-score") || 0;
highScoreElement.innerText = `Meilleure score: ${highScore}`;
const updateFoodPosition = () => {
// Passer de 1 - 30 aléatoirement
foodX = Math.floor(Math.random() * 30) + 1;
foodY = Math.floor(Math.random() * 30) + 1;
}
const handleGameOver = () => {
// Supprimer le score actuelle et afficher le popup
clearInterval(setIntervalId);
alert("GAME OVER 😭😂");
location.reload();
}
const changeDirection = e => {
// Les touches d'ordinateur
if(e.key === "ArrowUp" && velocityY != 1) {
velocityX = 0;
velocityY = -1;
} else if(e.key === "ArrowDown" && velocityY != -1) {
velocityX = 0;
velocityY = 1;
} else if(e.key === "ArrowLeft" && velocityX != 1) {
velocityX = -1;
velocityY = 0;
} else if(e.key === "ArrowRight" && velocityX != -1) {
velocityX = 1;
velocityY = 0;
}
}
// Appel de changeDirection à chaque clic de touche et transmission de la valeur de l'ensemble de données clés en tant qu'objet
controls.forEach(button => button.addEventListener("click", () => changeDirection({ key: button.dataset.key })));
const initGame = () => {
if(gameOver) return handleGameOver();
let html = `<div class="food" style="grid-area: ${foodY} / ${foodX}"></div>`;
// Vérifier si le serpent à mangé la nourriture
if(snakeX === foodX && snakeY === foodY) {
updateFoodPosition();
snakeBody.push([foodY, foodX]); // Pousser la position de la nourriture vers le corps du serpent
score++; // augmenter le score de 1
highScore = score >= highScore ? score : highScore;
localStorage.setItem("high-score", highScore);
scoreElement.innerText = `Score: ${score}`;
highScoreElement.innerText = `Meilleure score: ${highScore}`;
}
// Mise à jour de la position de la tête du serpent en fonction de la vitesse actuelle
snakeX += velocityX;
snakeY += velocityY;
// Décaler d'une unité les valeurs des éléments du corps du serpent
for (let i = snakeBody.length - 1; i > 0; i--) {
snakeBody[i] = snakeBody[i - 1];
}
snakeBody[0] = [snakeX, snakeY]; // Réglage du premier élément du corps du serpent à la position actuelle du serpent
// Vérifier si la tête du serpent est hors du mur, si c'est le cas, régler gameOver sur true
if(snakeX <= 0 || snakeX > 30 || snakeY <= 0 || snakeY > 30) {
return gameOver = true;
}
for (let i = 0; i < snakeBody.length; i++) {
// Ajout d'un div pour chaque partie du corps du serpent
html += `<div class="head" style="grid-area: ${snakeBody[i][1]} / ${snakeBody[i][0]}"></div>`;
// Vérifier si la tête de serpent a touché le corps, si c'est le cas, définissez gameOver sur true
if (i !== 0 && snakeBody[0][1] === snakeBody[i][1] && snakeBody[0][0] === snakeBody[i][0]) {
gameOver = true;
}
}
playBoard.innerHTML = html;
}
updateFoodPosition();
setIntervalId = setInterval(initGame, 100);
document.addEventListener("keyup", changeDirection);
</script>
</body>
</html>
2 commentaires