refactor: optimize visibleBoundingBox
This commit is contained in:
parent
9ff9fca1e9
commit
c9260a2cca
|
@ -107,7 +107,13 @@ export class EntityList extends decorate(Synchronized) {
|
|||
|
||||
visibleEntities(query) {
|
||||
const quadTree = this._quadTree;
|
||||
const entities = quadTree.search(query).map((node) => {
|
||||
// Make sure they're actually in the query.
|
||||
const nodes = quadTree.search(query).filter((node) => {
|
||||
const [x, y, entity] = node.data;
|
||||
const aabb = entity.visibleBoundingBox;
|
||||
return Rectangle.intersects(query, aabb);
|
||||
});
|
||||
let entities = nodes.map((node) => {
|
||||
return node.data[2];
|
||||
});
|
||||
// Hitting multiple points for each entity can return duplicates.
|
||||
|
|
|
@ -6,6 +6,7 @@ export class Listed extends Trait {
|
|||
|
||||
initialize() {
|
||||
this._list = undefined;
|
||||
this.quadTreeAabb = undefined;
|
||||
this.quadTreeNodes = undefined;
|
||||
}
|
||||
|
||||
|
@ -35,7 +36,13 @@ export class Listed extends Trait {
|
|||
return;
|
||||
}
|
||||
const aabb = this.entity.visibleBoundingBox;
|
||||
const points = Rectangle.toPoints(aabb);
|
||||
if (Rectangle.isNull(aabb)) {
|
||||
return;
|
||||
}
|
||||
// Expand the AABB so we don't have to update it every single tick.
|
||||
const expandedAabb = Rectangle.expand(aabb, [32, 32]);
|
||||
this.quadTreeAabb = expandedAabb;
|
||||
const points = Rectangle.toPoints(expandedAabb);
|
||||
this.quadTreeNodes = points.map((point) => [...point, this.entity]);
|
||||
// Add points to quad tree.
|
||||
for (const node of this.quadTreeNodes) {
|
||||
|
@ -43,6 +50,14 @@ export class Listed extends Trait {
|
|||
}
|
||||
}
|
||||
|
||||
get doesNeedReset() {
|
||||
if (!this.quadTreeAabb) {
|
||||
return true;
|
||||
}
|
||||
const aabb = this.entity.visibleBoundingBox;
|
||||
return !Rectangle.isInside(this.quadTreeAabb, aabb);
|
||||
}
|
||||
|
||||
removeQuadTreeNodes() {
|
||||
const list = this._list;
|
||||
if (!list) {
|
||||
|
@ -53,11 +68,15 @@ export class Listed extends Trait {
|
|||
for (const node of this.quadTreeNodes) {
|
||||
quadTree.remove(node);
|
||||
}
|
||||
this.quadTreeAabb = undefined;
|
||||
this.quadTreeNodes = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
resetQuadTreeNodes() {
|
||||
if (!this.doesNeedReset) {
|
||||
return;
|
||||
}
|
||||
this.removeQuadTreeNodes();
|
||||
this.addQuadTreeNodes();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ export class Visible extends decorate(Trait) {
|
|||
this._container.isVisible = this.entity.isVisible;
|
||||
}
|
||||
this.trackPosition = this.params.get('trackPosition');
|
||||
this._visibleBoundingBox = [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -44,6 +45,7 @@ export class Visible extends decorate(Trait) {
|
|||
}
|
||||
|
||||
get visibleBoundingBox() {
|
||||
if (Rectangle.isNull(this._visibleBoundingBox)) {
|
||||
// Collect all bounding boxes.
|
||||
const visibleBoundingBoxes = this.entity.invokeHookFlat(
|
||||
'visibleBoundingBoxes'
|
||||
|
@ -58,7 +60,9 @@ export class Visible extends decorate(Trait) {
|
|||
visibleBoundingBox,
|
||||
);
|
||||
}
|
||||
return unifiedBoundingBox;
|
||||
this._visibleBoundingBox = unifiedBoundingBox;
|
||||
}
|
||||
return this._visibleBoundingBox;
|
||||
}
|
||||
|
||||
shouldSynchronizePosition() {
|
||||
|
@ -80,6 +84,10 @@ export class Visible extends decorate(Trait) {
|
|||
this.entity.container.visible = this.entity.isVisible;
|
||||
},
|
||||
|
||||
visibleBoundingBoxesUpdated: () => {
|
||||
this._visibleBoundingBox = [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
};
|
||||
if (this.shouldSynchronizePosition()) {
|
||||
listeners.traitAdded = (type) => {
|
||||
|
|
|
@ -6,6 +6,20 @@
|
|||
|
||||
import * as Vector from '../vector';
|
||||
|
||||
export function expand(rectangle, expandBy) {
|
||||
const halfExpand = Vector.scale(expandBy, 0.5);
|
||||
// return compose(
|
||||
// Vector.sub(position(rectangle), halfExpand),
|
||||
// Vector.add(size(rectangle), halfExpand),
|
||||
// );
|
||||
return [
|
||||
rectangle[0] - halfExpand[0],
|
||||
rectangle[1] - halfExpand[1],
|
||||
rectangle[2] + expandBy[0],
|
||||
rectangle[3] + expandBy[1],
|
||||
];
|
||||
}
|
||||
|
||||
// Check if a rectangle intersects with another rectangle.
|
||||
//
|
||||
// avocado> Rectangle.intersects [0, 0, 16, 16], [8, 8, 24, 24]
|
||||
|
@ -29,6 +43,22 @@ export function intersects (l, r) {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function isInside(outer, inner) {
|
||||
if (inner[0] < outer[0]) {
|
||||
return false;
|
||||
}
|
||||
if (inner[1] < outer[1]) {
|
||||
return false;
|
||||
}
|
||||
if (inner[0] + inner[2] > outer[0] + outer[2]) {
|
||||
return false;
|
||||
}
|
||||
if (inner[1] + inner[3] > outer[1] + outer[3]) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if a rectangle is touching a vector.
|
||||
//
|
||||
// avocado> Rectangle.isTouching [0, 0, 16, 16], [0, 0]
|
||||
|
|
Loading…
Reference in New Issue
Block a user