import {System} from '@/ecs/index.js'; import SpatialHash from '@/util/spatial-hash.js'; export default class VisibleAabbs 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) { const {x, y} = this.ecs.get(1).AreaSize; if ( !this.hash || ( this.hash.area.x !== x || this.hash.area.y !== y ) ) { 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.VisibleAabb) { this.hash.remove(entity.id); return; } this.hash.update(entity.VisibleAabb, entity.id); } tick() { for (const entity of this.ecs.changed(['Position'])) { const {Position: {x, y}, Sprite, VisibleAabb} = entity; if (VisibleAabb) { let size = undefined; if (Sprite) { const frame = Sprite.animation ? Sprite.$$sourceJson.animations[Sprite.animation][Sprite.frame] : ''; size = Sprite.$$sourceJson.frames[frame].sourceSize; } /* v8 ignore next 3 */ if (!size) { throw new Error(`no size for aabb for entity ${entity.id}(${JSON.stringify(entity.toJSON(), null, 2)})`); } VisibleAabb.x0 = x - Sprite.anchor.x * size.w; VisibleAabb.x1 = x + (1 - Sprite.anchor.x) * size.w; VisibleAabb.y0 = y - Sprite.anchor.y * size.h; VisibleAabb.y1 = y + (1 - Sprite.anchor.y) * size.h; this.updateHash(entity); } } } within(query) { const within = new Set(); for (const id of this.hash.within(query)) { within.add(this.ecs.get(id)); } return within; } }