Les personnages non joueurs (PNJ)

Les météorites

Suite de la série d’articles consacrés à la création d’un shooter avec phaser.js, le précédent étant consacré à la gestion du laser du joueur.

La météorite et son mouvement

Le champ de météorites est composé sans surprise de météorites, plus ou moins grandes, plus ou moins rapides avec des trajectoires plus ou moins chaotiques.

Au départ et pour faire simple, on donne à la météorite un mouvement vertical du haut vers le bas de la scène, en lui appliquant une vitesse sur l’axe des ordonnées. La méthode d’animation diffère de celle du shooter puisqu’ici elle utilise une simple rotation du sprite sur lui-même.

Notez que la trajectoire de la météorite est un moyen très simple et peu couteux pour accroitre la difficulté. La synthèse des différents leviers à travailler peut se faire à l’aide d’un simple tableau. En jouant sur les curseurs de chacun, il devient facile de durcir le challenge et d’ajuster la courbe de difficulté comme vous pouvez en voir une illustration sommaire ci-dessous.

Sur le même modèle que celui du Laser, on crée un objet Meteor. Avec un constructeur, et 2 méthodes start pour lancer la météorite du haut vers le bas et anim pour l’animer en lui appliquant une rotation donnée en degrés par seconde.

export default class Meteor extends Phaser.Physics.Arcade.Sprite {

 constructor(scene, x, y, texture) {
  super(scene,x,y,texture);
  scene.add.existing(this);
}

 start(velocityX,velocityY) {
  this.setVelocityX(velocityX);
  this.setVelocityY(velocityY);
}

 anim(angularVelocity) {
  this.setAngularVelocity(angularVelocity) ;
 }
}

Idem que pour le laser, le code de l’objet est encapsulé dans un fichier dédié Meteor.js placé sous le dossier scene. Pour que cette classe soit accessible, il est nécessaire de l’importer depuis la scène définie dans le fichier Game.js et de charger les 2 images des météorites.

preload() { ...
 this.load.image('meteor', 'assets/meteor/meteor.png');
 this.load.image('meteor2', 'assets/meteor/meteor2.png');
}

Les météorites et leurs mouvements

Pour rendre le challenge à minima intéressant, ce n’est pas une mais 50 météorites qui seront lancées séparément à des endroits choisis au hasard sur l’horizontale. L’utilisation d’un timer est particulièrement adaptée : son paramétrage permet de lancer des actions à intervalle régulier en en limitant le nombre.

Phaser.js intègre plusieurs structures de données qui propose de rassembler des objets par nature et connexes dans leur comportement.

La structure staticGroup regroupe des objets inertes StaticBody, qui nécessitent une gestion manuelle des interactions et la structure group regroupe des objets Body qui subissent les affres de l’environnement dans lequel ils évoluent, comme la gravité ou d’autres objets en faisant partie. Environnement, par ailleurs, configurable par le biais de la propriété physics de l’objet Phaser.Game.

Nos objets étant animés et entrant en interaction les uns avec les autres, on crée un group en spécifiant les classes d’objets qui y seront rattachés depuis create.

Par soucis d’équité entre les joueurs, le déroulé d’une partie doit toujours être le même : d’une partie à l’autre, les météorites suivent toujours le même ordre et le même chemin. Positionner une météorite par le simple tirage d’un nombre aléatoire ne remplit pas cette mission puisque la suite de nombres va varier d’une partie à l’autre. Pour éviter cet écueil, on utilise une génération contrôlée de nombre aléatoires : la suite de nombres sera toujours la même.

Phaser.js a dans sa panoplie d’objets, un RandomDataGenerator qui prend en paramètre un nombre appelé graine (seed). Pour une seed donnée, la suite des nombres tirés au sort est toujours la même. Cette approche est aussi exploitée dans la génération procédurale d’espaces par le biais de l’algorithme de Perlin ou dérivés. On initialise ce générateur avec la graine 999 depuis create.

create() {....
 this.randomData = new Phaser.Math.RandomDataGenerator(999);
 this.meteorGroup = this.physics.add.group({
  classType: Meteor
 });
  .....}

La configuration du type d’objets via classType du groupe permet au groupe de créer des objets de ce même type. On ajoute une méthode spawnMeteor dédiée à la création des météorites par le biais de meteorGroup qui prend en paramètres sa forme, les vitesses sur les 2 axes, la vitesse de rotation et la scène à laquelle se rattacher.

spawnMeteor(meteorView, velocityX, velocityY,angularVelocity,scene) {
 const meteor = this.meteorGroup.get(this.randomData.between(0, 600),50,meteorView);
 scene.add.existing(meteor);
 meteor.start(velocityX, velocityY);
 meteor.anim(angularVelocity);
}

Il ne reste plus qu’à générer chaque seconde les météores avec le timer en choisissant au hasard leur image.

create() {....
 this.meteorTimer = this.time.addEvent( { 
  delay : 1000,
  callback: () => {
   let meteorRandomView =  Math.ceil(Math.random()*2);
   let meteorView = 'meteor';
   if ( meteorRandomView == 1 ) {
    meteorView = 'meteor2';
   }
   this.spawnMeteor(meteorView,0,100,15,this) ;
  },
  loop: false, repeat : 50, callbackScope: this 
 });
....}

Pour jouer sur la difficulté, il suffit d’activer les leviers sur la vitesse, la trajectoire ou la taille de l’objet Meteor.

La suite de l’exercice va consister à gérer les collisions.

Ne rate pas cette chance

 

Reçois ton livre GRATUIT pour créer des jeux vidéo.

Bravo, jette un œil à ta boite mail pour télécharger ton guide.