[Phaser 3] Créer son premier jeu phaser complet en partant de rien

24h pour découvrir le département MMI

[Phaser 3] Créer son premier jeu phaser complet en partant de rien

Le tutoriel par où commencer! Phaser est une librairie permettant de créer des jeux vidéos en se basant sur un moteur physique très performant et intuitif. Dans ce TP nous allons créer un jeu de plate-forme. Ce TP n’est ni plus ni moins qu’une version francisée du tutorial officiel de création d’un premier jeu de la librairie Phaser.

Retrouvez le code HTML de départ, les images utilisées (répertoire Asssets), et le code HTML des différentes étapes en téléchargeant l’archive zip associée à ce tutoriel :

La philosophie de Phaser est la suivante :

  • On crée des objets, des éléments de décors, des éléments de jeu
  • On leur attribue des images respectives, et on les place dans un décor
  • On les plonge ensuite dans un environnement physique gérant la gravité, les collisions, les rebonds, l’accélération. On peut définir des contraintes particulières pour chaque objet, définir quels éléments peuvent rentrer en collision ou non
  • On définit les actions à surveiller au clavier, et comment chaque action au clavier influe sur la physique des objets (par exemple, une accélération si on tape sur la flèche de droite, un changement d’image, et plein d’autre choses)
  • On définit enfin les actions à effectuer sur quand des éléments particuliers rentrent en action (par exemple quand un personnage ramasse un objet), et les conditions de jeu.A partir du moment où l’on peut contrôler le monde physique et appliquer des actions particulières à des objets particuliers, les possibilités sont infinies.


Définition du jeu : premiers éléments

Nous listons quelques éléments principaux du jeu :

  • Le jeu que nous mettons en place est un jeu de plate-forme, avec présence de gravité.
  • Un personnage peut se déplacer à gauche et à droite, et sauter sur les différentes plates-formes
  • Il doit ramasser des étoiles qui sont tombées du ciel.
  • Lorsque toutes les étoiles ont été ramassées, une nouvelle série d’étoile ainsi qu’une bombe apparaissent
  • Si le personnage touche la bombe, il perd la partie.
  • A chaque fois que toutes les étoiles sont ramassées, une bombe supplémentaire apparait, rendant le jeu de plus en plus difficile.
  • Un score permet de savoir à quel record a été établi. A chaque ramassage d’étoile, le scoreaugmente de 1
  • Les bombes ont un facteur de rebond de 1 : c’est-à-dire qu’elles rebondissent sur une paroi à lamême vitesse qu’elles sont arrivées. Elle ne sont pas sujettes à un facteur d’amortissement.

Nous définissons ensuite les éléments graphiques de ce jeu. Il y a une image pour le fond, une pour les plates-formes, une pour les étoiles, une pour les bombes, et un spritesheet pour le personnage. Les différentes images sont disponibles dans l’archive images.zip de Moodle.

Pour plus de facilité, nous mettons toutes nos images dans un sous-répertoire nommé assetsNous allons voir qu’il est possible de mettre ce jeu en place avec moins de 150 lignes de code !

Mise en place du framework Phaser

On va tout d’abord mettre en place un environnement minimaliste pour Phaser. A la fin de cette section nous aurons une fenêtre de jeu entièrement vide. Créez un document HTML en utilisant le code ci-dessous, et mettez dans le même repertoire le fichier phaser.js que vous pouvez télécharger sur ce lien : phaser.js

<!doctype html> <html lang="fr"> <head>
<meta charset="UTF-8" />
<title>Un premier jeu Phaser 3.0 </title> <script
src="phaser.js"></script> <style type="text/css">
        body {
            margin: 0;
} </style>
</head>
<body>
<script type="text/javascript">
</script> </body> </html>

Il est important de noter la présence de la ligne ci-dessous, qui permet le chargement de phaser : <script src= »//cdn.jsdelivr.net/npm/phaser@3.11.0/dist/phaser.js »></script>.Par la suite, on ajoutera tout le code entre les balises <script type= »text/javascript »> et </script> .

