avocado-old/packages/physics/list.js

136 lines
3.3 KiB
JavaScript

import {Vector} from '@avocado/math';
import {Shape} from './shape';
import {shapeFromJSON} from './index';
export class ShapeList extends Shape {
constructor() {
super();
this._shapes = [];
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]() {
for (const shape of this._shapes) {
yield shape;
}
}
get aabb() {
if (0 === this._shapes.length) {
return [0, 0, 0, 0];
}
const min = [Infinity, Infinity];
const max = [-Infinity, -Infinity];
for (const shape of this._shapes) {
const aabb = shape.aabb;
min[0] = aabb[0] < min[0] ? aabb[0] : min[0];
min[1] = aabb[1] < min[1] ? aabb[1] : min[1];
max[0] = aabb[0] > max[0] ? aabb[0] : max[0];
max[1] = aabb[1] > max[1] ? aabb[1] : max[1];
}
return Rectangle.translated(
[min[0], min[1], max[0] - min[0], max[1] - min[1]],
this.position
);
}
addShape(shape) {
const oldShapes = [...this._shapes];
this._shapes.push(shape);
this.emit('shapesChanged', oldShapes, this._shapes);
}
fromJSON(json) {
super.fromJSON(json);
if (json.shapes) {
const shapes = [];
json.shapes.forEach((shape) => {
shapes.push(shapeFromJSON(shape));
});
const oldShapes = [...this._shapes];
this._shapes = shapes;
this.emit('shapesChanged', oldShapes, this._shapes);
}
return this;
}
intersects(list) {
if (0 === this._shapes.length) {
return false;
}
if (!Rectangle.intersects(this.aabb, list.aabb)) {
return false;
}
// TODO: Quadtrees?
for (const shape of this._shapes) {
for (const otherShape of list._shapes) {
if (Rectangle.intersects(
Rectangle.translated(shape.aabb, this.position),
Rectangle.translated(otherShape.aabb, otherShape.position)
)) {
return true;
}
}
}
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(),
type: 'list',
shapes: this._shapes.map((shape) => {
return shape.toJSON();
}),
}
}
}