fix: visibleBoundingBox optimizations

This commit is contained in:
cha0s 2019-04-16 13:30:15 -05:00
parent 1b35fc4215
commit 570054c610
4 changed files with 56 additions and 41 deletions

View File

@ -31,8 +31,7 @@ export class Listed extends Trait {
if (!list) {
return;
}
const quadTree = list.quadTree;
if (!('visibleBoundingBox' in this.entity)) {
if (!this.entity.is('visible')) {
return;
}
const aabb = this.entity.visibleBoundingBox;
@ -45,6 +44,7 @@ export class Listed extends Trait {
const points = Rectangle.toPoints(expandedAabb);
this.quadTreeNodes = points.map((point) => [...point, this.entity]);
// Add points to quad tree.
const quadTree = list.quadTree;
for (const node of this.quadTreeNodes) {
quadTree.add(node);
}
@ -84,11 +84,7 @@ export class Listed extends Trait {
listeners() {
return {
visibleBoundingBoxesUpdated: () => {
this.resetQuadTreeNodes();
},
positionChanged: () => {
visibleBoundingBoxChanged: () => {
this.resetQuadTreeNodes();
},

View File

@ -11,7 +11,7 @@ const decorate = compose(
}),
);
class PicturedBase extends Trait {
export class Pictured extends decorate(Trait) {
static defaultParams() {
return {
@ -28,8 +28,6 @@ class PicturedBase extends Trait {
initialize() {
this._images = this.params.get('images').toJS();
this.sprites = undefined;
// Bounding box update.
this.entity.emit('visibleBoundingBoxesUpdated');
}
destroy() {
@ -61,10 +59,11 @@ class PicturedBase extends Trait {
return;
}
// Load all images.
const imagePromises = [];
this.sprites = {};
for (const key in this._images) {
const {uri} = this._images[key];
Image.load(uri).then((image) => {
const imagePromise = Image.load(uri).then((image) => {
const sprite = this.sprites[key] = new Sprite(image);
// Calculate any offset.
sprite.position = this.viewPositionFor(key);
@ -74,7 +73,12 @@ class PicturedBase extends Trait {
this.showImage(key);
}
});
imagePromises.push(imagePromise);
}
Promise.all(imagePromises).then((images) => {
// Bounding box update.
this.entity.updateVisibleBoundingBox();
});
}
offsetFor(key) {
@ -133,7 +137,7 @@ class PicturedBase extends Trait {
return {
currentImageChanged: (oldKey) => {
// Bounding box update.
this.entity.emit('visibleBoundingBoxesUpdated');
this.entity.updateVisibleBoundingBox();
// Only client/graphics.
if (!this.sprites) {
return;
@ -155,5 +159,3 @@ class PicturedBase extends Trait {
}
}
export class Pictured extends decorate(PicturedBase) {}

View File

@ -1,6 +1,7 @@
import {compose} from '@avocado/core';
import {StateProperty, Trait} from '@avocado/entity';
import {Rectangle, Vector} from '@avocado/math';
import {Property} from '@avocado/mixins';
import {Container} from '../container';
import {hasGraphics} from '../has-graphics';
@ -9,6 +10,13 @@ const decorate = compose(
StateProperty('isVisible', {
track: true,
}),
Property('visibleBoundingBox', {
default: [0, 0, 0, 0],
emit: function (...args) {
this.entity.emit(...args);
},
track: true,
})
);
export class Visible extends decorate(Trait) {
@ -30,8 +38,8 @@ export class Visible extends decorate(Trait) {
this._container = new Container();
this._container.isVisible = this.entity.isVisible;
}
this.scheduledBoundingBoxUpdate = true;
this.trackPosition = this.params.get('trackPosition');
this._visibleBoundingBox = [0, 0, 0, 0];
}
destroy() {
@ -44,27 +52,6 @@ export class Visible extends decorate(Trait) {
return this._container;
}
get visibleBoundingBox() {
if (Rectangle.isNull(this._visibleBoundingBox)) {
// Collect all bounding boxes.
const visibleBoundingBoxes = this.entity.invokeHookFlat(
'visibleBoundingBoxes'
);
if (0 === visibleBoundingBoxes.length) {
return [0, 0, 0, 0];
}
let unifiedBoundingBox = [0, 0, 0, 0];
for (const visibleBoundingBox of visibleBoundingBoxes) {
unifiedBoundingBox = Rectangle.united(
unifiedBoundingBox,
visibleBoundingBox,
);
}
this._visibleBoundingBox = unifiedBoundingBox;
}
return this._visibleBoundingBox;
}
shouldSynchronizePosition() {
return this._container && this.trackPosition;
}
@ -84,9 +71,9 @@ export class Visible extends decorate(Trait) {
this.entity.container.visible = this.entity.isVisible;
},
visibleBoundingBoxesUpdated: () => {
this._visibleBoundingBox = [0, 0, 0, 0];
}
positionChanged: () => {
this.scheduledBoundingBoxUpdate = true;
},
};
if (this.shouldSynchronizePosition()) {
@ -103,10 +90,40 @@ export class Visible extends decorate(Trait) {
return listeners;
}
methods() {
return {
updateVisibleBoundingBox: () => {
this.scheduledBoundingBoxUpdate = true;
},
}
}
tick(elapsed) {
if (this.shouldSynchronizePosition()) {
this.synchronizePosition();
}
if (this.scheduledBoundingBoxUpdate) {
// Collect all bounding boxes.
const visibleBoundingBoxes = this.entity.invokeHookFlat(
'visibleBoundingBoxes'
);
if (0 === visibleBoundingBoxes.length) {
this.visibleBoundingBox = [0, 0, 0, 0];
}
else {
let unifiedBoundingBox = [0, 0, 0, 0];
for (const visibleBoundingBox of visibleBoundingBoxes) {
unifiedBoundingBox = Rectangle.united(
unifiedBoundingBox,
visibleBoundingBox,
);
}
this.visibleBoundingBox = unifiedBoundingBox;
this.scheduledBoundingBoxUpdate = false;
}
}
}
}

View File

@ -81,7 +81,7 @@ class AnimatedBase extends Trait {
animation.direction = this.entity.direction;
});
// Bounding box update.
this.entity.emit('visibleBoundingBoxesUpdated');
this.entity.updateVisibleBoundingBox();
});
}
@ -167,7 +167,7 @@ class AnimatedBase extends Trait {
oldAnimation.reset();
}
// Bounding box update.
this.entity.emit('visibleBoundingBoxesUpdated');
this.entity.updateVisibleBoundingBox();
// Only client/graphics.
if (!this.animationViews) {
return;