L’étape suivante consiste à configurer Phaser pour notre jeu. On crée une variable nommée configcomprenant toutes les informations de configuration. Rajoutez à votre programme le morceau de code suivant :

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
scene: {
        preload: preload,
        create: create,
        update: update
    }
};

Notez les différentes valeurs présentées dans config :

  • type définit le type de jeu (choisi automatiquement par Phaser : Phaser.AUTO)
  • widthet heightsont les dimensions de la fenêtre 
  • sceneest un élément essentiel : il décrit les noms des fonctions de préchargement, de chargement, et de mise à jour, respectivement preload,create, et update.

On ajoute ensuite ces trois fonctions, en les laissant vide pour l’instant. On mettra les instructions de pré-chargement dans la fonction preload : 

function preload () {
}

On mettra les instructions de création des objets qu’on va utiliser dans la fonction create: 

function create () {
}

On mettra dans la fonction update() tout ce qui est relatif à l’action dans le jeu et la mise à jour du jeu :

function update () {
}

Création d’une instance de jeu

Une fois la variable de configuration créée, on peut enfin créer une instance du jeu. On va appeler la méthode Game()de la librairie Phaser. On lui passe en paramètre la variable config. Et on obtient un nouvel objet décrivant un jeu, ici appelé game:

var game = new Phaser.Game(config);

On vient de créer notre premier jeu phaser. Vide. Vous pouvez visualiser le résultat sur le navigateur. Un cadre noir de 800×600 devrait apparaître. Nous avons un jeu, mais nous n’avons pas encore configuré le moteur physique à utiliser.

Nous modifions la variable config pour qu’elle contienne désormais des informations de configuration du moteur physique. Au sein de la variable config, ajoutez le morceau de code suivant (attention les … correspondent à du code écrit précédemment) :

var config = {
...
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
...
}

Notez les éléments présentés : physics : indique les éléments de configuration pour le moteur physique. Dedans on trouvera :

  • le type de moteur par défaut : élément défautassocié à la valeur  ‘arcade’
  • pour ce moteur arcade, la configuration de la gravité globale du monde, avec l’élément gravity : C’est un élément clé du jeu. Ici la gravité a été mise à 300sur l’axe des y(vertical). Donc sauf indication contraire, tous les objets qui vont être ajoutés par la suite dans le jeu subiront une gravité descendante de force 300.

Chargement des images

Etape suivante, nous allons charger les images de notre jeu pour pouvoir les utiliser à l’initialisation de notre jeu. Les lignes de code suivantes seront donc à ajouter dans la fonction preload. Ajoutez tout d’abord la ligne suivante :

this.load.image('sky', 'assets/sky.png');

Cette ligne permet de charger l’image sky.pngdu répertoire assetssous le mot-clé ‘sky’. On pourra ensuite utiliser ce mot-clé pour référencer cette image.

En nous inspirant de cette ligne, on ajoute les lignes de code permettant de charger les images suivantes avec les noms associés :

this.load.image('ground', 'assets/platform.png');
this.load.image('star', 'assets/star.png');
this.load.image('bomb', 'assets/bomb.png');

A titre d’exemple, voyez par exemple l’image ‘assets/platform.png’ référencée par le mot clé ground dans l’image ci-dessous : Cette image simple représente une plate-forme de 400×32 pixels. Ces dimensions sont importantes car elles seront discutées après.

Figure 1 – image platform.png

Nous allons enfin charger le spritesheetdu personnage. Il s’agit d’un fichier spécial qui contient toutes les animations de notre personnage. Ici ce fichier fait 48 pixels de haut, et 288 pixels de large avec 9 motifs dedans, soit 32 pixel par motif (voir Figure 2)

Figure 2 – spritesheet de notre personnage

La syntaxe diffère un peu d’une simple image, aussi contentez-vous d’ajouter la ligne suivante :

this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 });

Cette ligne nous dit que nous chargeons dans notre jeu (this) un spritesheet qui va être référencé sous le nom dude. Le fichier spritesheetest assets/dude.pnget comme il s’agit de plusieurs image il est important de préciser la taille du cadre à prendre dans cette image, à savoir une largeur de 32 pixels (frameWidth :32) et une hauteur de 48 pixels (frameHeight :48)

