Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Containers' children not added to updateList #5817

Closed
prakol16 opened this issue Aug 26, 2021 · 1 comment
Closed

Containers' children not added to updateList #5817

prakol16 opened this issue Aug 26, 2021 · 1 comment

Comments

@prakol16
Copy link

prakol16 commented Aug 26, 2021

Version

  • Phaser Version: 3.55.2
  • Operating system: Ubuntu
  • Browser: any

Description

When an object is added to a container, ADDED_TO_SCENE is never called. This is an issue because many objects use these events to manage whether they are in the updateList as well.

For example,

  • Sprite animations use the update list
  • DOM elements that need to know when to hide themselves use the update list

Both of these break when used in a container, except if the object is first added to the scene and then added to the container in the same frame.

Example Test Code


class MainScene extends Phaser.Scene {
  preload() {
    this.load.spritesheet("mummy", mummyURL, {
      frameWidth: 37,
      frameHeight: 45
    });
  }

  create() {
    const mummyAnimation = this.anims.create({
      key: "walk",
      frames: this.anims.generateFrameNumbers("mummy"),
      frameRate: 16
    });

    // V1 (doesn't work)
    this.makeSpriteV1();
    // V2 (doesn't work)
    // this.makeSpriteV2();
    // V3 (does work)
    // this.makeSpriteV3();
  }

  makeSpriteV1() {
    const sprite = this.add.sprite(50, 50, "mummy");
    this.sprite = sprite;
    // Wait until sprite gets properly added to updateList
    // so that it isn't in _pending anymore
    this.time.delayedCall(1, () => this.addSpriteToContainer());
  }

  makeSpriteV2() {
    // The sprite is never added to the display list at all
    const sprite = new Phaser.GameObjects.Sprite(this, 50, 50, "mummy");
    this.sprite = sprite;
    this.addSpriteToContainer();
  }

  makeSpriteV3() {
    // Sprite is added to `updateList._pending`
    const sprite = this.add.sprite(50, 50, "mummy");
    this.sprite = sprite;
    this.addSpriteToContainer();
    // Sprite was added to container, hence removed from displayList
    // so it is in `updateList._destroyed` as well
    // but it is also in pending
    // so a little bit accidentally it does end up in the updateList after all
  }
  
  addSpriteToContainer() {
    const container = this.add.container(100, 100, [this.sprite]);
    this.sprite.play({ key: "walk", repeat: 7 });
  }
}

In the example above (see https://codepen.io/prakol16/pen/YzQXxpg for the codepen), the mummy's animation doesn't run, except in V3. The reason it works in V3 seems to be something of an accident; when the sprite is first added to the scene, it is added to the update list, and hence added to updateList._pending. Then, when it is added to the container, it is added to updateList._destroy. (This is also kind of a bug, because I think a more expected behavior is that updateList.remove first checks if the item is in _pending, and removes it from _pending if so; otherwise it queues it to be destroyed). Luckily, when these queued events are resolved, it seems _destroy is executed first, and so it is "removed," (when it wasn't in _active to begin with) and then added back from _pending.

If we add a 1 ms delay, so that the sprite properly moves to _active, before adding it to the container, or if we simply never added it to _pending at all by not using the factory constructor, the bug shows up.

photonstorm added a commit that referenced this issue Jun 7, 2022
… in the same frame were not correctly removed from the UpdateList. Fix #5803 #5817 #5818 #6052

* `ProcessQueue.isActive` is a new method that tests if the given object is in the active list, or not.
* `ProcessQueue.isPending` is a new method that tests if the given object is in the pending insertion list, or not.
* `ProcessQueue.isDestroying` is a new method that tests if the given object is pending destruction, or not.
* `ProcessQueue.add` will no longer place the item into the pending list if it's already active or pending.
* `ProcessQueue.remove` will check if the item is in the pending list, and simply remove it, rather than destroying it.
@photonstorm
Copy link
Collaborator

Thank you for submitting this issue. We have fixed this and the fix has been pushed to the master branch. It will be part of the next release. If you get time to build and test it for yourself we would appreciate that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants