From 3e2e85faf3bb9bdf601f413867275a223ed80731 Mon Sep 17 00:00:00 2001 From: cha0s Date: Fri, 3 May 2019 01:21:35 -0500 Subject: [PATCH] chore: remove event listeners on shape destroy --- packages/physics/circle.js | 13 +++- packages/physics/list.js | 84 ++++++++++++++++--------- packages/physics/polygon.js | 39 ++++++++---- packages/physics/rectangle.js | 31 +++++---- packages/physics/shape-view.js | 35 ++++++++--- packages/physics/shape.js | 16 ++++- packages/physics/traits/shaped.trait.js | 3 +- 7 files changed, 152 insertions(+), 69 deletions(-) diff --git a/packages/physics/circle.js b/packages/physics/circle.js index fed293e..82ac987 100644 --- a/packages/physics/circle.js +++ b/packages/physics/circle.js @@ -12,9 +12,7 @@ export class CircleShape extends decorate(Shape) { constructor() { super(); - this.on('radiusChanged', () => { - this.emit('aabbChanged'); - }); + this.on('radiusChanged', this.onAabbChanged, this); } get aabb() { @@ -28,6 +26,11 @@ export class CircleShape extends decorate(Shape) { ]; } + destroy() { + super.destroy(); + this.off('radiusChanged', this.onAabbChanged); + } + fromJSON(json) { super.fromJSON(json); if (json.radius) { @@ -36,6 +39,10 @@ export class CircleShape extends decorate(Shape) { return this; } + onAabbChanged() { + this.emit('aabbChanged'); + } + toJSON() { return { ...super.toJSON(), diff --git a/packages/physics/list.js b/packages/physics/list.js index 1938764..5755771 100644 --- a/packages/physics/list.js +++ b/packages/physics/list.js @@ -8,29 +8,22 @@ export class ShapeList extends Shape { constructor() { super(); this._shapes = []; - this.on('shapesChanged', () => { - this._shapes.forEach((shape) => { - shape.off('aabbChanged'); - shape.on('aabbChanged', () => { - this.emit('aabbChanged'); - }); - }); - }); - this.on('originChanged', (oldOrigin) => { - this._shapes.forEach((shape) => { - shape.emit('parentOriginChanged', oldOrigin, this.origin); - }); - }); - this.on('rotationChanged', (oldRotation) => { - this._shapes.forEach((shape) => { - shape.emit('parentRotationChanged', oldRotation, this.rotation); - }); - }); - this.on('scaleChanged', (oldScale) => { - this._shapes.forEach((shape) => { - shape.emit('parentScaleChanged', oldScale, this.scale); - }); - }); + this.on('shapesChanged', this.onShapesChanged, this); + this.on('originChanged', this.onOriginChanged, this); + this.on('rotationChanged', this.onRotationChanged, this); + this.on('scaleChanged', this.onScaleChanged, this); + } + + destroy() { + super.destroy(); + this.off('shapesChanged', this.onShapesChanged); + this.off('originChanged', this.onOriginChanged); + this.off('rotationChanged', this.onRotationChanged); + this.off('scaleChanged', this.onScaleChanged); + for (let i = 0; i < this._shapes.length; i++) { + const shape = this._shapes[i]; + shape.destroy(); + } } *[Symbol.iterator]() { @@ -58,6 +51,12 @@ export class ShapeList extends Shape { ); } + addShape(shape) { + const oldShapes = [...this._shapes]; + this._shapes.push(shape); + this.emit('shapesChanged', oldShapes, this._shapes); + } + fromJSON(json) { super.fromJSON(json); if (json.shapes) { @@ -65,17 +64,13 @@ export class ShapeList extends Shape { json.shapes.forEach((shape) => { shapes.push(shapeFromJSON(shape)); }); + const oldShapes = [...this._shapes]; this._shapes = shapes; - this.emit('shapesChanged'); + this.emit('shapesChanged', oldShapes, this._shapes); } return this; } - addShape(shape) { - this._shapes.push(shape); - this.emit('shapesChanged'); - } - intersects(list) { if (0 === this._shapes.length) { return false; @@ -97,6 +92,37 @@ export class ShapeList extends Shape { return false; } + onChildAabbChanged() { + this.emit('aabbChanged'); + } + + onOriginChanged(oldOrigin) { + this._shapes.forEach((shape) => { + shape.emit('parentOriginChanged', oldOrigin, this.origin); + }); + } + + onRotationChanged(oldRotation) { + this._shapes.forEach((shape) => { + shape.emit('parentRotationChanged', oldRotation, this.rotation); + }); + } + + onScaleChanged(oldScale) { + this._shapes.forEach((shape) => { + shape.emit('parentScaleChanged', oldScale, this.scale); + }); + } + + onShapesChanged(oldShapes) { + oldShapes.forEach((shape) => { + shape.off('aabbChanged'); + }); + this._shapes.forEach((shape) => { + shape.on('aabbChanged', this.onChildAabbChanged, this); + }); + } + toJSON() { return { ...super.toJSON(), diff --git a/packages/physics/polygon.js b/packages/physics/polygon.js index 72828f0..040fdd0 100644 --- a/packages/physics/polygon.js +++ b/packages/physics/polygon.js @@ -16,18 +16,20 @@ export class PolygonShape extends Shape { 'rotationChanged', 'scaleChanged', 'verticesChanged', - ], () => { - const parentOrigin = this.parent ? this.parent.origin : [0, 0]; - const origin = Vector.add(this.origin, parentOrigin); - const parentRotation = this.parent ? this.parent.rotation : 0; - const rotation = this.rotation + parentRotation; - const parentScale = this.parent ? this.parent.scale : 1; - const scale = this.scale * parentScale; - this._translatedVertices = this._vertices.map((vertice) => { - return Vertice.translate(vertice, origin, rotation, scale); - }); - this.emit('aabbChanged'); - }); + ], this.onRecalculateVertices, this); + } + + destroy() { + super.destroy(); + this.off([ + 'parentOriginChanged', + 'parentRotationChanged', + 'parentScaleChanged', + 'originChanged', + 'rotationChanged', + 'scaleChanged', + 'verticesChanged', + ], this.onRecalculateVertices); } *[Symbol.iterator]() { @@ -62,6 +64,19 @@ export class PolygonShape extends Shape { return this; } + onRecalculateVertices() { + const parentOrigin = this.parent ? this.parent.origin : [0, 0]; + const origin = Vector.add(this.origin, parentOrigin); + const parentRotation = this.parent ? this.parent.rotation : 0; + const rotation = this.rotation + parentRotation; + const parentScale = this.parent ? this.parent.scale : 1; + const scale = this.scale * parentScale; + this._translatedVertices = this._vertices.map((vertice) => { + return Vertice.translate(vertice, origin, rotation, scale); + }); + this.emit('aabbChanged'); + } + get vertices() { return this._vertices; } diff --git a/packages/physics/rectangle.js b/packages/physics/rectangle.js index 99d3686..05ad49e 100644 --- a/packages/physics/rectangle.js +++ b/packages/physics/rectangle.js @@ -14,18 +14,12 @@ export class RectangleShape extends decorate(PolygonShape) { constructor() { super(); - this.on(['positionChanged', 'sizeChanged'], () => { - const halfSize = Vector.scale(this.size, 0.5); - const width = this.width - 0.001; - const height = this.height - 0.001; - const position = Vector.add(this.position, Vector.scale(halfSize, -1)); - this.vertices = [ - position, - Vector.add(position, [width, 0]), - Vector.add(position, [width, height]), - Vector.add(position, [0, height]), - ]; - }); + this.on(['positionChanged', 'sizeChanged'], this.onVerticesChanged, this); + } + + destroy() { + super.destroy(); + this.off(['positionChanged', 'sizeChanged'], this.onVerticesChanged); } fromJSON(json) { @@ -41,6 +35,19 @@ export class RectangleShape extends decorate(PolygonShape) { return this; } + onVerticesChanged() { + const halfSize = Vector.scale(this.size, 0.5); + const width = this.width - 0.001; + const height = this.height - 0.001; + const position = Vector.add(this.position, Vector.scale(halfSize, -1)); + this.vertices = [ + position, + Vector.add(position, [width, 0]), + Vector.add(position, [width, height]), + Vector.add(position, [0, height]), + ]; + } + toJSON() { return { ...super.toJSON(), diff --git a/packages/physics/shape-view.js b/packages/physics/shape-view.js index 6a3f34c..574e1c7 100644 --- a/packages/physics/shape-view.js +++ b/packages/physics/shape-view.js @@ -12,15 +12,11 @@ export class ShapeView extends Renderable { this.shape = shape; if (shape instanceof PolygonShape) { this.redrawPolygonLines(); - shape.on('aabbChanged', () => { - this.redrawPolygonLines(); - }); + shape.on('aabbChanged', this.onPolygonShapeAabbChanged, this); } if (shape instanceof CircleShape) { this.redrawCircle(); - shape.on('aabbChanged', () => { - this.redrawCircle(); - }); + shape.on('aabbChanged', this.onCircleShapeAabbChanged, this); } if (shape instanceof ShapeList) { for (const child of shape) { @@ -29,15 +25,36 @@ export class ShapeView extends Renderable { } } this.container.position = shape.position; - shape.on('positionChanged', () => { - this.container.position = shape.position; - }) + shape.on('positionChanged', this.onShapePositionChanged, this); + } + + destroy() { + super.destroy(); + if (shape instanceof PolygonShape) { + this.shape.off('aabbChanged', this.onPolygonShapeAabbChanged); + } + if (shape instanceof CircleShape) { + this.shape.off('aabbChanged', this.onCircleShapeAabbChanged); + } + this.shape.off('aabbChanged', this.onShapePositionChanged); } get internal() { return this.container.internal; } + onPolygonShapeAabbChanged() { + this.redrawPolygonLines(); + } + + onCircleShapeAabbChanged() { + this.redrawCircle(); + } + + onShapePositionChanged() { + this.container.position = shape.position; + } + redrawCircle() { const primitives = new Primitives(); primitives.drawCircle( diff --git a/packages/physics/shape.js b/packages/physics/shape.js index 8867dc0..f858ec3 100644 --- a/packages/physics/shape.js +++ b/packages/physics/shape.js @@ -30,15 +30,21 @@ export class Shape extends decorate(class {}) { 'originChanged', 'rotationChanged', 'scaleChanged', - ], () => { - this.emit('aabbChanged'); - }); + ], this.onAabbChanged, this); } get aabb() { return [0, 0, 0, 0]; } + destroy() { + this.off([ + 'originChanged', + 'rotationChanged', + 'scaleChanged', + ], this.onAabbChanged); + } + fromJSON(json) { const keys = [ 'origin', @@ -54,6 +60,10 @@ export class Shape extends decorate(class {}) { return this; } + onAabbChanged() { + this.emit('aabbChanged'); + } + toJSON() { return { origin: this.origin, diff --git a/packages/physics/traits/shaped.trait.js b/packages/physics/traits/shaped.trait.js index cd65ff6..649f397 100644 --- a/packages/physics/traits/shaped.trait.js +++ b/packages/physics/traits/shaped.trait.js @@ -21,10 +21,11 @@ export class Shaped extends decorate(Trait) { } destroy() { + this._shape.destroy(); if (this.shapeView) { this.shapeView.destroy(); + this.shapeView = undefined; } - this.shapeView = undefined; } get shape() {