Code viewer for World: Phaser Chaser

// Cloned by Paul Bashford on 20 Aug 2023 from World "Phaser test World " by Mark Humphrys 
// Please leave this clone trail here.
 

// port of the start of this tutorial:
// https://medium.com/@joseph.a.guzzardo/intro-to-phaser-for-javascript-6bf4b5a09085

// code basically unchanged - just put inside a getScript 

// did up as far as creation of player and physics
// next step would be to add the stars



// assets from:
// https://phaser.io/tutorials/making-your-first-phaser-3-game/phaser3-tutorial-src.zip
// missing - got them from Internet Archive 

// https://github.com/photonstorm/phaser

  
 

$.getScript("https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js", function() {
  var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    preserveDrawingBuffer: true,
    scene: {
      preload: preload,
      create: create,
      update: update
    },
    physics: {
      default: "arcade",
      arcade: {
        gravity: { y: 300 },
        debug: false
      }
    }
  };

  window.addEventListener('resize', onWindowResize, false );

  function onWindowResize(){
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth,window.innerHeight)
  }

  var game = new Phaser.Game(config);
  var platforms, player, player2, player3, cursors, cursors2;
  var scoreText1, scoreText2;
  var score1 = 0, score2 = 0;
  var timerText;
  var timerEvent;
  var timeLeft = 60;
  var chaseTarget;
  var stars; // Group to hold stars
  var starSpawnTimerEvent; // Timer event for spawning stars

  function preload() {
    this.load.image("sky", "/uploads/humphrys/sky.png");
    this.load.image("ground", "/uploads/humphrys/platform.png");
    this.load.image("star", "/uploads/humphrys/star.png");
    this.load.image("bomb", "/uploads/humphrys/bomb.png");
    this.load.image("freeze", "/uploads/paulbashford/freeze.png");
    this.load.spritesheet("dude", "/uploads/humphrys/dude.png", {
      frameWidth: 32,
      frameHeight: 48
    });

    // Load assets for the second player
    this.load.spritesheet("dude2", "/uploads/paulbashford/dude2.png", {
      frameWidth: 32,
      frameHeight: 48
    });

    this.load.spritesheet("dude3", "/uploads/paulbashford/dude3.png", {
      frameWidth: 32,
      frameHeight: 48
    });
  }

  function create() {
    this.add.image(400, 300, "sky");

    platforms = this.physics.add.staticGroup();
    platforms.create(400, 568, "ground").setScale(2).refreshBody();
    platforms.create(600, 400, "ground");
    platforms.create(50, 250, "ground");
    platforms.create(750, 220, "ground");

    player = this.physics.add.sprite(100, 450, "dude");
    player.setBounce(0.2);
    player.setCollideWorldBounds(true);
    this.physics.add.collider(player, platforms);
    this.anims.create({
      key: "left",
      frames: this.anims.generateFrameNumbers("dude", { start: 0, end: 3 }),
      frameRate: 10,
      repeat: -1
    });
    this.anims.create({
      key: "turn",
      frames: [{ key: "dude", frame: 4 }],
      frameRate: 20
    });
    this.anims.create({
      key: "right",
      frames: this.anims.generateFrameNumbers("dude", { start: 5, end: 8 }),
      frameRate: 10,
      repeat: -1
    });
    cursors = this.input.keyboard.createCursorKeys();

    // Create the second player
    player2 = this.physics.add.sprite(200, 450, "dude2");
    player2.setBounce(0.2);
    player2.setCollideWorldBounds(true);
    this.physics.add.collider(player2, platforms);
    this.anims.create({
      key: "left2",
      frames: this.anims.generateFrameNumbers("dude2", { start: 0, end: 3 }),
      frameRate: 10,
      repeat: -1
    });
    this.anims.create({
      key: "turn2",
      frames: [{ key: "dude2", frame: 4 }],
      frameRate: 20
    });
    this.anims.create({
      key: "right2",
      frames: this.anims.generateFrameNumbers("dude2", { start: 5, end: 8 }),
      frameRate: 10,
      repeat: -1
    });
    cursors2 = this.input.keyboard.addKeys({
      up: Phaser.Input.Keyboard.KeyCodes.W,
      down: Phaser.Input.Keyboard.KeyCodes.S,
      left: Phaser.Input.Keyboard.KeyCodes.A,
      right: Phaser.Input.Keyboard.KeyCodes.D
    });

    // Create the third AI player
    player3 = this.physics.add.sprite(400, 300, "dude3");
    player3.setBounce(0.2);
    player3.setCollideWorldBounds(true);
    this.physics.add.collider(player3, platforms);
    this.anims.create({
      key: "left3",
      frames: this.anims.generateFrameNumbers("dude3", { start: 0, end: 3 }),
      frameRate: 10,
      repeat: -1
    });
    this.anims.create({
      key: "right3",
      frames: this.anims.generateFrameNumbers("dude3", { start: 5, end: 8 }),
      frameRate: 10,
      repeat: -1
    });

    // Choose a target for the AI player to chase
    chaseTarget = Math.random() < 0.5 ? player : player2;

    // Create score display
    scoreText1 = this.add.text(16, 16, "Player 1: 0", {
      fontSize: "32px",
      fill: "#fff"
    });

    scoreText2 = this.add.text(16, 50, "Player 2: 0", {
      fontSize: "32px",
      fill: "#fff"
    });

    // Create timer display
    timerText = this.add.text(650, 16, "Time: " + timeLeft, {
      fontSize: "32px",
      fill: "#fff"
    });

    // Create timer event
    timerEvent = this.time.addEvent({
      delay: 1000,
      callback: updateTimer,
      callbackScope: this,
      loop: true
    });

    // Create a group to hold stars
    stars = this.physics.add.group();

    // Set up timer event for spawning stars
    starSpawnTimerEvent = this.time.addEvent({
      delay: 2000, // Adjust the delay as needed
      callback: spawnStar,
      callbackScope: this,
      loop: true
    });
  }

  function update() {
    if (cursors.left.isDown) {
      player.setVelocityX(-160);
      player.anims.play("left", true);
    } else if (cursors.right.isDown) {
      player.setVelocityX(160);
      player.anims.play("right", true);
    } else {
      player.setVelocityX(0);
      player.anims.play("turn");
    }

    if (cursors.up.isDown && player.body.touching.down) {
      player.setVelocityY(-330);
    }

    // Controls for the second player
    if (cursors2.left.isDown) {
      player2.setVelocityX(-160);
      player2.anims.play("left2", true);
    } else if (cursors2.right.isDown) {
      player2.setVelocityX(160);
      player2.anims.play("right2", true);
    } else {
      player2.setVelocityX(0);
      player2.anims.play("turn2");
    }

    if (cursors2.up.isDown && player2.body.touching.down) {
      player2.setVelocityY(-330);
    }

    // Update AI player (player3) behavior
    var speed = 100;
    if (player3.x < chaseTarget.x) {
      player3.setVelocityX(speed);
      player3.anims.play("right3", true);
    } else if (player3.x > chaseTarget.x) {
      player3.setVelocityX(-speed);
      player3.anims.play("left3", true);
    } else {
      player3.setVelocityX(0);
    }

    // Check if player 3 catches a target player (player 1 or player 2)
    if (Phaser.Math.Distance.Between(player3.x, player3.y, chaseTarget.x, chaseTarget.y) < 20) {
      // Decrease player 1's or player 2's score
      if (chaseTarget === player) {
        score1--;
        scoreText1.setText("Player 1: " + score1);
      } else {
        score2--;
        scoreText2.setText("Player 2: " + score2);
      }

      // Respawn player 3 and choose a new target
      player3.x = 400;
      player3.y = 300;
      player3.setVelocity(0);
      chaseTarget = chaseTarget === player ? player2 : player;
    }
  }

  function spawnStar() {
    var x = Phaser.Math.Between(0, 800); // Random x-coordinate
    var y = Phaser.Math.Between(0, 600); // Random y-coordinate

    var randomItem = Math.random();

    if (randomItem < 0.8) {
      // Spawn a star
      var star = stars.create(x, y, "star");
      star.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8)); // Random bounce

      // Collider for stars with platforms
      this.physics.add.collider(star, platforms);

      // Overlap check between stars and players
      this.physics.add.overlap(player, stars, collectStar, null, this);
      this.physics.add.overlap(player2, stars, collectStar, null, this);
    } else {
      // Spawn the freeze item
      var freezeItem = stars.create(x, y, "freeze");
      freezeItem.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8)); // Random bounce

      // Collider for freeze items with platforms
      this.physics.add.collider(freezeItem, platforms);

      // Overlap check between freeze items and players
      this.physics.add.overlap(player, freezeItem, collectFreezeItem, null, this);
      this.physics.add.overlap(player2, freezeItem, collectFreezeItem, null, this);
    }
  }

  function collectStar(x, star) {
    star.disableBody(true, true); // Remove star on collection

    // Determine which player collected the star and increase their score
    if (x === player) {
      // Player 1 collected the star
      score1 += 10; // Adjust the score increment as needed
      scoreText1.setText("Player 1: " + score1);
    } else if (x === player2) {
      // Player 2 collected the star
      score2 += 10; // Adjust the score increment as needed
      scoreText2.setText("Player 2: " + score2);
    }
  }

function collectFreezeItem(x, freezeItem) {
  freezeItem.disableBody(true, true); // Remove freeze item on collection

  // Identify the opposite player
  var oppositePlayer = x === player2 ? player : player2;

  // Freeze the opposite player
  oppositePlayer.setVelocity(0);
}

  function updateTimer() {
    // Update the timer
    timeLeft--;
    timerText.setText("Time: " + timeLeft);

    if (timeLeft === 0) {
      // Stop the timer event
      timerEvent.remove();
      
      // Determine the winner
        var winnerText;
        if (score1 > score2) {
          winnerText = "Player 1 Wins!";
        } else if (score2 > score1) {
          winnerText = "Player 2 Wins!";
        } else {
          winnerText = "It's a Tie!";
        }

      // Display a game over message
      this.add.text(400, 300, winnerText, {
        fontSize: "48px",
        fill: "#ff0000"
      }).setOrigin(0.5);
      this.scene.pause() // pause game when timer runs out
    }
  }
});