2024-07-02 16:16:39 -05:00
|
|
|
import Component from '@/ecs/component.js';
|
|
|
|
import {intersects} from '@/util/math.js';
|
|
|
|
|
|
|
|
import vector2d from './helpers/vector-2d';
|
|
|
|
|
|
|
|
export default class Collider extends Component {
|
|
|
|
instanceFromSchema() {
|
|
|
|
const {ecs} = this;
|
|
|
|
return class ColliderInstance extends super.instanceFromSchema() {
|
2024-07-02 22:42:56 -05:00
|
|
|
collidingWith = {};
|
2024-07-02 16:16:39 -05:00
|
|
|
isCollidingWith(other) {
|
|
|
|
const {aabb, aabbs} = this;
|
|
|
|
const {aabb: otherAabb, aabbs: otherAabbs} = other;
|
2024-07-03 16:13:14 -05:00
|
|
|
const intersections = [];
|
2024-07-02 16:16:39 -05:00
|
|
|
if (!intersects(aabb, otherAabb)) {
|
2024-07-03 16:13:14 -05:00
|
|
|
return intersections;
|
2024-07-02 16:16:39 -05:00
|
|
|
}
|
2024-07-03 16:13:14 -05:00
|
|
|
for (const i in aabbs) {
|
|
|
|
const aabb = aabbs[i];
|
|
|
|
for (const j in otherAabbs) {
|
|
|
|
const otherAabb = otherAabbs[j];
|
2024-07-02 16:16:39 -05:00
|
|
|
if (intersects(aabb, otherAabb)) {
|
2024-07-03 16:13:14 -05:00
|
|
|
intersections.push([this.bodies[i], other.bodies[j]]);
|
2024-07-02 16:16:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-03 16:13:14 -05:00
|
|
|
return intersections;
|
2024-07-02 16:16:39 -05:00
|
|
|
}
|
|
|
|
isWithin(query) {
|
|
|
|
const {aabb, aabbs} = this;
|
|
|
|
if (!intersects(aabb, query)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (const aabb of aabbs) {
|
|
|
|
if (intersects(aabb, query)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
recalculateAabbs() {
|
|
|
|
const {Position: {x: px, y: py}} = ecs.get(this.entity);
|
|
|
|
this.aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity};
|
|
|
|
this.aabbs = [];
|
|
|
|
const {bodies} = this;
|
2024-07-03 16:13:14 -05:00
|
|
|
for (const body of bodies) {
|
2024-07-02 16:16:39 -05:00
|
|
|
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
|
2024-07-03 16:13:14 -05:00
|
|
|
for (const point of body.points) {
|
2024-07-02 16:16:39 -05:00
|
|
|
const x = point.x + px;
|
|
|
|
const y = point.y + py;
|
|
|
|
if (x < x0) x0 = x;
|
|
|
|
if (x < this.aabb.x0) this.aabb.x0 = x;
|
|
|
|
if (x > x1) x1 = x;
|
|
|
|
if (x > this.aabb.x1) this.aabb.x1 = x;
|
|
|
|
if (y < y0) y0 = y;
|
|
|
|
if (y < this.aabb.y0) this.aabb.y0 = y;
|
|
|
|
if (y > y1) y1 = y;
|
|
|
|
if (y > this.aabb.y1) this.aabb.y1 = y;
|
|
|
|
}
|
|
|
|
this.aabbs.push({
|
|
|
|
x0: x0 > x1 ? x1 : x0,
|
|
|
|
x1: x0 > x1 ? x0 : x1,
|
|
|
|
y0: y0 > y1 ? y1 : y0,
|
|
|
|
y1: y0 > y1 ? y0 : y1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-02 22:42:56 -05:00
|
|
|
async load(instance) {
|
|
|
|
// heavy handed...
|
|
|
|
if ('undefined' !== typeof window) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
instance.collisionEndScriptInstance = await this.ecs.readScript(
|
|
|
|
instance.collisionEndScript,
|
|
|
|
{
|
|
|
|
ecs: this.ecs,
|
|
|
|
entity: this.ecs.get(instance.entity),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
instance.collisionStartScriptInstance = await this.ecs.readScript(
|
|
|
|
instance.collisionStartScript,
|
|
|
|
{
|
|
|
|
ecs: this.ecs,
|
|
|
|
entity: this.ecs.get(instance.entity),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2024-07-02 16:16:39 -05:00
|
|
|
static properties = {
|
|
|
|
bodies: {
|
|
|
|
type: 'array',
|
|
|
|
subtype: {
|
2024-07-03 16:13:14 -05:00
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
impassable: {type: 'uint8'},
|
|
|
|
points: {
|
|
|
|
type: 'array',
|
|
|
|
subtype: vector2d('int16'),
|
|
|
|
},
|
|
|
|
tags: {
|
|
|
|
type: 'array',
|
|
|
|
subtype: {type: 'string'},
|
|
|
|
},
|
|
|
|
},
|
2024-07-02 16:16:39 -05:00
|
|
|
},
|
|
|
|
},
|
2024-07-02 22:42:56 -05:00
|
|
|
collisionEndScript: {type: 'string'},
|
|
|
|
collisionStartScript: {type: 'string'},
|
2024-07-02 16:16:39 -05:00
|
|
|
};
|
|
|
|
}
|