Nos images sont chargées, avec des mots clé dans la fonction preload. Nous allons pouvoir créer les éléments de notre jeu en utilisant les mots clés affectés.


Construction du plateau de jeu

Nous allons commencer par ajouter les éléments statiques, fixes de notre jeu.

La mise en place d’un fond de jeu est trivial. Au sein de la fonction create, ajoutez tout d’abord simplement cette ligne de code :

this.add.image(400, 300, 'sky');

Cette ligne ajoute tout simplement l’image référencée par sky dans le cadre de jeu. Vous pouvez visualiser le résultat sur l’interface de jeu.

Attention :voyez les coordonnées utilisées ici : 400, 300. Il s’agit du centre du cadre de jeu ! Quand on ajoute une image, ou un élément en général, tout est positionné par rapport au centre de l’élément en question. Ici cela tombe bien, l’image référencée par sky faisant 800 x 600, elle couvrira entièrement la zone de jeu.

La plate-forme de jeu est le premier point un peu technique. Il faut distinguer plate-forme et plateS-formeS. Supposons que l’on veuille mettre en place le plateau de jeu de la Figure suivante :

Figure 3 – plates-formes de jeu

Sur cette image, on distingue en fait 4 plates-formes : le sol, 1 plate-forme flottante à gauche et 2 plates-formes flottantes à gauche. Chaque élément peut-être considéré de façon individuelle, par rapport à son motif, son positionnement. Mais il est aussi pertinent de les envisager groupées, et de les considérer comme une seule grosse entité. Le fait de les considérer ainsi permet d’appliquer les mêmes caractéristiques physique un seule fois sur le groupe, et non par plate-forme. (cette approche sera reprise par la suite sur les étoiles et les bombes). 

Au sein du programme principal, on va d’abord créer la variable platforms(avec un s) qui va permettre de référencer le groupe de plate-formes :

var platforms;

Nous allons ensuite créer un groupe contenant les plate-forme, qui sera référencé par platforms. La création de ce groupe se fait en début de jeu, donc au sein de la fonction create. Par ailleurs, ce groupe sera dit statique, c’est-à-dire qu’il sera fixe et ne sera pas sujet à la gravité.  Au sein de la fonction create, on ajoute la ligne suivante :

platforms = this.physics.add.staticGroup();

Notre groupe statique est créé. Il est pour l’instant vide. Ajoutons une plate-forme. Juste après la création du groupe, ajoutons l’instruction suivante : 

    platforms.create(50, 250, 'ground');

Avec cette instruction, on vient d’ajouter un élément représenté par l’image associée au mot clé ground. On vient de placer son centre aux coordonnées (50, 250) ce qui constitue la plate-forme en haut à gauche de la Figure 3. Cette plate-forme dépasse surement à gauche de l’affichage. Mais ce n’est absolument pas un problème.

En vous inspirant de cette ligne de code,  essayer d’ajoutez les deux autres plates-formes aux coordonnées (600,400) et (750, 220), et visualisez le résultat.

Ajoutons enfin le sol. C’est là que les choses se compliquent inutilement : en référence à la Figure 3on peut voir une grosse plate-forme qui constitue tout le sol, sur une longueur de 800px. Or on ne dispose que de l’image présentée dans la Figure 1et associée au mot clé ground, d’une longueur de 400px. En plus le sol semble être particulièrement épais, environ 2 fois plus que l’image référencée par ground. Plusieurs solutions s’offrent à nous: 

  • On peut récupérer une image plus grande pour faire tout le sol. 
  • On peut créer 4 morceaux de groundet les juxtaposer en carré.
  • On peut prendre l’image référencée par ground, l’étirer avec un facteur x2 pour qu’elle fasse 800 px, et on la positionne au milieu de la zone de sol.

 C’est cette dernière solution que nous retiendrons ici. On va ajouter la ligne suivante : 

    platforms.create(400, 568, 'ground').setScale(2).refreshBody();

