Contenu principal
Cours : Apprendre à coder > Chapitre 4
Leçon 5: Making a memory gameGrille de tuiles
La première étape du jeu de "Memory" est le mélange aléatoire de toutes les tuiles, puis leur disposition en grille rectangulaire, faces cachées, pour qu'on ne puisse pas voir où sont les images.
Tuiles faces cachées
Pour commencer notre programmation du jeu, préoccupons-nous juste de créer les tuiles faces cachées. Nous déterminerons comment implémenter les images plus tard.
La "tuile" est un objet suffisamment important dans le jeu de "Memory", pour que nous utilisions une conception orientée objet pour définir cet objet
Tile
, et ainsi créer plusieurs instances de celui-ci. Nous pourrons alors associer deux propriétés (la position et l'image), et un comportement (retourner la tuile, face dessus ou face dessous), à chaque Tile
s.Pour commencer, nous allons définir la fonction constructeur de
Tile
. Étant donné que nous ne traitons pas encore les images, nous allons juste lui passer les arguments x
et y
. Nous allons aussi enregistrer la largeur (une constante) (width en anglais) de la tuile, dans une propriété de l'objet.var Tile = function(x, y) {
this.x = x;
this.y = y;
this.width = 70;
};
Maintenant que nous avons défini le constructeur, nous pouvons utiliser une boucle pour créer des tuiles aux coordonnées x et y appropriées. En fait, nous allons utiliser deux boucles for (une boucle for imbriquée) pour faciliter la génération des coordonnées d'une grille.
Nous commençons par initialiser un tableau
tiles
vide :var tiles = [];
Notre boucle extérieure itère sur le nombre de colonnes que nous souhaitons, notre boucle intérieure sur le nombre de lignes. Ainsi, chaque nouvelle
Tile
est initialisée avec un x et un y, qui correspondent à une ligne et à une colonne.var NUM_COLS = 5;
var NUM_ROWS = 4;
for (var i = 0; i < NUM_COLS; i++) {
for (var j = 0; j < NUM_ROWS; j++) {
tiles.push(new Tile(i * 78 + 10, j * 78 + 40));
}
}
Mais, oh, il est difficile de savoir si les tuiles seront bien placées, car nous ne possédons encore aucun code nous permettant de les dessiner ! En fait, nous aurions dû peut-être commencer par cela. Quelquefois, en programmation, il n'est pas toujours évident de savoir par où commencer. Ajoutons une méthode à l'objet
Tile
, pour dessiner une tuile face cachée sur la zone de dessin. Nous allons dessiner un rectangle arrondi, avec une jolie feuille de Khan sur le dessus, aux coordonnées qui lui ont été assignées.Tile.prototype.drawFaceDown = function() {
fill(214, 247, 202);
strokeWeight(2);
rect(this.x, this.y, this.width, this.width, 10);
image(getImage("avatars/leaf-green"), this.x, this.y, this.width, this.width);
};
Et maintenant, nous pouvons vérifier l'apparence de nos tuiles. Ajoutons une nouvelle boucle for, parcourant les tuiles, pour appeler la méthode de dessin :
for (var i = 0; i < tiles.length; i++) {
tiles[i].drawFaceDown();
}
Voici à quoi ressemble notre programme, avec ce code. Essayez de bidouiller les différents nombres utilisés dans la boucle for imbriquée, pour voir comment les changements ont un impact sur la grille, ou essayez de modifier le dessin (un logo différent, peut-être ?) :
Tuiles faces visibles
Maintenant que nous avons notre grille de tuiles faces cachées, attaquons-nous à un problème plus délicat : leur assigner à chacune une image, de telle manière qu'il y en ait deux de chaque, distribuées aléatoirement dans le tableau. Il y a probablement plusieurs moyens d'accomplir cela, mais voici ce que je suggère :
- Nous créons un tableau des images possibles, en utilisant la fonction
getImage
, pour les sélectionner dans notre bibliothèque. - Nous n'aurons besoin que de 10 images pour les faces de nos 20 tuiles, donc nous créons un nouveau tableau, contenant 2 copies, de 10 images sélectionnées aléatoirement, du premier tableau.
- Nous mélangeons aléatoirement les images sélectionnées de ce nouveau tableau, pour qu'à l'intérieur, les paires d'images ne soient plus placées côte à côte.
- Dans la boucle for imbriquée, dans laquelle nous créons les tuiles, nous allons assigner une image de ce tableau à chaque tuile.
Ces étapes ne vous semblent peut-être pas encore très claires. Codons-les, pour voir à quoi cela ressemble
Étape 1 : Nous créons un tableau des images possibles, en utilisant la fonction
getImage
, pour les sélectionner dans notre bibliothèque :var faces = [
getImage("avatars/leafers-seed"),
getImage("avatars/leafers-seedling"),
getImage("avatars/leafers-sapling"),
getImage("avatars/leafers-tree"),
getImage("avatars/leafers-ultimate"),
getImage("avatars/marcimus"),
getImage("avatars/mr-pants"),
getImage("avatars/mr-pink"),
getImage("avatars/old-spice-man"),
getImage("avatars/robot_female_1"),
getImage("avatars/piceratops-tree"),
getImage("avatars/orange-juice-squid")
];
J'ai choisi un groupe d'avatars, mais vous pouvez changer et prendre des images qui vous plaisent. Ce qui est important est de veiller à ce que ce tableau contienne au moins 10 images, pour qu'on ne soit pas à court d'image pour nos 20 tuiles. Nous pouvons en ajouter beaucoup plus que 10 cependant, pour rendre notre jeu à chaque fois plus varié, car nous restreindrons la liste à la prochaine étape.
Étape 2 : Nous n'aurons besoin que de 10 images pour les faces de nos 20 tuiles, donc nous créons un nouveau tableau, contenant 2 copies, de 10 images sélectionnées aléatoirement, du premier tableau.
Pour faire cela, nous créons une boucle for qui itère 10 fois. À chaque itération, nous sélectionnons aléatoirement un index dans le tableau
faces
, poussons deux fois l'élément correspondant dans le tableau selected
(sélectionnés en français), puis utilisons la méthode splice pour le retirer du tableau faces
, afin que nous ne le sélectionnions pas une autre fois. Cette dernière étape est très importante !var selected = [];
for (var i = 0; i < 10; i++) {
// Sélectionne aléatoirement un élément du tableau faces
var randomInd = floor(random(faces.length));
var face = faces[randomInd];
// Pousse 2 copies dans le tableau selected
selected.push(face);
selected.push(face);
// Supprime l'élément du tableau faces pour éviter qu'il soit resélectionné
faces.splice(randomInd, 1);
}
Étape 3 : Nous mélangeons aléatoirement les images sélectionnées de ce nouveau tableau, pour qu'à l'intérieur, les paires d'images ne soient plus placées côte à côte.
Vous devez vous demandez comment on peut mélanger aléatoirement les éléments d'un tableau en JavaScript ? Il existe quelques techniques. Je vais vous montrer ma préférée.
En JavaScript, tous les objets tableau possède une méthode intégrée
sort
qui trie le tableau dans l'ordre "lexicographique". Ce qui signifie qu'il convertit chaque élément en chaîne de caractère, et les trie comme si elles étaient des mots dans un dictionnaire. Par exemple, regardons comment un tableau de nombres et de lettres serait trié :var items = ["A", 1, "C", "H", 10, "D", 2];
items.sort();
1,10,2,A,C,D,H
Cet ordre de tri est utile de temps en temps, mais la plupart du temps, on souhaitera trier notre tableau autrement. Par exemple, si nous avions un tableau de nombres, nous voudrions le trier numériquement. C'est pourquoi, la méthode
sort
accepte un argument facultatif, une fonction de retour, qui est appelée sur chaque paire d'éléments du tableau, et qui retourne une valeur indiquant lequel des deux éléments est le plus grand. Un nombre négatif indique que le premier élément doit être en premier, un nombre positif, que le second élément doit être en premier, et un zéro laisse l'ordre des éléments inchangé.Pour trier un tableau numériquement, du plus petit au plus grand, nous pouvons passer une fonction retournant
a-b
.var nums = [1, 5, 10, 2, 4];
nums.sort(function(a, b) {
return a-b;
});
// 1,2,4,5,10
OK. Comment utiliser cela pour trier aléatoirement un tableau ? Eh bien, il nous suffit juste de retourner un nombre aléatoire avec cette fonction, un nombre, soit négatif, soit positif. Voici comment procéder, sur notre tableau
selected
:selected.sort(function() {
return 0{,}5 - random();
});
Et nous voici maintenant avec un tableau de 10 paires d'images, triées aléatoirement !
Étape 4 : Dans la boucle for imbriquée, dans laquelle nous créons les tuiles, nous allons assigner une image de ce tableau à chaque tuile.
Nous possédons 20 images dans notre tableau
selected
, et nous itérons 20 fois, pour instancier les nouvelles tuiles aux coordonnées de la grille. Pour assigner une image à une tuile, utilisons simplement la méthode pop
sur le tableau. Cette méthode retire le dernier élément du tableau et le retourne. C'est la manière la plus simple de veiller à ce que nous assignions toutes les images, sans faire de doublons.for (var i = 0; i < NUM_COLS; i++) {
for (var j = 0; j < NUM_ROWS; j++) {
tiles.push(new Tile(i * 78 + 10, j * 78 + 40, selected.pop()));
}
}
Nous avons donc maintenant théoriquement une image assignée à chaque tuile, mais nous ne les avons pas encore affichées ! Ajoutons une méthode à l'objet
Tile
, qui va être responsable de l'affichage face visible. Elle va ressembler à celle qui s'occupe de l'affichage face cachée, sauf que la propriété this.face
est maintenant passée à la fonction image
.Tile.prototype.drawFaceUp = function() {
fill(214, 247, 202);
strokeWeight(2);
rect(this.x, this.y, this.width, this.width, 10);
image(this.face, this.x, this.y, this.width, this.width);
};
Pour éviter de répéter du code, nous pourrions en fait ajouter une méthode additionnelle, qui serait responsable du dessin des contours, et appeler cette méthode, au début de chacune des deux méthodes de dessin. Mais nous allons laisser les choses comme elles sont pour l'instant.
Finalement, pour tester tout ce travail, nous pouvons modifier notre boucle for, et appeler
drawFaceUp
à la place de drawFaceDown
:for (var i = 0; i < tiles.length; i++) {
tiles[i].drawFaceUp();
}
Et voilà, toutes ensemble ! Redémarrez (Restart) pour voir comment la disposition des tuiles changent à chaque fois.
Vous souhaitez rejoindre la discussion ?
Pas encore de posts.