UNPKG

@rpgjs/physic

Version:

A deterministic 2D top-down physics library for RPG, sandbox and MMO games

212 lines (211 loc) 5.46 kB
import { Region } from "./index25.js"; import { AABB } from "./index4.js"; class RegionManager { /** * Creates a new region manager * * @param config - Manager configuration */ constructor(config) { this.regions = []; this.regionMap = /* @__PURE__ */ new Map(); this.entityRegionMap = /* @__PURE__ */ new Map(); this.config = { worldBounds: config.worldBounds, regionSize: config.regionSize, overlap: config.overlap ?? 0, autoActivate: config.autoActivate ?? true }; this.createRegions(); } /** * Creates the grid of regions */ createRegions() { const { worldBounds, regionSize, overlap } = this.config; const worldWidth = worldBounds.getWidth(); const worldHeight = worldBounds.getHeight(); const cols = Math.ceil(worldWidth / regionSize); const rows = Math.ceil(worldHeight / regionSize); for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const minX = worldBounds.minX + col * regionSize; const minY = worldBounds.minY + row * regionSize; const maxX = Math.min(minX + regionSize, worldBounds.maxX); const maxY = Math.min(minY + regionSize, worldBounds.maxY); const bounds = new AABB(minX, minY, maxX, maxY); const region = new Region({ bounds, overlap, active: !this.config.autoActivate // Start inactive if auto-activate is enabled }); const key = this.getRegionKey(col, row); this.regions.push(region); this.regionMap.set(key, region); } } } /** * Gets a region key from grid coordinates * * @param col - Column index * @param row - Row index * @returns Region key string */ getRegionKey(col, row) { return `${col},${row}`; } /** * Gets the region containing a point * * @param point - Point to find region for * @returns Region or null */ getRegionAt(point) { for (const region of this.regions) { if (region.contains(point)) { return region; } } return null; } /** * Gets all regions that overlap with an AABB * * @param bounds - AABB to check * @returns Array of overlapping regions */ getRegionsInBounds(bounds) { const result = []; for (const region of this.regions) { if (region.getExpandedBounds().intersects(bounds)) { result.push(region); } } return result; } /** * Adds an entity to the appropriate region * * @param entity - Entity to add */ addEntity(entity) { const region = this.getRegionAt(entity.position); if (region) { region.addEntity(entity); this.entityRegionMap.set(entity, region); if (this.config.autoActivate) { region.activate(); } } } /** * Removes an entity from its region * * @param entity - Entity to remove */ removeEntity(entity) { const region = this.entityRegionMap.get(entity); if (region) { region.removeEntity(entity); this.entityRegionMap.delete(entity); if (this.config.autoActivate && region.getEntities().length === 0) { region.deactivate(); } } } /** * Updates entity positions and migrates them between regions if needed */ updateEntities() { const entitiesToMigrate = []; for (const [entity, currentRegion] of this.entityRegionMap) { if (!currentRegion.shouldContain(entity)) { const newRegion = this.getRegionAt(entity.position); if (newRegion && newRegion !== currentRegion) { entitiesToMigrate.push({ entity, newRegion }); } } } for (const { entity, newRegion } of entitiesToMigrate) { const oldRegion = this.entityRegionMap.get(entity); if (oldRegion) { oldRegion.removeEntity(entity); } newRegion.addEntity(entity); this.entityRegionMap.set(entity, newRegion); if (this.config.autoActivate) { newRegion.activate(); } } } /** * Steps all active regions */ step() { this.updateEntities(); for (const region of this.regions) { if (region.isActive()) { region.step(); } } } /** * Gets all regions * * @returns Array of all regions */ getRegions() { return [...this.regions]; } /** * Gets active regions * * @returns Array of active regions */ getActiveRegions() { return this.regions.filter((r) => r.isActive()); } /** * Gets the region containing an entity * * @param entity - Entity to find region for * @returns Region or null */ getEntityRegion(entity) { return this.entityRegionMap.get(entity) ?? null; } /** * Clears all entities from all regions */ clear() { for (const region of this.regions) { const entities = region.getEntities(); for (const entity of entities) { region.removeEntity(entity); } } this.entityRegionMap.clear(); } /** * Gets statistics about regions * * @returns Statistics object */ getStats() { let totalEntities = 0; for (const region of this.regions) { totalEntities += region.getEntities().length; } return { totalRegions: this.regions.length, activeRegions: this.getActiveRegions().length, totalEntities }; } } export { RegionManager }; //# sourceMappingURL=index26.js.map