Projet : jeu Snake§

1

Principe§

2

Objectif§

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).

3

Objectif§

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).

4

Représentation interne§

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.

5

Représentation interne§

_images/snake-grid.svg

Exemple de grille.

// 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],
];
6

Représentation interne§

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.

7

Contrôles§

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).

8

Déroulement d'une partie§

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.

  1. Vérifier si l'utilisateur a enfoncé une touche, et modifier la direction du serpent en conséquence (si cela est compatible avec sa direction actuelle).
  2. Calculer la nouvelle position de la tête du serpent en fonction de sa direction.
9

Déroulement d'une partie§

  1. Vérifier si la tête du serpent rencontre de la nourriture, un mur, ou un morceau de son corps.
    • Dans le premier cas, le score augmente, et une autre nourriture est ajoutée dans une case vide aléatoire.
    • Dans les autres cas, la partie se termine.
  2. Mettre à jour le tableau 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.
  3. Effacer intégralement le canvas, et re-dessiner l'état de WORLD. (On pourrait envisager de ne redessiner que les parties qui ont changées, mais cette méthode est plus simple et plus évolutive).
10

Gestion des niveaux§

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}
11

Gestion des niveaux§

La 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.

12

Extensions§

Le cahier des charges ci-dessus est minimaliste. À vous de faire preuve d'originalité en l'étendant. Par exemple :

13

Extensions§

14