Aperçu de l'interface
Snake Game est une réinterprétation complète du jeu classique, développée entièrement
en JavaScript natif sans aucune bibliothèque externe. Le moteur de jeu gère
une boucle d'animation fluide via requestAnimationFrame,
le rendu sur un élément <canvas>,
et une gestion d'états complète (menu, jeu, pause, game over).
Le projet met l'accent sur l'accessibilité multi-plateforme : contrôles clavier
classiques sur desktop, swipe gestuel et D-pad virtuel sur mobile, avec
un layout entièrement responsive dès 320 px.
Extraits de code
<!-- Structure HTML minimaliste — 44 lignes --> <div id="arena"> <canvas id="gameCanvas"></canvas> <div id="overlay"> <div id="overlay-title">SNAKE</div> <div id="overlay-sub">Flèches / WASD<br>ou balayage tactile</div> <button id="btn-start">JOUER</button> </div> </div> <!-- D-Pad mobile —> <div id="dpad"> <div class="dpad-btn" id="btn-up">▲</div> <div class="dpad-btn" id="btn-left">◀</div> <div class="dpad-btn" id="btn-pause">⏸</div> <div class="dpad-btn" id="btn-right">▶</div> <div class="dpad-btn" id="btn-down">▼</div> </div> <script src="game.js"></script>
// ── Constantes de configuration ────────────────────── const GRID = 20; // cellules par côté const BASE_MS = 200; // intervalle initial (ms) const SCORE_PER_APPLE = 10; // × niveau courant const APPLE_PER_LEVEL = 5; // pommes avant niveau+1 const MAX_LEVEL = 10; // ── Boucle de jeu ──────────────────────────────────── function gameLoop(timestamp) { if (timestamp - lastTime < getInterval()) { requestAnimationFrame(gameLoop); return; } lastTime = timestamp; update(); // avance le serpent, détecte collisions render(); // redessine le canvas requestAnimationFrame(gameLoop); } // ── Vitesse progressive selon le niveau ────────────── function getInterval() { return BASE_MS - (level - 1) * 18; } // ── Détection de collision ──────────────────────────── function checkCollision(head) { if (head.x < 0 || head.x >= GRID || head.y < 0 || head.y >= GRID) return true; return snake.some(seg => seg.x === head.x && seg.y === head.y); } // ── Swipe tactile ───────────────────────────────────── arena.addEventListener('touchstart', e => { touchStart = { x: e.touches[0].clientX, y: e.touches[0].clientY }; }); arena.addEventListener('touchend', e => { const dx = e.changedTouches[0].clientX - touchStart.x; const dy = e.changedTouches[0].clientY - touchStart.y; handleSwipe(dx, dy); });
/* Grille centrale responsive */ #arena { position: relative; width: min(90vw, 90vh, 480px); aspect-ratio: 1 / 1; margin: 0 auto; } /* D-pad mobile — disposition en croix */ #dpad { display: grid; grid-template-columns: repeat(3, 52px); grid-template-rows: repeat(3, 52px); gap: 4px; justify-content: center; margin-top: 16px; } /* Masqué sur desktop (pointer: fine) */ @media (pointer: fine) { #dpad { display: none; } } /* Score bar */ #score-bar { display: flex; justify-content: space-around; max-width: min(90vw, 480px); margin: 8px auto; }
Architecture du projet
| Plateforme | Action | Touches |
|---|---|---|
| Desktop | Déplacement | ↑↓←→ / WASD |
| Desktop | Pause | Espace / P |
| Mobile | Déplacement | Swipe sur la grille |
| Mobile | D-pad | Boutons ▲◀⏸▶▼ |
niveau × 10 points par pomme mangéelocalStorage entre les parties
Aucune installation requise. Ouvrir index.html directement dans
un navigateur, ou accéder à la démo GitHub Pages déployée automatiquement.
Points forts techniques
Utilisation de requestAnimationFrame avec
delta-time pour un framerate stable indépendant du matériel. La vitesse du serpent est
contrôlée par un intervalle configurable décroissant avec le niveau.
Support simultané du swipe gestuel sur la grille canvas ET d'un D-pad visuel CSS Grid.
Le D-pad est affiché uniquement sur les appareils tactiles
via @media (pointer: coarse).
Projet 100 % vanilla — aucun framework, aucun bundler, aucun npm. Déploiement immédiat sur GitHub Pages sans pipeline CI/CD. Idéal pour démontrer la maîtrise des API natives du navigateur.