Aller au contenu

Déplacements 2/2

Dimensions du jeu vidéo : Je suggère d'utiliser une résolution maximale de 1280x720 (HD), idéalement 960x600 (WebGL). C'est le bon compromis entre qualité visuelle et performance. De plus, ca doit entrer dans l'interace itch.io.

Variables dans Phaser : this.ma_variable ou let ma_variable ?

Github 🤷‍♂️

Saut simple

Changement de la zone de collision.

Aperçu
class Example extends Phaser.Scene {
  preload() {
    // ...
  }

  create() {
    // Plateformes
    this.platforms = this.physics.add.staticGroup();
    this.platforms.create(600, 300, "ground");

    // Joueur
    this.player = this.physics.add.sprite(config.width / 2, 200, "dude");
    this.player.setBounce(0);
    this.player.body.setGravityY(1000);
    this.physics.add.collider(this.player, this.platforms);

    // Contrôles
    this.cursors = this.input.keyboard.createCursorKeys();
  }

  update() {
    // Saut
    if (this.cursors.up.isDown && this.player.body.blocked.down) {
      this.player.setVelocityY(-500);
    }
    // ...
  }
}

const config = {
  // ...
  physics: {
    default: "arcade"
  }
};

refreshBody()

Dans un groupe static, si on change l'attribut d'une image (ex: son origine, son scale), il faut appeler la fonction refreshBody() pour appliquer les changements.

this.platforms.create(600, 300, "ground").setScale(3).refreshBody();

blocked vs. touching

this.monBonhomme.body.blocked.down est spécifique aux collisions avec des objets statiques ou les bordures du monde (par exemple, le sol ou un mur solide).

this.monBonhomme.body.touching.down détecte toute collision dans la direction bas, que ce soit avec un objet mobile ou statique.

Double saut

Si le joueur (this.player) entre en collision avec this.platforms (par exemple, en atterrissant sur une plateforme), une fonction de rappel (callback) sera exécutée.

create()
this.jumpCount = 0;
this.jumpKeyReleased = true;

this.physics.add.collider(this.player, this.platforms, () => {
    this.jumpCount = 0;
    this.jumpKeyReleased = true;
});
update()
// Vérifie si la touche de saut est relâchée
if (this.keys.jump.isUp) {
  this.jumpKeyReleased = true;
}

// Le joueur peut sauter si :
//   - la touche de saut est enfoncée
//     ET
//   - la touche de saut a été relâchée
//     ET
//   - il est au sol OU le nombre de sauts est inférieur à 2
if (this.keys.jump.isDown && this.jumpKeyReleased && (this.player.body.touching.down || this.jumpCount < 2)) {
  this.player.setVelocityY(-500);
  this.jumpCount++;
  this.jumpKeyReleased = false; // Empêche de maintenir la touche pour continuer à sauter
}

Tomber d'une plateforme

Il est possible de désactiver la collision entre deux objets ou ensemble d'objets. C'est exactement ce que nous devons faire pour passer à travers une plateforme.

Lorsqu'on clique sur la touche du saut en même temps que la touche vers le bas, on peut, à ce moment précis, déclencher la désactivation de la collision. Voici comment faire.

create()
// Mettre la collision dans une variable
this.playerCollider = this.physics.add.collider(
  this.player,
  this.platforms
);
update()
// Saut
if (this.cursors.jump.isDown && this.player.body.blocked.down) {
  this.player.setVelocityY(-500);
}

// Tomber à travers la plateforme
if (
  this.cursors.down.isDown &&
  this.cursors.jump.isDown &&
  this.player.body.touching.down
) {
  // Désactivation de la collision et changement de direction
  this.playerCollider.active = false;
  this.player.setVelocityY(300);
} else {
  this.playerCollider.active = true;
}

Collision uni-directionnelle

Parfois, on souhaite que seule la surface du dessus d’une forme détecte une collision. Ça peut rendre l’expérience utilisateur plus fluide et moins restrictive. Pour ce faire, il suffit d’utiliser les propriétés (up, down, right, left) de l’objet checkCollision.

create()
// Plateformes
this.platforms = this.physics.add.staticGroup();
this.platforms.create(400, 400, "ground");
this.platforms.create(400, 200, "ground");
this.platforms.create(200, 300, "ground");

