silphius/app/ecs-components/collider.js
2024-07-04 21:47:14 -05:00

132 lines
3.6 KiB
JavaScript

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() {
collidingWith = {};
get aabb() {
const {Position: {x: px, y: py}} = ecs.get(this.entity);
return {
x0: this.$$aabb.x0 + px,
x1: this.$$aabb.x1 + px,
y0: this.$$aabb.y0 + py,
y1: this.$$aabb.y1 + py,
};
}
get aabbs() {
const {Position: {x: px, y: py}} = ecs.get(this.entity);
const aabbs = [];
for (const aabb of this.$$aabbs) {
aabbs.push({
x0: aabb.x0 + px,
x1: aabb.x1 + px,
y0: aabb.y0 + py,
y1: aabb.y1 + py,
})
}
return aabbs;
}
isCollidingWith(other) {
const {aabb, aabbs} = this;
const {aabb: otherAabb, aabbs: otherAabbs} = other;
const intersections = [];
if (!intersects(aabb, otherAabb)) {
return intersections;
}
for (const i in aabbs) {
const aabb = aabbs[i];
for (const j in otherAabbs) {
const otherAabb = otherAabbs[j];
if (intersects(aabb, otherAabb)) {
intersections.push([this.bodies[i], other.bodies[j]]);
}
}
}
return intersections;
}
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;
}
}
}
async load(instance) {
instance.$$aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity};
instance.$$aabbs = [];
const {bodies} = instance;
for (const body of bodies) {
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
for (const point of body.points) {
const x = point.x;
const y = point.y;
if (x < x0) x0 = x;
if (x < instance.$$aabb.x0) instance.$$aabb.x0 = x;
if (x > x1) x1 = x;
if (x > instance.$$aabb.x1) instance.$$aabb.x1 = x;
if (y < y0) y0 = y;
if (y < instance.$$aabb.y0) instance.$$aabb.y0 = y;
if (y > y1) y1 = y;
if (y > instance.$$aabb.y1) instance.$$aabb.y1 = y;
}
instance.$$aabbs.push({
x0: x0 > x1 ? x1 : x0,
x1: x0 > x1 ? x0 : x1,
y0: y0 > y1 ? y1 : y0,
y1: y0 > y1 ? y0 : y1,
});
}
// 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),
},
);
}
static properties = {
bodies: {
type: 'array',
subtype: {
type: 'object',
properties: {
impassable: {type: 'uint8'},
points: {
type: 'array',
subtype: vector2d('int16'),
},
tags: {
type: 'array',
subtype: {type: 'string'},
},
},
},
},
collisionEndScript: {type: 'string'},
collisionStartScript: {type: 'string'},
};
}