Dans ce tutoriel nous proposons un mécanisme simple permettant d’interagir avec un élément du jeu : une porte. Lorsque le personnage du joueur est sur cette porte, il peut soit l’ouvrir, soit la fermer, en appuyant sur la touche espace.
Les notions abordées sur ce tutoriel sont :
- la détection d’éléments qui se superposent,
- le changement de statut d’un objet à l’autre (ici porte ouverte / fermée),
- et la pression simple d’une touche sur le clavier (il y a ici une légère différence avec le fait de détecter si la touche est pressée ou pas)
Le résultat est un jeu dans lequel un personnage peut aller sur la porte et l’activer en tapant sur espace.
Démo du résultat à obtenir avec ce tutoriel
Base de départ pour ce tutoriel
Nous partons d’une base constituée d’un jeu dans lequel un personnage est présent sur un monde de taille fixe avec une gravité prédéfinie. Ce personnage peut aller à gauche, à droite, et sauter avec la flèche du haut s’il touche le sol. Les animations sur ce personnage ont été définies. Cette base a été créée à partir du tutoriel Créer son premier jeu de plate-forme en découvrant Phaser sur lequel on a enlevé toute la partie « génération des étoiles », « génération du score », « génération des bombes ».
Cette base est directement accessible sur codesandbox sous forme de template: lorsque vous créez une nouvelle sandbox, choisissez « explore templates » et et recherchez dans la barre de recherche « phaser-base-plateforme »
I - Ajout de la porte
I.1 - Chargement de l’asset, et placement de la porte
Nous allons utiliser le spritesheet spritesheet_porte.png présenté ci-dessous (clic droit sur l’image et enregistrer pour le récupérer.
Nous plaçons le fichier spritesheet_porte.png dans le répertoire src/assets. Dans la fonction preload(), on charge notre fichier spritesheet_porte.png que l’on référence avec le mot clé « img_porte » :
this.load.spritesheet("img_porte", "src/assets/spritesheet_porte.png", {
frameWidth: 96,
frameHeight: 120
});
En dehors de toute fonction nous ajoutons tout d’abord la variable porte qui va référencer notre porte :
var porte;
Nous plaçons ensuite la porte en tant que sprite statique; Dans la fonction create() on ajoute la ligne suivante pour placer la porte en coordonnées (550,372)
porte = this.physics.add.staticSprite(550, 372, "img_porte");
Pourquoi un staticSprite() et non pas un sprite() comme pour notre personnage de jeu? tout simplement parce que la porte est immobile, et n’est pas censée bouger. Utiliser un staticSprite() permet de la figer et de la prémunir de la gravité.
I.2 - Création des animations d’ouverture et de fermeture
Nous créons ensuite deux animations d’ouverture et de fermeture de porte a partir du spritesheet de la porte. Rien de nouveau ici, on réutilise ce qu’on a vu précédemment. Dans la fonction create() on crée l’animation d’ouverture de porte :
this.anims.create({
key: "anim_ouvreporte",
frames: this.anims.generateFrameNumbers("img_porte", { start: 0, end: 5 }),
frameRate: 50,
repeat: 0
});
Toujours dans la fonction create() on crée l’animation de fermeture de porte, en inversant les indices de frame de début et de fin :
this.anims.create({
key: "anim_fermeporte",
frames: this.anims.generateFrameNumbers("img_porte", { start: 5, end: 0 }),
frameRate: 50,
repeat: 0
});
II - Interaction avec la porte
Nous définissons ici la partie nouvelle de ce tutoriel : l’interaction avec la porte. Cette interaction se fait si deux conditions sont réunies : 1) le personnage est sur la porte et 2) il appuie sur la barre espace. Nous réutilisons ici la variable clavier que nous avions défini en tant qu’écouteur clavier avec un createCursorKeys() dans le tutoriel de base.
II.1 - Détection du personnage sur la porte et commande d’ouverture
Nous allons utiliser 2 fonctions de Phaser particulièrement utiles :
- Phaser.Input.Keyboard.JustDown() : permet de détecter quand une touche vient d’etre pressée.
- this.physics.overlap() est une fonction qui prend deux paramètres de type sprite, et renvoie true si les hitbox de ces deux objets s’intersectent (this est un élément plus complexe qu’il n’y parait. Il représente ici la scène en question)
Jusqu’a présent nous aurions écrit if (clavier.space.isDown == true) { …} pour tester si une touche est pressée. Mais cette dernière instruction aurait renvoyé true tant que la touche était appuyée. Meme en appuyant quelques milli-secondes sur la touche, on aurait pu exécuter plusieurs fois le if () car la fonction update() aurait boucle plusieurs fois dessus. L’utilisation de JustDown() de la classe Phaser.Input.Keyboard permet de ne renvoyer true que lorsque la touche vient d’être appuyée. Pour l’activer une seconde fois, il faudra relâcher et rappuyer sur la touche. C’est, pour résumer, toute la différence que l’on aura entre « laisser appuyer » et « simplement appuyer » sur une touche.
Dans la fonction update() on ajoute donc le code suivant : si les deux conditions « appui sur une touche espace » et « superposition entre la hitbox du player et celle de la porte » sont vérifiées, on lance l’animation d’ouverture de porte sur la porte.
if ( Phaser.Input.Keyboard.JustDown(clavier.space) == true &&
this.physics.overlap(player, porte) == true) {
// le personnage est sur la porte et vient d'appuyer sur espace
porte.anims.play("anim_ouvreporte");
}
Testez votre jeu : une fois sur la porte, appuyez sur espace : la porte s’ouvre. Mais si vous rappuyez sur espace, l’animation de porte se relance. Nous allons essayer de faire quelque chose de plus finalisé, en fermant la porte
II.2 - Ajout d'un statut et changement de l'animation selon le statut
Pour ouvrir ou fermer la porte, il va falloir tout d’abord stocker son état dans le jeu. Est-elle actuellement fermée ou ouverte? Le plus simple est de stocker cet élément en tant qu’attribut de la porte ! Javascript offre une certaine souplesse sur la définition des attributs d’objets déjà existant : il suffit de les manipuler pour qu’ils soient automatiquement ajoutés à l’objet ! On rajoute donc un attribut ouverte à l’objet porte, qui prendra comme valeur true si la porte est ouverte, et false sinon.
Au départ, la porte est fermée. Dans la fonction create(), après la création de la porte, on ajoute :
porte.ouverte = false;
Dans la fonction update() on modifie l’animation lancée lorsque le personnage est sur la porte et appuie sur espace : si la porte est fermée, on lance l’animation anim_ouvreporte et on fait passer le statut de la porte à ouvert ( porte.ouverte = true; ). Sinon on lance l’animation anim_fermeporte on fait passer le statut de la porte à fermé (porte.ouverte = false; )
//...
// le personnage est sur la porte et vient d'appuyer sur espace
if (porte.ouverte == false) {
porte.anims.play("anim_ouvreporte");
porte.ouverte = true;
} else {
porte.anims.play("anim_fermeporte");
porte.ouverte = false;
}
//...
Votre porte s’ouvre et se ferme désormais correctement.