Ici l’appel à la méthode setscale(2)permet de doubler la taille de la zone. L’appel à refreshBody() permet de rafraichir la taille pour adapter l’image à la zone.

Il ne reste plus qu’a tester notre code et à admirer le résultat : On a désormais un beau ciel bleu, un sol et quelques plates-formes. Prochaine étape : ajouter notre personnage.

code associé : plusieurs_niveaux_partie5.html


Mise en place du personnage principal

Ajoutons désormais notre personnage principal. De la même facon que pour platforms, nous ajoutons une variable nommée playerdans notre programme principal. Cette variable permettra de pointer sur notre personnage.

var player;

Ensuite nous allons créer ce joueur : dans la fonction create, nous ajoutons un spriteau jeu, en position (100, 450), et lui attribuons l’image associée à dude.

player = this.physics.add.sprite(100, 450, 'dude');

Allez voir ensuite votre jeu en actualisant la page. Plein de choses se sont passées : 

Tout d’abord, le personnage est apparu aux coordonnées indiquées, dans l’air, puis il a été attiré au sol a cause de la gravité… mais ne s’est pas arrêté. Il a traversé le sol, puis la zone de jeu. Ceci est normal ! nous n’avons pas précisé que le personnage ne pouvait sortir du cadre du jeu. Pour remédier à cela, nous ajoutons à la suite de la fonction createl’instruction suivante :

    player.setCollideWorldBounds(true);

Cette instruction dit tout simplement que l’objet playerdoit pouvoir se cogner aux bords de la fenêtre. Relancez le jeu, notre joueur s’arrête au bord de la fenêtre de jeu. C’est mieux mais pas parfait, puisqu’il traverse le sol.


On va alors ajouter la notion de collision entre la plateforme et le joueur, grâce à la méthode collider() du moteur physique de notre jeu. Ceci permet de dire que les deux éléments ne peuvent se chevaucher et son sujets aux interactions physiques du monde. Dans la fonction createon ajoute, une fois la plateforme (platforms) et le joueur (player) définis l’instruction suivante :

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

Relancez votre jeu. Cette fois notre personnage s’arrête pile sur le sol. Gagné !

Evitons qu’il ne se blesse en tombant : ajoutons-lui un peu de rebond avec la ligne suivante, toujours dans la fonction preload() :

player.setBounce(0.2);

La valeur 0.2 permet de dire : quand le joueur rebondit, il rebondit dans la direction opposée avec une vitesse correspondant à 0.2 fois la vitesse initiale avec laquelle il arrivait avant collision.

Notez enfin une dernière chose : de base l’image du spritesheet chargé dans dude est celle la plus à gauche.

Gestion des mouvements

Nous allons ensuite faire déplacer notre personnage. Pour cela il va nous falloir récupéer les touches pressées au clavier. 

On va définir une variable cursorsqui va nous permettre de récupérer les événements au clavier. Dans le programme principal, ajoutez cette variable avec la ligne suivante :

var cursors;

Ensuite nous initialiser la variable Cursors pour qu’elle décrive un écouteur sur le clavier. Au sein de la fonction create, nous ajoutons la ligne suivante :

cursors = this.input.keyboard.createCursorKeys()

Notre clavier est prêt. La prochaine étape consiste à capteur les touches pressées et à effectuer les actions correspondantes quand ces touches sont pressées.

En phase de jeu, nous sommes précisément au sein de la fonction update. C’est dans cette fonction que l’on analyse les événements survenus en cours de jeu. Ajoutez les lignes suivantes :

   if (cursors.left.isDown) {
        player.setVelocityX(-160);
    }
    else if (cursors.right.isDown) {
        player.setVelocityX(160);
    }
    else {
        player.setVelocityX(0);
    }

Que nous indiquent ces lignes : ?

  • que lorsque la touche leftdu clavier , représenté par cursors, est pressée (down) on applique une vitesse sur le player, sur l’axe des X d’une valeur de -160 ; En gros on le fait aller à gauche.
  • Réciproquement, si la touche rightest pressée, la vitesse sur l’axe des X sera de 160.
  • Sinon, si aucune de ces touches n’est pressée, la vitesse sur l’axe des X sera de 0.

