class Example extends Phaser.Scene {
  preload() {
    this.load.image(
      "bullet",
      "https://assets.codepen.io/9367036/1bit-projectile.png"
    );
    this.load.image(
      "enemyBullet",
      "https://assets.codepen.io/9367036/1bit-enemy-projectile.png"
    );
    this.load.image(
      "ship",
      "https://assets.codepen.io/9367036/1bit-player.png"
    );
    this.load.image(
      "starfield",
      "https://assets.codepen.io/9367036/background_1.png"
    );
    this.load.spritesheet(
      "enemy",
      "https://assets.codepen.io/9367036/1bit-enemy.png",
      {
        frameWidth: 64,
        frameHeight: 64
      }
    );
  }

  create() {
    // Arrière plan
    this.stars = this.add
      .tileSprite(0, 0, 800, 400, "starfield")
      .setOrigin(0, 0);

    // Ennemie
    this.enemy = this.physics.add.sprite(50, 128, "enemy", 0);
    this.enemy.setScale(2);
    this.enemy.pointsDeVie = 5;
    this.enemyMoving = this.tweens.add({
      targets: this.enemy,
      x: config.width - 50,
      duration: 3000,
      ease: "Linear",
      yoyo: true,
      repeat: -1
    });
    this.enemyBullets = this.physics.add.group({
      defaultKey: "enemyBullet",
      maxSize: 5
    });
    this.enemyFiring = this.time.addEvent({
      delay: 666,
      loop: true,
      callback: () => {
        const bullet = this.enemyBullets.get(this.enemy.x, this.enemy.y + 32);
        if (bullet) {
          bullet.setActive(true);
          bullet.setVisible(true);
          bullet.setVelocity(0, 200);
        }
      }
    });

    // Joueur
    this.player = this.physics.add.sprite(256, config.height - 50, "ship");
    this.player.setScale(2);
    this.bullets = this.physics.add.group({
      defaultKey: "bullet",
      maxSize: 1
    });

    // Collisions
    this.physics.add.overlap(this.enemy, this.bullets, (enemy, bullet) => {
      enemy.pointsDeVie -= 1;
      bullet.setActive(false);
      bullet.setVisible(false);
      bullet.y = -999999;

      if (enemy.pointsDeVie <= 0) {
        this.enemyFiring.remove();
        this.enemyMoving.stop();
        enemy.body.checkCollision.none = true;
        enemy.destroy();
      }
    });
    this.physics.add.overlap(
      this.player,
      this.enemyBullets,
      (player, bullet) => {
        bullet.setActive(false);
        bullet.setVisible(false);
        bullet.y = -999999;
      }
    );

    // Événements / Contrôles
    this.input.on("pointermove", (pointer) => {
      this.player.x = pointer.worldX;
    });
    this.input.on("pointerdown", () => {
      const bullet = this.bullets.get(this.player.x, this.player.y);
      if (bullet) {
        bullet.setActive(true);
        bullet.setVisible(true);
        bullet.setVelocity(0, -666);
      }
    });
  }

  update() {
    // Lorsqu'une balle sort de la zone visible du jeu, on la désactive et on la cache.
    this.bullets.children.each((bullet) => {
      let cachee = !this.cameras.main.worldView.contains(bullet.x, bullet.y);
      if (bullet.active && cachee) {
        bullet.setActive(false);
        bullet.setVisible(false);
      }
    });

    // Lorsqu'une balle sort de la zone visible du jeu, on la désactive et on la cache.
    this.enemyBullets.children.each((bullet) => {
      let cachee = !this.cameras.main.worldView.contains(bullet.x, bullet.y);
      if (bullet.active && cachee) {
        bullet.setActive(false);
        bullet.setVisible(false);
      }
    });
  }
}

const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 400,
  pixelArt: true,
  parent: "phaser-example",
  physics: {
    default: "arcade",
    arcade: { debug: false }
  },
  scene: Example
};

const game = new Phaser.Game(config);

activateControls(["LMB"]);
Run Pen

External CSS

  1. https://codepen.io/tim-momo/pen/yLWvyra.css
  2. https://fonts.googleapis.com/css2?family=DotGothic16&amp;display=swap

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/phaser/3.85.1/phaser.min.js
  2. https://codepen.io/tim-momo/pen/yLWvyra.js