117 lines
3.6 KiB
JavaScript
117 lines
3.6 KiB
JavaScript
import {System} from '@/ecs/index.js';
|
|
import SpatialHash from '@/util/spatial-hash.js';
|
|
|
|
export default class Colliders extends System {
|
|
|
|
hash;
|
|
|
|
deindex(entities) {
|
|
super.deindex(entities);
|
|
for (const id of entities) {
|
|
this.hash.remove(id);
|
|
}
|
|
}
|
|
|
|
static get priority() {
|
|
return {
|
|
after: 'IntegratePhysics',
|
|
};
|
|
}
|
|
|
|
reindex(entities) {
|
|
for (const id of entities) {
|
|
if (1 === id) {
|
|
this.hash = new SpatialHash(this.ecs.get(1).AreaSize);
|
|
}
|
|
}
|
|
super.reindex(entities);
|
|
for (const id of entities) {
|
|
this.updateHash(this.ecs.get(id));
|
|
}
|
|
}
|
|
|
|
updateHash(entity) {
|
|
if (!entity.Collider) {
|
|
return;
|
|
}
|
|
entity.Collider.recalculateAabbs();
|
|
this.hash.update(entity.Collider.aabb, entity.id);
|
|
}
|
|
|
|
tick() {
|
|
const seen = {};
|
|
for (const entity of this.ecs.changed(['Position'])) {
|
|
if (seen[entity.id]) {
|
|
continue;
|
|
}
|
|
seen[entity.id] = true;
|
|
if (!entity.Collider) {
|
|
continue;
|
|
}
|
|
const {collidingWith: wasCollidingWith} = entity.Collider;
|
|
entity.Collider.collidingWith = {};
|
|
this.updateHash(entity);
|
|
for (const other of this.within(entity.Collider.aabb)) {
|
|
if (seen[other.id]) {
|
|
continue;
|
|
}
|
|
seen[other.id] = true;
|
|
if (!other.Collider) {
|
|
continue;
|
|
}
|
|
delete other.Collider.collidingWith[entity.id];
|
|
const intersections = entity.Collider.isCollidingWith(other.Collider);
|
|
if (intersections.length > 0) {
|
|
entity.Collider.collidingWith[other.id] = true;
|
|
other.Collider.collidingWith[entity.id] = true;
|
|
if (!wasCollidingWith[other.id]) {
|
|
if (entity.Collider.collisionStartScriptInstance) {
|
|
entity.Collider.collisionStartScriptInstance.context.intersections = intersections;
|
|
entity.Collider.collisionStartScriptInstance.context.other = other;
|
|
entity.Ticking.addTickingPromise(entity.Collider.collisionStartScriptInstance.tickingPromise());
|
|
}
|
|
if (other.Collider.collisionStartScriptInstance) {
|
|
other.Collider.collisionStartScriptInstance.context.intersections = intersections
|
|
.map(([l, r]) => [r, l]);
|
|
other.Collider.collisionStartScriptInstance.context.other = entity;
|
|
other.Ticking.addTickingPromise(other.Collider.collisionStartScriptInstance.tickingPromise());
|
|
}
|
|
}
|
|
for (const [, {impassable}] of intersections) {
|
|
if (impassable) {
|
|
entity.Position.x = entity.Position.lastX
|
|
entity.Position.y = entity.Position.lastY
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (const otherId in wasCollidingWith) {
|
|
if (!entity.Collider.collidingWith[otherId]) {
|
|
const other = this.ecs.get(otherId);
|
|
if (!other || !other.Collider) {
|
|
continue;
|
|
}
|
|
if (entity.Collider.collisionEndScriptInstance) {
|
|
entity.Collider.collisionEndScriptInstance.context.other = other;
|
|
entity.Ticking.addTickingPromise(entity.Collider.collisionEndScriptInstance.tickingPromise());
|
|
}
|
|
if (other.Collider.collisionEndScriptInstance) {
|
|
other.Collider.collisionEndScriptInstance.context.other = entity;
|
|
other.Ticking.addTickingPromise(other.Collider.collisionEndScriptInstance.tickingPromise());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
within(query) {
|
|
const within = new Set();
|
|
for (const id of this.hash.within(query)) {
|
|
within.add(this.ecs.get(id));
|
|
}
|
|
return within;
|
|
}
|
|
|
|
}
|