Testez votre jeu. Votre personnage se déplace ! Il ne regarde pas encore du bon coté, mais ce point sera corrigé par la suite.

Nous allons compléter les mouvements avec l’action de saut. Le saut va être déclenché lorsque l’on appuie sur la touche espace (space) . Mais cette action n’est possible que si le corps du joueur touche le sol. Cette seconde conditions peut se modéliser facilement par le test player.body.touching.down.

Rajoutez, et complétez le code suivant (remplacez les éléments en commentaires entre les balises /* */) en vous inspirant des actions de mouvements gauche et droite

    if (/*si ‘space’ est pressé */ && player.body.touching.down) { 
       /*appliquer une velocite de -330 verticalement*/
    }
}

Testez votre jeu. Le personnage se déplace, et doit pouvoir sauter. Vérifiez qu’il ne peut pas sauter s’il est déjà en l’air. Reste le problème du sens dans lequel regarde notre personnage…  nous allons régler cela en créant une animation.

Création des animations liées au mouvement 

Pour gérer l’affichage des mouvements de notre personnage, nous allons créer des animations à partir du spritesheetstocké dans dude (Figure2). La procédure est globalement la suivante :

  • D’abord on crée une animation en définissant les images à utiliser du spritesheetet la vitesse
  • On donne un nom à cette animation
  • Enfin on la lance lorsque la touche correspondante est pressée.

Nous allons tout d’abord créer l’animation à lancer quand le joueur se déplace à gauche. Si l’on numérote les vignettes du spritesheetdudede 0 à 8, Cette animation doit utiliser les vignettes 0 à 3, et boucler. 

Dans la fonction create, on crée cette animation, et on lui donne comme nom (key) ‘left’ :

    this.anims.create({
        key: 'left',
        frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
        frameRate: 10,
        repeat: -1
    });

Comme on peut le lire sur ce code, on crée une nouvelle animation a la liste des animations (anims) du jeu (this). Cette animation a comme nom left, et ses framessont récupérées à partir des vignettes 0(start) à 3(end) du spritesheetdude, ceci grâce à la méthode generateFrameNumbersqui fait tout le boulot

Une fois l’animation créée, il nous faut la lancer quand la touche leftest pressée. Rien de plus simple : allons modifier l’action lancée quand on se déplace à gauche, dans la fonction update() en rajoutant la ligne player.anims.play(‘left’, true); :

    if (cursors.left.isDown) {
        player.setVelocityX(-160);
        player.anims.play('left', true);
    }

l’ajout de la ligne en gris permet de lancer l’animation left. Le paramètre truepermet de dire « il ne faut pas relancer l’animation si cette dernière était déjà en train d’être lancée ». Cela permet d’éviter les phénomènes de saccade.

En vous inspirant de ce code, ajoutez une animation similaire, nommée right, décrivant l’animation du joueur à lancer lorsque ce dernier se déplace à droite. Référez-vous au spritesheetpour trouver les indices de vignettes correspondantes. Puis associez-la à la touche right.

Testez votre jeu. Vous pourrez constater que l’animation continue quand le personnage ne bouge plus. Ce qui est un peu gênant. Pour corriger ceci, il suffit d’ajouter une animation quand on n’avance plus. Dans create()on ajoute l’animation ‘turn’, uniquement constituée de la vignette 4. 

    this.anims.create({
        key: 'turn',
        frames: [ { key: 'dude', frame: 4 } ],
        frameRate: 20
    });

Il ne nous manque plus qu’à l’associer à la phase  « immobile » dans la fonction update() :  

 ...
    else {
        player.setVelocityX(0);
        player.anims.play('turn');
    }
...

Re-testez votre jeu. Le personnage bouge désormais de façon impeccable ! 

1          Ajout des étoiles

Nous allons ajouter des étoiles à collecter à notre jeu.

De manière similaire aux plates-formes, nous allons grouper les étoiles. Nous commençons par ajouter une variable stars qui contiendra toutes nos étoiles. 

