Here’s an example of where event listeners are not being cleaned up after the script is destroyed:
// initialize code called once per entity
HotSpots.prototype.initialize = function() {
this.spots = [];
var nodes = this.hotspots.children;
for(var i=0; i<nodes.length; i++){
var front = nodes[i].findByPath('Front');
var back = nodes[i].findByPath('Back');
//设置每个热点的颜色
front.model.material.diffuse = this.color;
front.model.material.update();
back.model.material.diffuse = this.color;
back.model.material.update();
this.spots.push(back);
}
this.ray = new pc.Ray();
this.defaultForwardDirectionList = [];
this.directionToCamera = new pc.Vec3();
// Register the mouse down and touch start event so we know when the user has clicked
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
if (this.app.touch) {
this.app.touch.on(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
}
this.hitPosition = new pc.Vec3();
this.shapes = [];
for(var i=0; i<this.spots.length; i++){
//碰撞检测球
this.shapes.push(new pc.BoundingSphere(this.spots[i].getPosition(), this.rayRadius));
//记录初始化时热点的朝向
this.defaultForwardDirectionList.push(this.spots[i].up.clone());
}
//热点动画
this.opacity = {alpha:1};
this.scale = new pc.Vec3(this.scaleBegin, this.scaleBegin, this.scaleBegin);
this.tween1 = this.app.tween(this.opacity).to({alpha:0}, this.duration, pc.Linear).loop(true).yoyo(false).on('update', this.onFadeout, this).start();
this.tween2 = this.app.tween(this.scale).to(new pc.Vec3(this.scaleEnd, this.scaleEnd, this.scaleEnd), this.duration, pc.Linear).loop(true).yoyo(false).on('update', this.onScaleout, this).start();
this.on("destroy", function () {
this.tween1.stop();
this.tween2.stop();
});
};
We have added a couple of event listeners that add subscribers to the app
object:
// Register the mouse down and touch start event so we know when the user has clicked
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
if (this.app.touch) {
this.app.touch.on(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
}
When the script is destroyed, the subscriber is still on the app
object so when it gets called, it is now referencing a non existent script object.
What should be do is to remove the listener when the script is destroyed:
this.on("destroy", function () {
this.tween1.stop();
this.tween2.stop();
this.app.mouse.off(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
if (this.app.touch) {
this.app.touch.off(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
}
});