<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 0 20px;
  color: #eee;
  font: caption;
}

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

let background;
let bird;
let ground_physics;
let isJumping;
let margin;
let pipes;
let spaceBar;

// Generate a random integer between min (inclusive) and max (inclusive)
function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

class GamePlay extends Phaser.Scene {
  constructor() {
    super("game");
  }

  preload() {
    this.load.image("ground", "assets/sprites/32x32.png");
    this.load.image("pipe", "assets/sprites/32x32.png");
    this.load.image("pipe180", "assets/sprites/32x32.png");
    //
    this.load.image("background", "assets/pics/platformer-backdrop.png");
    this.load.spritesheet("chick", "assets/sprites/chick.png", {
      frameWidth: 16,
      frameHeight: 18
    });
  }

  create() {
    console.log("game started");

    // Create the background sprite
    // background = this.add.sprite(0, 0, "background").setOrigin(0, 0);

    // Physics for pipes
    margin = 200;
    pipes = this.physics.add.staticGroup();
    for (var i = 0; i < 20; i++) {
      let randomY = getRandomInt(200, 400);
      pipes
        .create(400 + margin, randomY, "pipe")
        .setOrigin(0, 0)
        .refreshBody();
      pipes
        .create(400 + margin, randomY - getRandomInt(100, 200), "pipe180")
        .setOrigin(0, 1)
        .refreshBody();
      margin += 400;
    }

    // Physics for ground
    ground_physics = this.physics.add.staticGroup();
    ground_physics.create(0, 500, "ground").setOrigin(0, 0).refreshBody();
    ground_physics.create(468, 500, "ground").setOrigin(0, 0).refreshBody();

    // Create the bird sprite
    bird = this.physics.add.sprite(170, 250, "bird1"); // Adjust the position as needed

    this.anims.create({
      key: "birdAnimation",
      frames: "chick",
      frameRate: 15, // Frames per second (e.g., 24)
      repeat: -1 // -1 means the animation repeats indefinitely
    });

    // Play the "birdAnimation" when a specific event occurs
    bird.play("birdAnimation");

    spaceBar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);

    // Check for collisions
    this.physics.add.collider(bird, pipes, Callback);
    this.physics.add.collider(bird, ground_physics, Callback);

    function Callback() {
      console.log("");
    }
  }

  update() {
    // Scroll the ground horizontally
    let scrollSpeed = 3; // Adjust the scrolling speed as needed
    ground_physics.children.iterate((item) => {
      item.x -= scrollSpeed;
      // Reset if it has gone off screen
      if (item.x + 468 <= 0) {
        item.x = 468;
      }
    });

    // Scroll the pipes horizontally
    pipes.children.iterate((item) => {
      item.x -= scrollSpeed;
      item.body.x -= scrollSpeed;
    });

    // Trigger jump animation when space key is pressed
    isJumping = false;
    console.log(isJumping);

    if (Phaser.Input.Keyboard.JustUp(spaceBar) && !isJumping) {
      console.log("click");
      bird.setVelocityY(-350); //-350
      isJumping = true;
    }

    // Handle touch input
    if (game.input.activePointer.isDown && !isJumping) {
      console.log("touch");
      bird.setVelocityY(-350); //-350
      isJumping = true;
    }

    if (isJumping) {
      // Apply gravity while the bird is in the air
      bird.setGravityY(750); //750
      console.log(isJumping);
    }

    // If bird is going up or down tilt angle
    bird.angle = Math.min(90, bird.body.velocity.y * 0.15);
  }
}

// Pointer debugging below:

const { PRE_RENDER, POST_RENDER } = Phaser.Core.Events;
const { PI2 } = Phaser.Math;
const { red, green, yellow, fuchsia, white } = colors.cssColors;

const POINTER_DOWN_COLOR = green;
const POINTER_ACTIVE_COLOR = yellow;
const POINTER_INACTIVE_COLOR = red;
const POINTER_CANCELED_COLOR = fuchsia;
const POINTER_ALPHA = 0.6;
const POINTER_RADIUS = 20;

class DebugPointerPlugin extends Phaser.Plugins.BasePlugin {
  init() {
    const { input, renderer } = this.game;

    if (!renderer || renderer.type !== Phaser.CANVAS) {
      throw new Error("CANVAS renderer only");
    }

    console.info("%s total pointers?", input.pointersTotal);
  }

  start() {
    this.game.events.on(POST_RENDER, this.render, this);
  }

  stop() {
    this.game.events.off(POST_RENDER, this.render, this);
  }

  render() {
    const { context } = this.game;

    context.font = "24px monospace";
    context.globalAlpha = POINTER_ALPHA;
    context.textBaseline = "top";

    this.game.input.pointers.forEach(this.renderPointer, this);
  }

  renderPointer(pointer) {
    const { x, y, id, event } = pointer;
    const { context } = this.game;

    if (pointer.isDown) {
      context.fillStyle = POINTER_DOWN_COLOR;
    } else if (pointer.active) {
      context.fillStyle = POINTER_ACTIVE_COLOR;
    } else if (pointer.wasCanceled) {
      context.fillStyle = POINTER_CANCELED_COLOR;
    } else {
      context.fillStyle = POINTER_INACTIVE_COLOR;
    }

    context.beginPath();
    context.arc(x, y, POINTER_RADIUS, 0, PI2);
    context.fill();
    context.closePath();

    context.fillStyle = white;
    context.fillText(`${id} ${event?.type || ""}`, x, y);
  }
}

const config = {
  type: Phaser.CANVAS,
  width: 640,
  height: 512,
  pixelArt: true,
  scene: GamePlay,
  loader: {
    baseURL: "https://labs.phaser.io",
    crossOrigin: "anonymous"
  },
  physics: {
    default: "arcade",
    arcade: {
      gravity: { y: 300 },
      debug: true
    }
  },
  plugins: {
    global: [
      { plugin: DebugPointerPlugin, key: "DebugPointerPlugin", start: true }
    ]
  }
};

const game = new Phaser.Game(config);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

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