silphius/app/ecs-systems/update-spatial-hash.js

110 lines
2.5 KiB
JavaScript
Raw Normal View History

2024-06-10 22:42:30 -05:00
import {RESOLUTION} from '@/constants.js'
import {System} from '@/ecs/index.js';
class SpatialHash {
2024-06-11 02:24:45 -05:00
constructor({x, y}) {
this.area = {x, y};
this.chunkSize = {x: RESOLUTION.x / 2, y: RESOLUTION.y / 2};
this.chunks = Array(Math.ceil(this.area.x / this.chunkSize.x))
2024-06-10 22:42:30 -05:00
.fill(0)
.map(() => (
2024-06-11 02:24:45 -05:00
Array(Math.ceil(this.area.y / this.chunkSize.y))
2024-06-10 22:42:30 -05:00
.fill(0)
.map(() => [])
));
this.data = {};
}
clamp(x, y) {
return [
2024-06-11 02:24:45 -05:00
Math.max(0, Math.min(x, this.area.x - 1)),
Math.max(0, Math.min(y, this.area.y - 1))
2024-06-10 22:42:30 -05:00
];
}
chunkIndex(x, y) {
const [cx, cy] = this.clamp(x, y);
return [
2024-06-11 02:24:45 -05:00
Math.floor(cx / this.chunkSize.x),
Math.floor(cy / this.chunkSize.y),
2024-06-10 22:42:30 -05:00
];
}
remove(datum) {
if (datum in this.data) {
for (const [cx, cy] of this.data[datum]) {
const chunk = this.chunks[cx][cy];
chunk.splice(chunk.indexOf(datum), 1);
}
}
this.data[datum] = [];
}
update({x0, x1, y0, y1}, datum) {
this.remove(datum);
for (const [x, y] of [[x0, y0], [x0, y1], [x1, y0], [x1, y1]]) {
const [cx, cy] = this.chunkIndex(x, y);
this.data[datum].push([cx, cy]);
this.chunks[cx][cy].push(datum);
}
}
}
export default class UpdateSpatialHash extends System {
deindex(entities) {
super.deindex(entities);
for (const id of entities) {
this.hash.remove(id);
}
}
reindex(entities) {
2024-06-14 15:18:55 -05:00
for (const id of entities) {
if (1 === id) {
this.hash = new SpatialHash(this.ecs.get(1).AreaSize);
}
}
2024-06-10 22:42:30 -05:00
super.reindex(entities);
for (const id of entities) {
this.updateHash(this.ecs.get(id));
}
}
updateHash(entity) {
if (!entity.VisibleAabb) {
return;
}
this.hash.update(entity.VisibleAabb, entity.id);
}
tick() {
2024-06-22 12:30:25 -05:00
for (const entity of this.ecs.changed(['VisibleAabb'])) {
this.updateHash(entity);
2024-06-10 22:42:30 -05:00
}
}
2024-06-11 02:10:08 -05:00
nearby(entity) {
const [cx0, cy0] = this.hash.chunkIndex(
2024-06-11 02:24:45 -05:00
entity.Position.x - RESOLUTION.x * 0.75,
entity.Position.y - RESOLUTION.x * 0.75,
2024-06-11 02:10:08 -05:00
);
const [cx1, cy1] = this.hash.chunkIndex(
2024-06-11 02:24:45 -05:00
entity.Position.x + RESOLUTION.x * 0.75,
entity.Position.y + RESOLUTION.x * 0.75,
2024-06-11 02:10:08 -05:00
);
const nearby = new Set();
for (let cy = cy0; cy <= cy1; ++cy) {
for (let cx = cx0; cx <= cx1; ++cx) {
this.hash.chunks[cx][cy].forEach((id) => {
nearby.add(this.ecs.get(id));
});
}
}
return nearby;
}
2024-06-10 22:42:30 -05:00
}