99 lines
2.1 KiB
JavaScript
99 lines
2.1 KiB
JavaScript
import {RESOLUTION} from '@/constants.js'
|
|
import {System} from '@/ecs/index.js';
|
|
|
|
class SpatialHash {
|
|
|
|
constructor(area) {
|
|
this.area = area;
|
|
this.chunkSize = [RESOLUTION[0] / 2, RESOLUTION[1] / 2];
|
|
this.chunks = [];
|
|
const chunkCount = [
|
|
Math.ceil(this.area[0] / this.chunkSize[0]),
|
|
Math.ceil(this.area[1] / this.chunkSize[1]),
|
|
];
|
|
this.chunks = Array(chunkCount[0])
|
|
.fill(0)
|
|
.map(() => (
|
|
Array(chunkCount[1])
|
|
.fill(0)
|
|
.map(() => [])
|
|
));
|
|
this.data = {};
|
|
}
|
|
|
|
clamp(x, y) {
|
|
return [
|
|
Math.max(0, Math.min(x, this.area[0] - 1)),
|
|
Math.max(0, Math.min(y, this.area[1] - 1))
|
|
];
|
|
}
|
|
|
|
chunkIndex(x, y) {
|
|
const [cx, cy] = this.clamp(x, y);
|
|
return [
|
|
Math.floor(cx / this.chunkSize[0]),
|
|
Math.floor(cy / this.chunkSize[1]),
|
|
];
|
|
}
|
|
|
|
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 {
|
|
|
|
constructor(ecs) {
|
|
super(ecs);
|
|
const master = ecs.get(1);
|
|
this.hash = new SpatialHash([master.AreaSize.x, master.AreaSize.y]);
|
|
}
|
|
|
|
deindex(entities) {
|
|
super.deindex(entities);
|
|
for (const id of entities) {
|
|
this.hash.remove(id);
|
|
}
|
|
}
|
|
|
|
reindex(entities) {
|
|
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() {
|
|
const {diff} = this.ecs;
|
|
for (const id in diff) {
|
|
if (diff[id].VisibleAabb) {
|
|
this.updateHash(this.ecs.get(parseInt(id)));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|