'It seems Phaser 3 throws "animationcomplete" notification twice for a single animation, how do I make it one?

I'm confused about the 'animationcomplete' notification. I thought I would receive the notification one time when the animation I listen finishes. It turns out I will receive the notification n times. Here is the code.

class BootScene extends Phaser.Scene {
  constructor() {
    super({ key: 'BootScene' });
  }
  preload() {
    this.load.spritesheet('brawler', 'https://raw.githubusercontent.com/photonstorm/phaser3-examples/master/public/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
  }
  create() {

    this.anims.create({
      key: 'win',
      frames: this.anims.generateFrameNumbers('brawler', { frames: [ 30, 31 ] }),
      frameRate: 8,
      repeat: 0,
    });
    const cody = this.add.sprite(200, 70);
    cody.setScale(8);

    let btn = this.add.rectangle(500, 70, 200, 150, '#000')
    this.add.text(500, 70, 'click')

    btn.setInteractive();
    btn.on('pointerdown', () => {
      console.log('pointerdown');
      cody.play('win');
      cody.on('animationcomplete', (e) => {
        console.log(e.key);
      });
    });
  }
}

var config = {
  width: 800,
  height: 500,
  backgroundColor: '#555',
  scene: [BootScene]
}

var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

I put two console.log in there, one for pointerdown and the other for animationcomplete.

First time I click the btn, I get one pointerdown and one animationcomplete. Second time I click the btn, I get one pointerdown and two animationcomplete.

How do I get just one animationcomplete no matter I click the btn n-th time?



Solution 1:[1]

As @Ourobours mentioned you are attaching, on each click, new event handler for animationcomplete.
An Since you can attach multiple event-handlers for the same event, all of them will be executed the next time it fires, ans so on.

You would only have to move the animationcomplete event-handler out of the pointerdown event handler function, and everything should work as you would expect it.

Here a working demo:

class BootScene extends Phaser.Scene {
  constructor() {
    super({ key: 'BootScene' });
  }
  preload() {
    this.load.spritesheet('brawler', 'https://raw.githubusercontent.com/photonstorm/phaser3-examples/master/public/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
  }
  create() {

    this.anims.create({
      key: 'win',
      frames: this.anims.generateFrameNumbers('brawler', { frames: [ 30, 31 ] }),
      frameRate: 8,
      repeat: 0,
    });
    const cody = this.add.sprite(200, 70);
    cody.setScale(8);

    let btn = this.add.rectangle(500, 70, 200, 150, '#000')
    this.add.text(500, 70, 'click')

    btn.setInteractive();
    
    cody.on('animationcomplete', (e) => {
        console.log(e.key);
    });
      
    btn.on('pointerdown', () => {
      console.log('pointerdown');
      cody.play('win');

    });
  }
}

var config = {
  width: 800,
  height: 500,
  backgroundColor: '#555',
  scene: [BootScene],
  banner:false
}

var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1