TP1 2020-2021 L3 Miage JavaScript

De $1

Version de 15:59, 16 Avr 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Introduction

 

Dans ce TP vous allez coder le squelette d'un jeu de type Mach-3 (à la Candy Crush). Nous verrons deux implémentations:

  1. La première, recommandée dans un premier temps pour tout le monde, utilise le DOM, des éléments HTML <div> et <img> pour afficher les différentes pièces du jeu et interagir avec elles. C'est celle que je recommande aux débutants en JavaScript. On pourra déplacer les pièces (les "swapper") à l'aide de clicks souris ou du drag'n'drop.

     
  2. La seconde utilise le <canvas> de HTML5 et de l'animation à 60 images secondes. C'est cette méthode que je recommande à ceux qui connaissent déjà JavaScript, elle est un peu plus challengeante :-) Mais permettra de faire des animations plus fluides, au pixel près, notamment lors des chutes de pièces, des animations d'explosions etc. Avant de vous attaquer à cette méthode, essayez de faire la première.

TP méthode 1, à l'aide de l'API du DOM

Installation d'un squelette du jeu, analyse du code

Travail à faire :

  1. Récupérer cette archive, la dezipper,
  2. Ouvrir Visual Studio code sur le projet,
  3. Ouvrir le fichier index.html et click droit "Ouvrir avec Live Server", cela doit lancer le projet dans un onglet de votre navigateur.
  4. Etudier le code, notamment le code CSS, pour comprendre comment on a codé en CSS le dessin de la grille, et les effets de surlignage et zoom sur les deux images codées en dur dans le fichier index.html
  5. Regarder le contenu des fichiers JavaScript, notamment de script.js, qui contient le programme principal (fonction init)
  6. Regardez où se trouvent les images (dossier assets/images), et regardez les images ! On trouve parmi elles six types de cookies ! Et pour chaque Cookie on a trois versions : un petite image, un grosse @2x et une surlignée ("highlighted").

Coder une classe pour décrire les Cookies (les objets affichés dans chaque case)

