How to destroy a gameObject reference completely?

If I have a Player class that has been created in the main game scene that creates a new gameobject Inventory:

export class Player extends Phaser.GameObjects.Sprite {
  inventory: Inventory | null;

  constructor(params) {
     this.currentScene = params.scene;
     this.inventory = null;
  }

  update() : void {
    if (this.currentScene.keys.i.isDown && !this.inventory) {
        this.inventory = new Inventory(this.currentScene, 400, 300, this);
    }
  }
}

And I destroy the class like so:

export class Inventory extends Phaser.GameObjects.Container {

  constructor(params) {
    // ... some code ...

    this.currentScene = scene;
    this.inventoryBars = this.currentScene.add.group();
    this.currentScene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.J).once('down', () => {
      this.destroyInventory();
    });

   // ... more code ...
  }

  destroyInventory() {
    this.currentScene.player.inventory = null;
    this.inventoryBars.destroy(true);
    this.destroy(true);
  }
}

Why do I need to get a reference to the parent player.inventory and set it to null in order to completely remove it? Shouldn’t this.destroy(true) take care of it?

Hi @joshuar500, welcome to the Phaser group. :smile:

When you call this.destroy(true) what you are doing is telling that gameobject to remove itself from the displaylist, from the updatelist and from some Phaser’s internal systems like the input manager. It will also clear all its references to its parents (scene, container, etc).

BUT the property this.currentScene.player.inventory in your Player class still has a reference to that instance of Inventory so the Javascript garbage collector cannot remove it from memory. Your Inventory instance is effectively destroyed (Phaser cannot use it again) but it will remain in memory until you clear all references to it (setting them to null).

@jackfreak Thanks for the quick response! Just to be sure: this.currentScene.player.inventory inside of the Inventory class has a context reference to the Player class’s scene and this.currentScene inside of the Player class has a reference to the parent class of whatever instantiates that class (in this case the game scene). And because I instantiate new Inventory with the Player’s this.currentScene, I am actually keeping a reference to that instantiation, and destroy() won’t have any affect to that reference – it only “destroys” in the sense of cleaning up Phaser system stuff?

I’m wondering then, if there is a better way to do this so that the destroy() method (or maybe something else) also resets the variable in the Player class to clean up unused references. I can imagine holding references in a lot of variables without resetting them somehow can build up memory usage. I have tried just using the scene parameter for GameObject’s but have gotten errors in the past. Any ideas for GameObjects that are nested inside of classes like this?

To be honest you lost me there :sweat_smile:

All I can say is that destroy() only clears up Phaser system stuff like you said, you are still in charge to clear all the references to the instances of Inventory so the GC will pick them up.

Currently you are triggering the destruction of the Inventory instance from within the instance itself, so you -should- clear any references to it outside the instance (means doing this.currentScene.player.inventory = null). Doing that is not mandatory but is a good practice to make sure your destroyed instance will become free for garbage collection.

A cleaner way could be to call destroyInventory() from the Player instance, something like this:

export class Player extends Phaser.GameObjects.Sprite {
  inventory: Inventory | null;

  constructor(params) {
     this.currentScene = params.scene;
     this.inventory = null;
  }

  clearInventory() : void {
    if(this.inventory !== null) {
        this.inventory.destroyInventory();

        // And then mark the instance for GC
        this.inventory = null;
    }
  }
}

Now there’s no need of accessing this.currentScene.player.inventory from within the Inventory instance, if that’s whats bothering you :slight_smile: .

Hah, sorry for being so convoluted, but you definitely helped me answer my question. Thanks again @jackfreak, really appreciate all your help!

1 Like