Déclencher une action quand un sprite marche sur une tuile ou un groupe de tuiles

Nous présentons quelques morceaux de code utiles pour gérer les interactions entre un joueur et les tuiles d’un d’un jeu des tuiles. Ces éléments peuvent servir si vous souhaitez: 

  • Ramasser des objets placés en tant que tuile dans un tileset
  • Déclencher des actions quand une tuile particulière est touchée
  • Définir des zones constituées de tuiles, par exemple des zones de fin de niveau
  • Créer des passages secrets, ou des obstacles que l’on peut franchir selon certaines conditions …

Démo du résultat de ce tutoriel : a suivre

I - Lancer une action lorsque le sprite touche un type de tuiles

I.1 - La methode setTileIndexCallback :

on va utiliser la méthode setTileIndexCallback() :

Cette méthode est une méthode de calque. Elle est appelée depuis un calque statique (retourné par createStaticLayer) ou dynamique (retourné par createDynamicLayer)

elle permet de déclencher une action lorsqu’un type de tuiles est touché. Utile par exemple pour tuer un personnage s’il marche sur une tuile de lave, ou ramasser des objets placés sur la carte. Elle s’utilise de la façon suivante : 

  • Le premier paramètre est le numéro (ou la liste des numéros entre [ … ]  ) des tuiles concernées. 
  • Le second paramètre est la fonction de callback à appeler quand une tuile est touchée. 
  • Le troisième paramètre est le contexte, généralement this 

la fonction de callback est exécutée avec 2 paramètres : le sprite qui a touché la tuile, et la tuile en question. Ceci permettra de distinguer les type de tuiles, ou le sprite en question.

Il faut cependant que l’interaction entre le sprite et les tuiles du calque soit surveillée :

  • s’il s’agit de tuiles que l’on peut traverser,  on ajoutera simplement un overlap entre le sprite et le calque.
  • s’il s’agit de tuiles auxquelles le sprite va se cogner, on va ajouter un collider entre le sprite et le caque. Ici le retour de la fonction de callback permettra de valider la collision, ou au contraire de l’annuler. Ce point est facultatif, mais est discuté par la suite.

I.2 - Exemple : ramasser des pièces sous forme de tuiles dans un calque

Supposons que l’on possède un calque monCalque comprenant des pièces à ramasser sous formes de tuiles., que l’on souhaite ramasser. Le calque sera de type dynamique, car des tuiles vont être enlevées du calque. Dans la partie create() on pourra charger le calque, et appliquer une fonction de callback sur les tuiles représentant les pièces, identifiée par l’identifiant 26 dans l’exemple ci-dessous : 

// monCalque est déclaré hors fonction create() pour etre accessible en dehors
monCalque = map.createDynamicLayer('layer_pieces', tilesetpieces, 0, 0);

// quand on marche sur les tuiles d'ID 26 on lance la function "ramasserPieces" 
monCalque.setTileIndexCallback(26, ramasserPieces, this); 

On n’oubliera pas d’activer la surveillance de la superposition, par exemple entre notre joueur player et le calque monCalque en ajoutant l’ instruction suivante dans create()  autrement la fonction ne sera pas déclenchée :

this.physics.add.overlap(player, monCalque); 

Un exemple de fonction ramasserPiece()  serait alors :

function ramasserPiece (sprite, tuile) {
    // on enleve la piece
    moncalque.removeTileAt(tuile.x, tuile.y);
} 

II - Lancer une action lorsqu'un sprite rentre dans une zone ou touche une tuile particulière

II.1 - La methode setTileLocationCallback :

La méthode setTileLocationCallback() :c’est très similaire à setTileIndexCallback(), à ceci près qu’elle se déclenche non pas quand un sprite intéragit avec un type de tuile, mais avec une zone de tuiles rectangulaire (qui peut être juste une tuile). Cette zone est définie par les coordonées de la tuile supérieure gauche, et par le nombre de tuiles en largeur et hauteur.

Cette méthode est également  une méthode de calque, invoquable depuis un calque statique ou dynamique. Elle s’utilise de façon similaire à  setTileIndexCallback() 

  • Les quatre premiers paramètre définissent la zone de tuiles concernée. Il s’agit de coordonnées et de  nombre de tuiles par rapport au jeu de tuiles, et non par rapport au monde  on ne précise pas les coordonnées en pixels.. 
  • Le cinquième paramètre est la fonction de callback à appeler quand une tuile est touchée. 
  • Le sixième paramètre est le contexte, généralement this 

