<footer><div id=version></div></footer>
html, body {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  background: #111 url(https://labs.phaser.io/assets/sprites/phaser3-logo-small.png) no-repeat left top;
  color: #eee;
  font: caption;
}

#version {
  position: absolute;
  left: 0;
  top: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.5)
}
/* global colors, Phaser */

var SPEEDX = 160;
var SPEEDY = -320;
var SPEED = Math.hypot(SPEEDX, SPEEDY);

var { red, green } = colors.hexColors;

var Breakout = new Phaser.Class({
  Extends: Phaser.Scene,

  initialize: function Breakout() {
    Phaser.Scene.call(this, { key: "breakout" });

    this.bricks;
    this.paddle;
    this.ball;
  },

  preload: function () {
    this.load.atlas(
      "assets",
      "assets/games/breakout/breakout.png",
      "assets/games/breakout/breakout.json"
    );
  },

  create: function () {
    this.physics.world.debugGraphic.defaultStrokeWidth = 2;

    //  Create the bricks in a 10x6 grid
    this.bricks = this.physics.add.staticGroup({
      key: "assets",
      frame: ["blue1", "red1", "green1", "yellow1", "silver1", "purple1"],
      frameQuantity: 10,
      gridAlign: {
        width: 10,
        height: 6,
        cellWidth: 64,
        cellHeight: 32,
        x: 112,
        y: 100
      }
    });

    this.balls = this.physics.add.group({
      key: "assets",
      frame: "ball2",
      quantity: 20,
      setXY: { x: 64, y: 640, stepX: 64, stepY: 0 },
      bounceX: 1,
      bounceY: 1,
      collideWorldBounds: true,
      velocityX: SPEEDX,
      velocityY: SPEEDY,
      createCallback: (ball) => {
        ball.body.setCircle(10);
      }
    });

    this.paddle = this.physics.add
      .image(400, 550, "assets", "paddle1")
      .setImmovable();

    //  Our colliders
    this.physics.add.collider(
      this.balls,
      this.bricks,
      this.hitBrick,
      null,
      this
    );

    //  Input events
    this.input.on(
      "pointermove",
      function (pointer) {
        //  Keep the paddle within the game
        this.paddle.x = Phaser.Math.Clamp(pointer.x, 52, 748);
      },
      this
    );
  },

  hitBrick: function (ball, brick) {
    brick.disableBody(true, true);

    if (this.bricks.countActive() === 0) {
      this.resetLevel();
    }
  },

  resetBall: function () {},

  resetLevel: function () {
    this.bricks.children.each(function (brick) {
      brick.enableBody(false, 0, 0, true, true);
    });
  },

  hitPaddle: function (ball, paddle) {},

  update: function () {
    // Verify the speed is nearly constant
    for (const ball of this.balls.getChildren()) {
      ball.body.debugBodyColor = Phaser.Math.Fuzzy.Equal(
        ball.body.speed,
        SPEED,
        1
      )
        ? green
        : red;
    }
  }
});

var config = {
  width: 800,
  height: 600,
  scene: [Breakout],
  physics: {
    default: "arcade",
    arcade: { debug: true }
  },
  loader: {
    baseURL: "https://labs.phaser.io",
    crossOrigin: "anonymous"
  }
};

document.getElementById("version").textContent = `Phaser v${Phaser.VERSION}`;

new Phaser.Game(config);
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js
  2. https://cdn.jsdelivr.net/npm/@samme/colors@1.2.0/dist/colors.umd.js