var stars;

Dans la fonction create(), nous créeons  un groupe d’éléments, dont l’image sera associés au mot clé star. Ajoutez ce morceau de code :

stars = this.physics.add.group({

        key: ‘star’,

        repeat: 11,

        setXY: { x: 12, y: 0, stepX: 70 }

   });

Le code ci-dessus se traduit ainsi : Grace à l’option repeat, nous pouvons répéter la création 11 fois (soit au total 12 fois). On définit les coordonnées de ces étoiles avec l’attribut setXY. Nous plaçons la première étoile en coordonnées (12, 0), puis espaçons les autres de 70 pixels vers la droite à chaque fois. 

Nous ajoutons ensuite la gestion des collisions entre les étoiles et les plates-formes avec la ligne suivante (ligne similaire à celle écrite pour la gestion de la collision entre le joueur et les plates-formes)

   this.physics.add.collider(stars, platforms);

Vos étoiles sont désormais présentes. En testant le jeu vous pouvez voir que le joueur peut marcher sur les étoiles, car nous n’avons pas défini de collision entre starset player(ce qui est normal)

.1.2        Collecte des étoiles 

Il est temps de ramasses les étoiles. 

Ajoutons une nouvelle fonction collectStar. Cette fonction sera à terme déclenchée lorsque le spriteplayermarchera sur une étoilestar. Pour l’instant, cette fonction consistera simplement à désactiver l’étoile qui aura été passée en paramètre (la rendre invisible). 

function collectStar (player, star) {

   star.disableBody(true, true);

}

Pour déclencher cette action, nous allons ajouter une contrainte au moteur physique, qui dit que lorsque un objet playerintersecte (en anglais « overlap ») un objet du groupe stars, alors il faut exécuter la fonction collectStar()avec en paramètre lesdeux éléments qui s’intersectent.

    this.physics.add.overlap(player, stars, collectStar, null, this);

Avec cette simple ligne, la fonction collectStar()sera appelée à chaque fois que l’on ramasse une étoile, et cette dernière disparaitra.

.1.3        Ajout de rebonds aléatoires aux étoiles.

Pour ajouter un peu d’effet visuel, nous allons ajouter un coefficient de rebond aléatoire à chaque étoile, compris entre 0.2 et 0.4. Grace à la méthode Phaser.Math.FloatBetween(a,b),on peut récuperer une valeur flottante aléatoire comprise entre a et b. On va utiliser un iterateur, un mécanisme un peu complexe et non détaillé ici mais qui consiste à parcourir tous les éléments d’un groupe et leur appliquer les mêmes instructions. Au sein de la fonction create(),on ajoute donc les instructions suivantes :

    stars.children.iterate(function (child) {

    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));

   });

Quand on lance le jeu, on peut voir que les étoiles rebondissent désormais plus ou moins.

.1.4        Regénération des étoiles 

On avance sur le gameplay. L’étape suivante consiste à régénérer les étoiles une fois que ces dernières ont été toutes collectées. La méthode countActive()d’un groupe permet de savoir combien d’élément du groups sont encore actifs. Lorsque cette valeur retourne 0, il nous suffit de réactiver toutes les étoiles que nous avons désactivé lorsque nous les avons ramassées. Ainsi on aura l’impression qu’une nouvelle vague d’étoiles a été re-générée. La méthode enableBody()permet de réactiver l’étoile. On l’appelle via l’itérateur sur chaque élément du groupe stars

Le code ci-dessous est à placer dans la fonction collectStar(),puisqu’on va vérifier à chaque fois qu’une étoile est ramassée si c’était la dernière active ou pas.

    if (stars.countActive(true) === 0)  {

       stars.children.iterate(function (child) {

            child.enableBody(true, child.x, 0, true, true);

        });

   }

2          Finalisation : ajout d’un score et des bombes

Les ultimes points consistent à ajouter un score, et une condition de fin de jeu.

 ajout du score :

L’ajout d’un score est relativement simple. D’abord on ajoute une variable scoreà notre programme principal, que l’on initialise à 0.

var score = 0;

On ajoute également une variable scoreText qui va nous permettre de gérer l’affichage du score.

var scoreText;

Au sein de la function create(), nous allons placer le texte « score : 0 » en haut à droite (coordonnées 16,16) avec une police de 32 px.

   scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });

Il ne nous manque plus qu’à mettre à jour le score. Ceci se fait bien évidemment dans la fonction collectStar(), puisque le score est maj à chaque fois qu’une étoile est ramassée.

   //  Add and update the score
  score += 10;
  scoreText.setText('Score: ' + score);

Ajout des bombes

Le dernier point consiste à ajouter des bombes. Les bombes permettent de terminer le jeu. Des que le joueur touche l’une d’entre elle, on termine la partie.

Nous allons tout d’abord ajouter un groupe bombsvide. Dans le programme principal on ajoute :

var bombs;

Dans la fonction create()on ajoute la ligne suivante  :

    bombs = this.physics.add.group();

Enfin, on ajoute le modèle de collision entre les bombset les platforms

this.physics.add.collider(bombs, platforms);

Il ne nous manque plus qu’à ajouter des bombes au groupe bombs. Nous faisons le choix d’ajouter une nouvelle bombe a chaque fois que l’on a ramassé l’ensemble des étoiles.Dans la function collectStar()on rajoute les lignes suivantes, après le test sur le nombre d’étoiles actives : 

if (stars.countActive(true) === 0)  {
...
        var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);

        var bomb = bombs.create(x, 16, 'bomb');
        bomb.setBounce(1);
        bomb.setCollideWorldBounds(true);
        bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
        bomb.allowGravity = false;
}

Examinons ce code ligne par ligne :

La ligne suivante est en fait un simple test avec une syntaxe un peu particulière. Si jamais la position du joueur sur l’axe des X est inférieure à 400, on tire un nombre aléatoire entre 400 et 800. Sinon on tire un nombre aléatoire entre 0 et 400. On stockera ce nombre dans une variable x.

 var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);

Dans la ligne ci-après, on va utilisera les coordonnées (x,16) pour ajouter une nouvelle bombe à bombs. L’utilisation de x permet tout simplement d’éviter que la bombe apparaisse trop près du joueur , induisant une défaite précipitée :

var bomb = bombs.create(x, 16, 'bomb');

On met un coefficient de rebond de la bombe à 1 

   bomb.setBounce(1);

On fait en sorte que la bombe ne sorte pas des limites du monde :

        bomb.setCollideWorldBounds(true);

On ajoute une vitesse aléatoire à la bombe

        bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);

On empêche la bombe d’être sujette à la gravité

        bomb.allowGravity = false;

Il ne reste plus qu’a définir la fin de partie lorsque le joueur touche une bombe

Définition d’une collision entre le joueur et une bombe et du game over

On ajoute une variable gameOvera notre programme principal, initialisée à false.

var gameOver = false;

Dans la fonction update() si jamais gameOver passait à vrai, on arrête le jeu

if (gameOver) {
        return;
    }

On crée ensuite une fonction hitBombcontenant les actions a effectuer si playertouche une des bombes de bomb, sur un modèle similaire à ce qui a été fait avec les stars. On ajoute la fonction suivante.

function hitBomb (player, bomb)

{

   this.physics.pause();

   player.setTint(0xff0000);

   player.anims.play(‘turn’);

   gameOver = true;

}

Cette fonction :

  • met le modèle physique en pause (tout se fige)
  • colore playeren rouge
  • lance l’animation turnpour que playersoit en position immobile
  • met gameOvera vrai.

Dans la fonction create(), on dit tout simplement d’exécuter la fonction hitBombsi playerintersecte avec bombs :

    this.physics.add.collider(player, bombs, hitBomb, null, this);

Retrouvez le code HTML de départ, les images utilisées (répertoire Asssets), et le code HTML des différentes étapes en téléchargeant l’archive zip associée à ce tutoriel :T


Tags: ,

Aucune réponse

Laisser un commentaire

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