la fonction de callback est exécutée avec 2 paramètres : le sprite qui a touché la tuile, et la tuile de la zone en question.La encore, il faut cependant que l’interaction entre le sprite et les tuiles du calque soit surveillée, en ajoutant un overlap entre le sprite et le calque ou un collider selon le cas – le retour de la fonction de callback permettra ici encore de valider la collision ou pas -. Ce point est discuté plus loin.

II.2 - Exemple : définir une zone d'arrivée dans une carte

Supposons que l’on possède un calque monCalque possédant une zone d’arrivée. Dans la partie create() on pourra charger le calque, et appliquer une fonction de callback sur les tuiles représentant la zone d’arrivée (dans l’exemple, les tuiles [10,15], [10,16] et [10,17]

// monCalque est déclaré hors fonction create() pour etre accessible en dehors
monCalque = map.createStaticLayer('plateformes', tilesetJeu, 0, 0);

// quand on marche sur la zone on lance la fonction "finirLeNiveau" 
monCalque.setTileLocationCallback(10,15,3,1, finirLeNiveau, this); 

On n’oubliera pas d’activer la surveillance de la collision, par exemple entre notre joueur player et le calque monCalque en ajoutant l’ instruction suivante dans create()  autrement la fonction ne sera pas déclenchée :

this.physics.add.collider(player, monCalque); 

Un exemple de fonction finirLeNiveau()  serait :

function finirLeNiveau (sprite, tuile) {
   // instructions de fin de niveau ..
} 

III - Manipulations avancées sur les déclencheurs sur tuiles

III.1 - Activer / Désactiver une fonction callback précédemment définie

pour désactiver une fonction callback sur une zone définie, il suffit de rappeler l’instruction correspondante en indiquant la valeur null pour la fonction de callback. Par exemple pour désactiver la zone définie dans la partie précédente, on peut écrire: 

// annulation de la  "finirLeNiveau" 
monCalque.setTileLocationCallback(10,15,3,1, null, this); 

III.2 - L'importance de la valeur retournée par la fonction de callback

Lorsque l’on a défini un collider entre un sprite et un calque, et que le sprite entre en collision avec une tuile déclenchant un callback, il est possible d’activer ou de désactiver à la volée la collision  entre ce sprite et la tuile. 

Ceci s’opère par grâce au retour de la fonction de callback, qui peut retourner une valeur de type booléen :

  • Si la valeur retournée est true, la collision est validée,
  • Si la valeur retourne est false,  la collision est refusée et le sprite pourra traverser la tuile.

III.3 - Exemple synthèse : ramasser des clés pour traverser la zone

 On peut appliquer ces concepts pour définir, par exemple, un passage qui sera validé seulement si joueur possède un objet. Dans l’exemple suivant, on peut ramasser des clés sur un calque calqueCles : si le nombre de clés est suffisant, on pourra passer sur le passage défini dans un calque calquePlateformes. Dans la fonction create() on ajoute donc le code suivant : 

/* chargement des calques t déclaré hors fonction create() pour etre accessibles 
en dehors de create() - dans les fonctions callback */
const calqueCles = map.createDynamicLayer('calqueCles', tilesetpieces, 0, 0);
const calquePlatesformes = map.createDynamicLayer('calqueCles', tilesetpieces, 0, 0);

// quand on marche sur les tuiles d'ID 26 on lance la function "ramasserPieces" 
calqueCles.setTileIndexCallback(26, ramasserPieces, this);

// quand on marche sur la zone on lance la fonction "traverserZone" 
calquePlatesformes.setTileLocationCallback(10,15,3,1, traverserZone, this);

//active les overlap avec calqueCles, les collisions calquePlatesformes 
this.physics.add.overlap(player, calqueCles);
this.physics.add.collider(player, calquePlatesformes);

player.nbCles = 0; // on initialise un attribut nbCles du sprite player à 0 

Les deux fonctions callback associées seraient alors  :

function ramasserPiece (sprite, tuile) {
    calqueCles.removeTileAt(tuile.x, tuile.y);  // on enleve la piece
    sprite.nbCles++; // incrementation du nombre de cles ramassées
}

function traverserZone (sprite, tuile) {
    if (sprite.nbCles >= 10) // nb de cles suffisant;
    return false;  // pas de collision : false renvoyé
    else return true;  // sinon : collision
}
 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *