91 lines
2.0 KiB
JavaScript
91 lines
2.0 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;
|
|
}
|
|
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;
|
|
}
|
|
if (entity.Collider.isCollidingWith(other.Collider)) {
|
|
console.log('collide', entity, other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
within(query) {
|
|
const {x0, x1, y0, y1} = query;
|
|
const [cx0, cy0] = this.hash.chunkIndex(x0, y0);
|
|
const [cx1, cy1] = this.hash.chunkIndex(x1, y1);
|
|
const seen = {};
|
|
const within = new Set();
|
|
for (let cy = cy0; cy <= cy1; ++cy) {
|
|
for (let cx = cx0; cx <= cx1; ++cx) {
|
|
for (const id of this.hash.chunks[cx][cy]) {
|
|
if (seen[id]) {
|
|
continue;
|
|
}
|
|
seen[id] = true;
|
|
const entity = this.ecs.get(id);
|
|
if (entity.Collider.isWithin(query)) {
|
|
within.add(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return within;
|
|
}
|
|
|
|
}
|