L'objectif de votre projet est de créer un clone du jeu Snake (comme celui-ci).
Vous le rendrez sous la forme d'un dépot GIT dont vous fournirez l'URL.
Avertissement
Il existe de nombreux tutoriels en ligne pour créer un jeu de Snake en Javascript.
Il n'est pas interdit de vous en inspirer, mais on attend de vous que vous écriviez votre propre code, pas que vous recopiiez passivement le code du tutoriel.
Notamment, votre note dépendra largement du respect des recommandations ci-dessous (les tutoriels optent généralement pour des solutions différentes).
Votre application comportera au minimum deux "écrans" :
Le passage d'un écran à l'autre doit se faire sans changer d'URL (vous devez donc modifier la page par manipulation du DOM, et non en chargeant une nouvelle page HTML).
L'état du monde est représenté dans un tableau JS à deux dimensions. Chaque cellule du tableau représente une "case" du monde, et indique (par sa valeur) ce ce que contient cette case (mur, serpent, nourriture...). Il vous est recommandé de définir des constantes correspondant à chaque type d'objet, pour améliorer la lisibilité du programme.
// La représentation qu'aurait cette grille en Javascript
let WORLD = [
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, FOOD, EMPTY, EMPTY],
[EMPTY, SNAKE, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, SNAKE, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, SNAKE, SNAKE, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
];
Par ailleurs, l'état du serpent est également représenté par un tableau, dont chaque cellule contient les coordonnées d'une case du serpent. Le début de ce tableau correspond à la queue du serpent, et la fin du tableau correspond à sa tête. Lorsque le serpent se déplace, on ajoutera la nouvelle position de sa tête à la fin (avec la méthode push) et on retirera l'ancienne position de sa queue (avec la méthode shift).
// La représentation qu'aurait le serpent dans la figure ci-dessus.
let SNAKE_BODY = [[4,2], [4,1], [3,1], [2,1]];
L'information sur le serpent est donc stockée de manière redondante dans ces deux tableaux. Cette redondance rendra la gestion du jeu plus simple par la suite.
L'événement keydown
est produit chaque fois que l'utilisateur enfonce une touche.
L'objet événement passé en paramètre du listener possède un attribut key
,
qui représente la touche enfoncée.
Lorsque la touche correspond à un caractère imprimable, key
contient ce caractère.
Sinon, il contient le nom de la touche, comme décrit dans ces tableaux.
En particulier, les flèches sont représentées respectivement par les chaînes
"ArrowDown"
, "ArrowLeft"
, "ArrowRight"
et "ArrowUp"
.
Chaque fois qu'une touche pertinente pour le jeu est enfoncée,
vous mémoriserez dans une variable la valeur de l'attribut key
.
Cette valeur sera utilisée dans la fonction step
(cf. ci-dessous).
Toute la mécanique du jeu sera gérée dans une fonction nommée step
,
qui sera appelée à intervalle régulier, grâce à la fonction setInterval.
Dans cette fonction, vous devrez effectuer les étapes suivantes.
SNAKE_BODY
en faisant avancer le serpent ;
s'il a mangé de la nourriture, son corps doit s'allonger
(ce qui revient à ne pas réduire sa queue).
Mettre également à jour le tableau WORLD
en conséquence.Chaque niveau est décrit par un fichier JSON ayant la structure suivante:
1{
2 "dimensions": [80, 40],
3 "delay": 200,
4 "walls": [
5 [5,5], [5,6], [5,7], [5,8], [70, 35], [71, 35], [72, 35]
6 ],
7 "food": [
8 [10,10]
9 ],
10 "snake": [
11 [60,30],
12 [60,29],
13 [60,28]
14 ]
15
16}
où
dimensions
donne la taille de la grille dans laquelle évolue le serpent,delay
donne le délais (en ms) entre deux appels à la fonction step
,walls
donne la position des cases de mur,food
donne la position initiale de la nourrituresnake
donne la position initiale du serpentLa page de garde doit donner le choix entre plusieurs niveaux ;
lorsque le joueur en choisit un, le fichier JSON correspondant est chargé,
et les variables WORLD
et SNAKE_BODY
sont initialisées conformément.
Le cahier des charges ci-dessus est minimaliste. À vous de faire preuve d'originalité en l'étendant. Par exemple :
Améliorations esthétiques :
- intégrer des sons ;
- utiliser des images bitmaps plutôt que des carrés monochromes ;
- utiliser un canvas WebGL pour représenter le jeu...