106 lines
2.6 KiB
TypeScript
106 lines
2.6 KiB
TypeScript
import { type World, type EntityId, type Actor, type Vec2 } from "../core/types";
|
|
import { idx } from "./world/world-logic";
|
|
|
|
export class EntityManager {
|
|
private grid: Map<number, EntityId[]> = new Map();
|
|
private actors: Map<EntityId, Actor>;
|
|
private world: World;
|
|
private lastId: number = 0;
|
|
|
|
constructor(world: World) {
|
|
this.world = world;
|
|
this.actors = world.actors;
|
|
this.lastId = Math.max(0, ...this.actors.keys());
|
|
this.rebuildGrid();
|
|
}
|
|
|
|
|
|
rebuildGrid() {
|
|
this.grid.clear();
|
|
for (const actor of this.actors.values()) {
|
|
this.addToGrid(actor);
|
|
}
|
|
}
|
|
|
|
private addToGrid(actor: Actor) {
|
|
const i = idx(this.world, actor.pos.x, actor.pos.y);
|
|
if (!this.grid.has(i)) {
|
|
this.grid.set(i, []);
|
|
}
|
|
this.grid.get(i)!.push(actor.id);
|
|
}
|
|
|
|
private removeFromGrid(actor: Actor) {
|
|
const i = idx(this.world, actor.pos.x, actor.pos.y);
|
|
const ids = this.grid.get(i);
|
|
if (ids) {
|
|
const index = ids.indexOf(actor.id);
|
|
if (index !== -1) {
|
|
ids.splice(index, 1);
|
|
}
|
|
if (ids.length === 0) {
|
|
this.grid.delete(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
moveActor(actorId: EntityId, from: Vec2, to: Vec2) {
|
|
const actor = this.actors.get(actorId);
|
|
if (!actor) return;
|
|
|
|
// Remove from old position
|
|
const oldIdx = idx(this.world, from.x, from.y);
|
|
const ids = this.grid.get(oldIdx);
|
|
if (ids) {
|
|
const index = ids.indexOf(actorId);
|
|
if (index !== -1) ids.splice(index, 1);
|
|
if (ids.length === 0) this.grid.delete(oldIdx);
|
|
}
|
|
|
|
// Update position
|
|
actor.pos.x = to.x;
|
|
actor.pos.y = to.y;
|
|
|
|
// Add to new position
|
|
const newIdx = idx(this.world, to.x, to.y);
|
|
if (!this.grid.has(newIdx)) this.grid.set(newIdx, []);
|
|
this.grid.get(newIdx)!.push(actorId);
|
|
}
|
|
|
|
addActor(actor: Actor) {
|
|
this.actors.set(actor.id, actor);
|
|
this.addToGrid(actor);
|
|
}
|
|
|
|
removeActor(actorId: EntityId) {
|
|
const actor = this.actors.get(actorId);
|
|
if (actor) {
|
|
this.removeFromGrid(actor);
|
|
this.actors.delete(actorId);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
getActorsAt(x: number, y: number): Actor[] {
|
|
const i = idx(this.world, x, y);
|
|
const ids = this.grid.get(i);
|
|
if (!ids) return [];
|
|
return ids.map(id => this.actors.get(id)!).filter(Boolean);
|
|
}
|
|
|
|
isOccupied(x: number, y: number, ignoreType?: string): boolean {
|
|
const actors = this.getActorsAt(x, y);
|
|
if (ignoreType) {
|
|
return actors.some(a => a.type !== ignoreType);
|
|
}
|
|
return actors.length > 0;
|
|
}
|
|
|
|
getNextId(): EntityId {
|
|
this.lastId++;
|
|
return this.lastId;
|
|
}
|
|
}
|
|
|