this.platforms.children.iterate((platform) => {
  platform.body.checkCollision.up = true;
  platform.body.checkCollision.down = false;
  platform.body.checkCollision.right = false;
  platform.body.checkCollision.left = false;
});

Course

Pour courir, c’est assez simple : lorsque vous appuyez sur une touche de déplacement, puis simultanément sur la touche Shift, la vélocité du personnage est augmentée. Tout simplement.

create()
this.walkSpeed = 150;
this.runSpeed = 400;
update()
let velocity = this.walkSpeed;

// Si Shift est pressé, on court
if (this.cursors.shift.isDown) {
  velocity = this.runSpeed;
}

// Déplacement
if (this.cursors.left.isDown) {
  this.player.setVelocityX(-velocity);
} else if (this.cursors.right.isDown) {
  this.player.setVelocityX(velocity);
} else {
  this.player.setVelocityX(0);
}

Caméra (introduction)

Si la taille de votre scène dépasse celle de la caméra, vous voudrez sans doute déplacer la caméra en même temps que votre personnage.

Pour ce faire, vous pouvez configurer la caméra pour qu’elle suive le joueur, tout en ajustant les limites X et Y pour empêcher la caméra de sortir de la scène.

// Talonner
this.cameras.main.startFollow(this.player);
this.cameras.main.setZoom(1);
this.cameras.main.setBounds(0, 0, mapWidth, mapHeight); // limites de la caméra

// Limites du monde
this.physics.world.setBounds(0, 0, config.width, config.height);

Le texte suit aussi la caméra ?

En appliquant la fonction .setScrollFactor(0); au texte, il n'est pas influencé par le déplacement de la caméra. Très utile un votre HUD 😉😉😉

Déplacement d'objet

Pour déplacer des objets, il faut simplement ne pas les assigner en tant qu'élément statique. Voici un exemple.

//...

this.cubes = this.physics.add.group();
const cube1 = this.cubes.create(150, 200, "cube");
const cube2 = this.cubes.create(300, 200, "cube");
const cube3 = this.cubes.create(450, 300, "cube");

this.cubes.children.iterate((cube) => {
  cube.setMaxVelocity(50, 500);
  cube.setDragX(500);
  cube.setGravityY(3000);
});

// Collision de tout avec tout
const allObjects = [this.player, this.cubes, this.platforms];
this.physics.add.collider(allObjects, allObjects);

Tiled 🥳

Tiled

Tiled est un éditeur de niveaux gratuit et open source. Il nous permettera de contruire nos niveau avec une logique de tileset et de tilemap dans Phaser1.

  • Tileset

    Un tileset est une collection d’images, souvent regroupées dans une seule image (spritesheet), contenant de petites images appelées tuiles (tiles).

    Tileset

  • Tilemap

    Un tilemap est une carte constituée d’un agencement de tiles provenant d’un ou plusieurs tilesets. C’est comme une grille où chaque cellule fait référence à un tile spécifique.

    Tilemap

Perspectives

Jeu de plateforme de type side-scroller

Jeu en vue de dessus (top-down)

Parmi les perspectives, on compte également la vue isométrique, la vue à la première personne et la vue à la troisième personne, mais ce sont des cas plus rares en 2D.

Application en Phaser

preload()
this.load.tilemapTiledJSON("clefDuTilemap", "./destination/de/votre/export.json");
this.load.image("imageDuTileset", "./destination/de/votre/image.png");
create()
// Tilemap
const maCarte = this.make.tilemap({ key: "clefDuTilemap" });

// Tileset
const tileset = maCarte.addTilesetImage("nomDuTilesetDansTiled", "imageDuTileset");

// Calques
const bgLayer = maCarte.createLayer("nomDuCalque1", [tileset], 0, 0);
const collisionLayer = maCarte.createLayer("nomDuCalque2", [tileset], 0, 0);
// Si un calque contien des zones de collision (variable custom dans Tiled)
collisionLayer.setCollisionByProperty({ collision: true });

// Par la suite on peut appliquer une collision avec le layer
// Ex: this.physics.add.collider(this.player, collisionLayer);

Demo

Exercice

Exercice - Phaser
Les ponts de la mort

Devoir

Devoir - Phaser
Mouvement