Collision callback not modifying object as expected

I’m making a two-player game and attempting to store state for each player on the sprite object that is created for each player but I’m seeing unexpected results.

I’ve created a simplified branch of my repo here and I’ve included the relevant code for my scene below.

In my create function, I’m trying to set ball possession to player1, which should then put the ball right next to the player but for some reason the possession is never set. You can see from the console log that neither player is given possession.

Is there an issue with adding properties to a sprite object? Is there another way I can do this? Or is the issue somewhere else entirely?

import Phaser from 'phaser';
import ballImg from './assets/ball.png';
import playerImg from './assets/paddle.png';
import player2Img from './assets/paddle-2.png';
import courtImg from './assets/court.png';

export default class Play extends Phaser.Scene {
  constructor() {
    super('gameplay');

    this.playerMovement = {
      gravity: 1000,
    };

    this.PLAYERS = {
      PLAYER1: 'player1',
      PLAYER2: 'player2',
    };

    this.player1;
    this.player2;
    this.players = [];
    this.ball;
    this.court;
  }

  preload() {
    this.load.image('ball', ballImg);
    this.load.image('player', playerImg);
    this.load.image('player2', player2Img);
    this.load.image('court', courtImg);
  }

  create() {
    this.player1 = this.physics.add.sprite(
      100,
      this.physics.world.bounds.height / 2,
      'player'
    );
    this.player1.setBounce(0, 0);
    this.player1.setGravityY(this.playerMovement.gravity);
    this.player1.playerNum = 1;
    this.player1.hasPossession = true;
    this.players.push(this.player1);

    this.rebounderPosition = this.physics.world.bounds.width * 0.75;
    this.player2 = this.physics.add.sprite(
      this.rebounderPosition,
      this.physics.world.bounds.height / 2,
      'player2'
    );
    this.player2.setBounce(0, 0);
    this.player2.setGravityY(this.playerMovement.gravity);
    this.player2.playerNum = 2;
    this.player2.hasPossession = false;
    this.players.push(this.player2);

    this.ball = this.physics.add.sprite(0, 0, 'ball');
    const ballPos = this.getBallRelativeToShooter(this.ball, this.player1);
    this.ball.body.x = ballPos.x;
    this.ball.body.y = ballPos.y;
    this.ball.setBounce(0.5, 0.5);
    this.ball.setGravityY(1000);

    this.court = this.physics.add.sprite(
      this.physics.world.bounds.width / 2,
      this.physics.world.bounds.height - 50,
      'court'
    );
    this.court.setImmovable();

    this.physics.add.collider(
      this.player1,
      this.ball,
      this.setPlayerPossession.bind(this)
    );
    this.physics.add.collider(this.ball, this.court);
    this.physics.add.collider(this.player1, this.court);
    this.physics.add.collider(this.player2, this.court);
    this.physics.add.collider(
      this.player2,
      this.ball,
      this.setPlayerPossession.bind(this)
    );
    this.physics.add.collider(this.player1, this.backboard);

    // First shooter is player1
    this.setPlayerPossession(this.player1);
  }

  update() {
    if (this.player1.hasPossession) {
      console.log('1 person');
      const ballPos = this.getBallRelativeToShooter(this.ball, this.player1);
      this.ball.body.x = ballPos.x;
      this.ball.body.y = ballPos.y;
    } else if (this.player2.hasPossession) {
      console.log('2 person');
      const ballPos = this.getBallRelativeToShooter(this.ball, this.player2);
      this.ball.body.x = ballPos.x;
      this.ball.body.y = ballPos.y;
    } else {
      console.log('Why does it hit this?');
    }
  }

  getPlayerKey(playerIndex) {
    return Object.values(this.PLAYERS)[playerIndex];
  }

  getBallRelativeToShooter(ball, player) {
    return {
      x: player.x + player.body.width / 2 + 5,
      y: player.y - player.body.height / 2,
    };
  }

  setPlayerPossession(player) {
    console.log(player);
    if (!player) {
      this.player1.hasPossession = false;
      this.player2.hasPossession = false;
      return;
    }

    player.hasPossession = true;
    const otherPlayer = this.getOtherPlayer(player);
    otherPlayer.hasPossession = false;
  }

  getOtherPlayer(player) {
    return this.players[(player.playerNum + 1) % 2];
  }
}

Hi, I guess you have to use the Phaser DataManager
https://photonstorm.github.io/phaser3-docs/Phaser.Data.DataManager.html

player.data.set("hasPossession", true)
player.data.get("hasPossession")
1 Like

Hi,
I found the bug, it comes from the getOtherPlayer, that return player1 instead of player 2
In create i added the name of the player:

this.player1.setBounce(0, 0).setName('player1');
this.player2.setBounce(0, 0).setName('player2');

and getOtherPlayer becomes:

getOtherPlayer(player) {
  if (player.name === 'player1') return this.player2;
  if (player.name === 'player2') return this.player1;
}

And it works now, so you know that

return this.players[(player.playerNum + 1) % 2];

doesn’t work as you expect.

1 Like
function setPlayerPossession (player) {
  this.player1.hasPossession = false;
  this.player2.hasPossession = false;
  
  console.log(player);

  if (!player) {
    return;
  }

  player.hasPossession = true;
}

Indeed, this was returning the right player here, which confused me especially but ultimately the issue was what @BlunT76 had mentioned. My logic in the getOtherPlayer function was off and causing the issue :man_facepalming:

I did end up replacing all custom keys on my sprite objects with getters or setters to the data object, after using this.player1.setDataEnabled(). It seems to be working fine but for my use case I guess I could have been fine with just dropping the custom values on the object itself.