UNPKG

@hiddentao/clockwork-engine

Version:

A TypeScript/PIXI.js game engine for deterministic, replayable games with built-in rendering

104 lines (103 loc) 3.42 kB
import { EventEmitter } from "../EventEmitter"; /** * Events emitted by CollisionGrid */ export var CollisionGridEventType; (function (CollisionGridEventType) { CollisionGridEventType["POINTS_CHANGED"] = "pointsChanged"; })(CollisionGridEventType || (CollisionGridEventType = {})); /** * CollisionGrid uses direct coordinate mapping for extremely fast collision detection */ export class CollisionGrid extends EventEmitter { constructor() { super(); this.gridMap = new Map(); this.sourceMap = new Map(); } add(point, source) { const key = this.getKey(point); const sourceId = source.getCollisionSourceId(); // Check if already exists const existing = this.gridMap.get(key) || []; for (const existingSource of existing) { if (existingSource.getCollisionSourceId() === sourceId) { return false; } } // Add to grid if (!this.gridMap.has(key)) { this.gridMap.set(key, []); } this.gridMap.get(key).push(source); // Update source index if (!this.sourceMap.has(sourceId)) { this.sourceMap.set(sourceId, new Set()); } this.sourceMap.get(sourceId).add(key); this.emit(CollisionGridEventType.POINTS_CHANGED); return true; } remove(point, source) { const key = this.getKey(point); const sources = this.gridMap.get(key); if (!sources) return false; const sourceId = source.getCollisionSourceId(); const initialLength = sources.length; for (let i = sources.length - 1; i >= 0; i--) { if (sources[i].getCollisionSourceId() === sourceId) { sources.splice(i, 1); break; } } if (sources.length === 0) { this.gridMap.delete(key); } const sourceCoords = this.sourceMap.get(sourceId); if (sourceCoords) { sourceCoords.delete(key); if (sourceCoords.size === 0) { this.sourceMap.delete(sourceId); } } const removed = sources.length < initialLength; if (removed) { this.emit(CollisionGridEventType.POINTS_CHANGED); } return removed; } removeSource(source) { const sourceId = source.getCollisionSourceId(); const coords = this.sourceMap.get(sourceId); if (!coords || coords.size === 0) return false; for (const key of coords) { const sources = this.gridMap.get(key); if (sources) { const filtered = sources.filter((s) => s.getCollisionSourceId() !== sourceId); if (filtered.length === 0) { this.gridMap.delete(key); } else { this.gridMap.set(key, filtered); } } } this.sourceMap.delete(sourceId); this.emit(CollisionGridEventType.POINTS_CHANGED); return true; } containsPoint(point) { const key = this.getKey(point); return this.gridMap.get(key) || []; } clear() { this.gridMap.clear(); this.sourceMap.clear(); this.emit(CollisionGridEventType.POINTS_CHANGED); } getKey(point) { return `${point.x},${point.y}`; } }