Scene shutdown: collider error thrown with TileMapLayer

I’m restarting a scene to test some randomisation elements, but getting this error from (I think) a collider instance that’s still trying to process collision between a GameObject and TileMapTileLayer instance. It looks like the world tries to update the collider, even after the Tilelayer has shutdown / been destroyed?

Uncaught TypeError: Cannot read property 'tileWidth' of undefined
    at World.collideSpriteVsTilemapLayer (phaser.js?d4ef:126135)
    at World.collideHandler (phaser.js?d4ef:125817)
    at World.collideObjects (phaser.js?d4ef:125719)
    at Collider.update (phaser.js?d4ef:129054)
    at World.update (phaser.js?d4ef:124921)

So to restart the scene, I’m invoking the below onPress of a debug key from another Scene. Scrub the old instance of the scene and launch a new one. I even added a custom event to emit just before Scene shutdown - causing me even more confusion!

      const worldScene = this.scene.get(WorldScene.KEY);
      worldScene.events.emit(WORLD_ACTIONS.PRE_SHUTDOWN);
      // ^^ I added this, in case it was a race condition before the WorldScene was shutdown

      this.scene.stop(WorldScene.KEY);
      this.scene.launch(WorldScene.KEY);

Meanwhile, elsewhere in the code

    const collider = scene.physics.add.collider(player, this.groundLayer, (a, b) => {
      // Here's the "on collide" code
    });

    // Even destroying the collider doesn't work? 
    scene.events.on(WORLD_ACTIONS.PRE_SHUTDOWN, () => {
      scene.physics.world.removeCollider(collider);
      collider.destroy();
    });

Is this an issue with the colliders & scene stop / starting, garbage collecting any colliders? Or am I fundamentally misunderstanding how to start and stop scenes or colliders?

So I created a TestCollider extends Phaser.Physics.Arcade.Collider to extend update() soI could try and understand the workflow where; and so that super.update() only gets invoked if object2 (ie, the TileMapLayer) is still present in scene. Sure, the first error stops happening. Yay.

However, after a second scene relaunch, I get a different error now when removing / destroying the collider. :man_shrugging: :confused:

phaser.js?d4ef:129072 Uncaught TypeError: Cannot read property 'removeCollider' of null
    at TestCollider.destroy (phaser.js?d4ef:129072)
    at EventEmitter.eval (world-map-manager.js?9c15:139)

Damn. I see what the problem is. Oof. Important lesson for anyone reading: always remember to unbind your event listeners when they’re not longer needed.

So the method where const collider = is assigned, is the result of an event listener callback; that listener is created in the constructor of a GameObject class - so while the class is destroyed when the Scene stops - the listener isn’t unbound using off(). Therefore, when the new Scene instance starts up, the old listener still exists, and triggers its callback against objects that no longer exist in the previous Scene now garbage-collected.

:man_facepalming:

2 Likes