Destroyed Entity Still Receiving Events

Hey All,

Curious if anyone has any input on an issue I’m having. I am spawning entities (a ball) via code but then based on an event I am proceeding to delete them one at a time during the game. At some point later (when the game is reset) I need to be able to delete all remaining entities.

Here is what the code looks like within the entity that is being spawned and then destroyed:

this.app.on("destroySpecificBall", function(ballEntity){
        if(self.entity === ballEntity){
            console.log("ball being destroyed");
            self.entity.destroy();
        }
    },this);
    
    this.app.on("deleteActiveBalls", function(){
        console.log("remaining balls destroyed");
        self.entity.destroy();
    },this);

Despite knowing that some of the entities have been successfully destroyed, I still get the console log “remaining balls destroyed” off of every entity, even the ones that have already been destroyed. So for example if I spawn 5 balls and then destroy 2 with the “destroySpecificBall” event, when I call “deleteActiveBalls” I should only get 3 console logs. Instead I get 5 so the entities are continuing to listen to events after being destroyed.

Anyone have any idea what is going on? Thanks in advance.

Since app is an object whose lifetime is not connected with the entity or script that it is called in, you need to remove the event listeners when the script is destroyed otherwise the callbacks are still subscribed to the app object events.

You can see an example here with the mouse object: https://playcanvas.com/editor/code/438459?tabs=5683278&line=36

    this.on('destroy', function() {
        if (this.app.mouse) {
            this.app.mouse.off(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
            this.app.mouse.off(pc.EVENT_MOUSEUP, this.onMouseUp, this);
        }

        if (this.app.touch) {
            this.app.touch.off(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
            this.app.touch.off(pc.EVENT_TOUCHEND, this.onTouchEndCancel, this);
            this.app.touch.off(pc.EVENT_TOUCHCANCEL, this.onTouchEndCancel, this);
        }
    }, this);

So your code will need to be:

var onDestroySpecificBall = function(ballEntity) {
    if(self.entity === ballEntity){
        console.log("ball being destroyed");
        self.entity.destroy();
    }
};

var onDeleteActiveBalls = function(){
    console.log("remaining balls destroyed");
    self.entity.destroy();
};

this.app.on("destroySpecificBall", onDestroySpecificBall, this);
this.app.on("deleteActiveBalls", onDeleteActiveBalls, this);

this.on('destroy', function() {
    this.app.off("destroySpecificBall", onDestroySpecificBall, this);
    this.app.off("deleteActiveBalls", onDeleteActiveBalls, this);
}, this);
1 Like

@yaustar
Thank you so much for this. Extremely helpful.

Is there any other data that sticks around like this after you destroy an entity? What happens when other scripts are referencing the entity that has been destroyed? Are there any other things I would feasibly need to include in my on destroy function?