On a six types de cookies (croissant, cupcake, danish, donut, macaroon, sugarCookie), chaque cookie a une position dans la grille (ligne, colonne), et deux images associées (une version normale et une version "surlignée" ("highlighted" en anglais).

Vous modifierez la classe Cookie pour que le constructeur prenne en paramètre : type (entre 0 et 5), ligne, colonne. Dans la classe Cookie, on a mis deux tableaux statiques pour décrire les URLs des images (normales, surlignees).

Un tableau statique n'est pas accédé à travers une instance mais à travers le nom de la classe. Par exemple : Cookie.urlsImagesNormales[this.type]; renverra l'url de l'image "normale" correspondant au type this.type.

Pour this.type = 0 ça donnera l'image d'un croissant.

Travail à faire :

  1. Ecrire un constructeur qui prend en paramètre type, ligne, colonne,
  2. Dans ce constructeur, initialiser les propriétés :
    • Vous mettrez les paramètres type, ligne, colonne dans des propriétés (rappel : propriété/attributs c'est pareil) du même nom
    • Vous créerez une propriété this.htmlImage qui sera crée à l'aide de l'API du DOM comme un élément HTML de type "img". Cette image aura comme source l'url de l'image correspondant au type de la cookie.
    • Vous modifierez les attributs width et height de l'image pour indiquer une taille de 80x80 pixels,
    • Vous ajouterez deux attributs via la dataset API. On veut stocker la ligne et la colonne dans l'objet DOM this.htmlImage

Coder dans la classe Grille de quoi remplir la grille

Regardez la classe Grille (dans grille.js). Elle sert à décrire la grille affichée à l'écran. 

Travail à faire :

  1. Déclarer un tableau de Cookie dans cette classe. Par exemple, appelez-le tabCookies,
  2. Ajoutez un constructeur qui prend en paramètres le nombre de lignes et de colonnes de la Grille. Pour le moment on a codé en dur dans index.html les <div> qui composent la grille. Il y en a 9x9. 
  3. Dans ce constructeur vous stockerez les paramètres passés dans des propriétés du même nom (nbLignes et nbColonnes)
  4. A la fin du constructeur vous appellerez la méthode this.remplirTableauDeCookies(6); // 6 = nombre de couleurs...5 ou 4 pour des difficultés moindres.
  5. Coder la méthode this.remplirTableauDeCookie(nbTypes) qui va remplir le tableau tabCookies par lignes et par colonnes:
    • En JavaScript on ne sait pas déclarer et allouer un tableau à n dimensions. En effet, la déclaration let tab[9][9] n'est pas valide par exemple. Dans le fichier utils.js on vous fournit une fonction create2DArray(nbLignes) qui prend en paramètre le nombre de lignes d'un tableau à deux dimensions. Utilisez-là pour allouer le tableau.
       
    • Ensuite à l'aide de deux boucles for imbriquées (sur le nombre de lignes et sur le nombre de colonnes de la grille), pour chaque case (ligne, colonne) :
      • générer un type au hasard, qui aura une valeur entre 0 et 5
      • créer un objet de type Cookie(type, ligne, colonne)
      • le rajouter dans le tableau tabCookies à la case [ligne][colonne]

 Coder dans la classe Grille la méthode showCookies() qui afficher les images dans la grille

Vous écrirez une méthode showCookies() dans la classe Grille, qui va :

  • Parcourir les <div> de la grille HTML à l'aide de document.querySelectorAll("#grille div"); Voir module 2 du MOOC sur le DOM et querySelector/querySelectorAll 
     
  • La liste des <div> obtenue est à une dimension, on utilisera l'itérateur forEach sur cette collection pour parcourir chaque élément avec son index : listeDivs.forEach((elem, index) => {.....});

  • Dans cet itérateur, utiliser des opérateurs mathématiques (/ et %) pour calculer la ligne et la colonne correspondant à l'index de l'itérateur (par ex, si index vaut 29, pour le 30ème div (on démarre l'index à zéro), quelle est la ligne/colonne de la cookie dans le 30ème div si on a 9 lignes et 9 colonnes ?)
     
  • Une fois qu'on a la ligne et la colonne, récupérer la cookie correspondante dans le tableau tabCookies
     
  • Récupérer l'image qui est une propriété de la cookie, et l'ajouter dans le DOM comme fils du <div> courant. Vous regarderez le MOOC sur "comment ajouter un élément au DOM". Vous utiliserez la méthode append(elem) ou appendChild(elem) sur le div.
     
  • Si tout va bien, on doit voir les cookies s'afficher à l'écran.

Detecter le click souris sur les images

Regardez là où les images sont crées. Cela se passe dans quelle classe ?

Mais dans quelle classe est le tableau des cookies ? Bon, on va devoir commencer à réfléchir à la logique du jeu...

On va d'abord voir comment détecter qu'on a cliqué sur un cookie, puis sur un autre. Si les deux sont à une case de distance, horizontalement ou verticalement, on les swappe (on les échange). Donc, où pensez-vous qu'il est plus judicieux de déclarer/coder l'écouteur de click sur les images ?

Et oui, c'est bien dans la classe Grille que ça va se passer, car c'est là qu'on pourra facilement tester (en cas de click) si on peut swapper deux cookies...

Travail à faire :

  1. Ajouter un écouteur de click sur les images avant de les afficher (par ex dans la méthode showCookies)
     
  2. Dans cet écouteur, on veut afficher la ligne et la colonne cliquée, et le type de cookie, comment faire ?
    faites un console.log de ces valeurs dans l'écouteur, vous voyez bien qu'on peut récupérer un cookie à partir de (ligne, colonne), codez donc une méthode dans la classe Grille intitulée getCookieDepuisLC(ligne, colonne), qui renvoie a cookie correspondante.
     
  3. Quand une cookie est cliquée, on veut changer sa classe CSS pour la mettre en évidence (classe "cookie-selected"), et changer son image pour son image highlightée (changer la valeur de htmlImage.src). Allez voir dans le MOOC HTML5 coding essential and best practices la documentation sur l'interface HTML5 ClassList.
     
  4. Vous rajouterez pour cela deux méthodes : "selectionnee() et "deselectionnee()" dans la classe Cookie, qui vont changer les classes CSS d'une cookie. 

Implémenter le swap que s'il est autorisé

Quand on clique une image/cookie, on va stoker la cookie cliquée dans un tableau cookiesCliquees de la classe Grille. Si le tableau a déjà un cookie dedans c'est qu'on a déjà clické sur la cookie "de départ". 

Quand on clique une seconde cookie, on va devoir :

  • Vérifier que la cookie est à une distance 1, si c'est le cas, on la sélectionne, et on swappe les deux images (et les types). Après le swap le tableau est remis à zéro et les deux cookies désélectionnées. Pour mesurer la distance entre deux cookies, on utilisera la distance euclidienne entre deux points (fournie sous la forme d'une méthode static distance(x1, y1, x2, y2) dans la classe Cookie).
     
  • Si la seconde cookie est à une distance > 1 de la première, alors on désélectionne les deux cookies  et on remet le tableau cookiesCliquees à zéro.
     
  • Ce n'est pas certain que vous en ayez besoin, mais pour supprimer un élément du tableau vous pouvez utiliserer la méthode splice(pos, nbElements) sur le tableau cookiesCliquees.
     
  • A la fin de cette étape, lorsqu'on clique sur une cookie, puis sur une autre, alors les cookies sont swappées. Attention, seule l'image et le type sont swappés, les lignes et colonnes associées ne doivent pas changer. Un click sur une image doit toujours donner la ligne et la colonne correctes. Vous écrirez une méthode statique swappe(cookie1, cookie2) dans la classe Cookie.

Essayer d'implémenter le drag'n'drop en plus du swap par click

On veut pouvoir aussi drag'n'dropper une image sur une autre et faire en sorte que les deux cookie soient swappés si ils sont à une distance de 1. Pendant le drag on veut voir un feedback visuel sur les cases survolées.

Support de cours pour le Drag'n'Drop : le module 3.3 du Mooc "HTML5 Apps and Games".

Vous devrez pour cela essayer de ré-utiliser au maximum le code écrit dans les étapes suivantes. On ré-utilisera par exemple le tableau cookiesCliquees pour stocker la cookie source (celle qu'on dragge) et la cookie destination (celle sur laquelle on droppe), et les algorithmes pour tester si on peut swapper et ceux qui implémentent le swap sont les mêmes.

Travail à faire :

  1. Ajouter un écouteur ondragstart sur les images. Vous copierez dans le clipboard du drag'n'drop (voir cours) un objet contenant la ligne et la colonne de l'image cliquée, en l'encodant en JSON à l'aide de la méthode JSON.stringify.
     
  2. Ajouter des écouteurs ondragenter et ondragleave qui ajouteront ou enlèveront la classe CSS "grilleDragOver" aux images survolées...
     
  3. Ajouter un écouteur ondrop qui récupèrera la cookie sur laquelle on a droppé (event.target), la cookie source (dans le clipboard, à partir de la ligne et la colonne) et qui swappera si possible (en appelant des méthodes existantes).

TP méthode 2, à l'aide du canvas HTML

Vous allez devoir reprendre pas mal d'idées proposées dans l'implémentation de la méthode 1.

Apprendre à utiliser un canvas HTML5 pour dessiner des images dedans

  1. Vous récupérerez ce projet squelette, le dézipperez et l'exécuterez,
     
  2. Vous allez regarder le MOOC "HTML5 Coding essential and best practices", module 2 et 3 sur le dessin et l'animation, en particulier la partie consacrée au dessin d'images.
     
  3. Avant de dessiner des images, il faut être sûr qu'elles ont toutes été bien chargées. Comme l'initialisation d'une image est une opération asynchrone, on fera appel à un bout de code assez pratique qui va faire le chargement des images à notre place, et nous prévenir quand il aura fini. Regardez dans script.js et dans assets.js comment est géré le chargement des assets. Il s'agit d'une version améliorée d'un "multiple image loader" présenté dans le MOOC HTML5 Coding essentials and best practices.
     
  4. Vous allez maintenant compléter le code partout  où figurent des // A FAIRE afin d'afficher correctement les images des cookies. Vous utiliserez la fonction drawImage vues dans le point 2 de cette liste.

Gérer les interactions à la souris et implémenter la logique du "swap" de cookies

  1. Maintenant essayez de refaire la partie "gestion du swap" du TP1. Vous devrez écouter les mouvements de la souris, les clicks sur le canvas, et essayer de déterminer à partir de la position x, y clickée quelle est la cookies qu'on a sélectionné. Vous lirez cette partie du MOOC HTML5 coding essentials and best practices sur la gestion des événements dans un canvas. Attention, récupérer la bonne position de la souris n'est pas trivial.

TP à rendre avant dimanche 24/01 minuit

Vous devrez rendre ce TP (quelle que soit la version que vous aurez faite) individuel, il sera noté.

Travail à faire :

  • Ajouter dans la classe grille deux méthodes "detecterMatch3Lignes()" et "detecterMatch3Colonnes()" qui vont marquer les cookies qui font partie d'un groupe de 3, 4, 5 ou 6 cookies de même type. 
  • Une fois qu'on a appelé ces deux méthodes, alors dans le tableau this.tabCookies les cookies qui doivent être supprimées visuellement de la grille sont ceux "marqués" (ajoutez un attribut dans la classe Cookie)
     
  • Vous ajouterez un bouton HTML : quand on clique, cela montrera graphiquement les cookies qui forment des groupes horizontaux et verticaux d'au moins 3. Par exemple en appelant leur méthode "selectionnee" de la classe Cookie.
     
  • Ecrivez un bout de code qui permet de "vider" (ne plus montrer) les cookies qui font partie d'un groupe d'au moins 3. Il faudra peut-être ajouter une propriété à la classe cookie pour indiquer qu'une  cookie est candidate à la disparition. Dans un premier temps on fera juste que "ne pas afficher" les cookies qui disparaitront.
     
  • Bonus : réfléchissez à un algorithme capable de gérer "les chutes" et re-remplir les cases rendues vides par les cookies disparues. Dans un premier temps il faudra "remplir les cases vides" puis évidemment redétecter s'il y a des matches et re-remplir le cas échéant, etc. Essayez d'implémenter cet algorithme.
     
  • Pour ceux qui ont fait la version canvas : réfléchissez à comment on pourrait "animer" les chutes et les disparitions.