UNPKG

@rpgjs/physic

Version:

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

211 lines 6.56 kB
import { Entity, EntityConfig } from '../physics/Entity'; import { IntegrationMethod } from '../physics/integrator'; import { EventSystem } from './events'; import { SpatialPartition } from './SpatialPartition'; import { Vector2 } from '../core/math/Vector2'; import { RaycastHit } from '../collision/Ray'; /** * World configuration */ export interface WorldConfig { /** Time step for simulation (default: 1/60 for 60 FPS) */ timeStep?: number; /** Integration method (default: Euler) */ integrationMethod?: IntegrationMethod; /** Gravity vector (default: zero for top-down) */ gravity?: Vector2; /** Spatial partition cell size (default: 100) */ spatialCellSize?: number; /** Spatial partition grid width (default: 100) */ spatialGridWidth?: number; /** Spatial partition grid height (default: 100) */ spatialGridHeight?: number; /** Enable sleep for inactive entities (default: true) */ enableSleep?: boolean; /** Tile width for grid-based logic (default: 32) */ tileWidth?: number; /** Tile height for grid-based logic (default: 32) */ tileHeight?: number; /** Sleep threshold in seconds (default: 0.5) */ sleepThreshold?: number; /** Velocity threshold for sleep detection (default: 0.01) */ sleepVelocityThreshold?: number; /** Custom spatial partition (optional) */ spatialPartition?: SpatialPartition; /** * Optional quantization step (world units) applied to positions after every tick. * Set to a positive number (e.g. 1/16) to reduce floating point drift for networking. */ positionQuantizationStep?: number; /** * Optional quantization step (world units / second) applied to velocities after every tick. * Set to a positive number (e.g. 1/256) to enforce deterministic clamps. */ velocityQuantizationStep?: number; /** * Number of collision-resolution iterations per tick (default: 3). * Higher values further reduce interpenetration in crowded scenes. */ resolverIterations?: number; /** Custom collision resolver factor controlling how aggressively overlaps are corrected. */ positionCorrectionFactor?: number; /** Maximum positional correction applied per iteration (world units). */ maxPositionCorrection?: number; /** Minimum penetration depth before a collision is resolved. */ minPenetrationDepth?: number; } /** * Physics world * * Manages entities, physics simulation, collisions, and events. * * @example * ```typescript * const world = new World({ timeStep: 1/60 }); * const entity = world.addEntity({ position: { x: 0, y: 0 }, radius: 10 }); * world.step(); * ``` */ export declare class World { private entities; private staticEntities; private dynamicEntities; private integrator; private resolver; private spatialPartition; private events; private timeStep; private enableSleep; private tileWidth; private tileHeight; private sleepThreshold; private sleepVelocityThreshold; private previousCollisions; private queryResults; private readonly positionQuantizationStep; private readonly velocityQuantizationStep; private readonly resolverIterations; /** * Creates a new physics world * * @param config - World configuration */ constructor(config?: WorldConfig); /** * Gets the event system * * @returns Event system instance */ getEvents(): EventSystem; /** * Returns the fixed simulation time step. * * @returns Time step in seconds */ getTimeStep(): number; /** * Adds an entity to the world * * @param entity - Entity to add * @returns The added entity */ addEntity(entity: Entity): Entity; /** * Performs a raycast against all entities in the world. * * @param origin - Starting point of the ray * @param direction - Direction of the ray (normalized) * @param length - Maximum length (default: Infinity) * @param mask - Optional collision mask (layer) * @param filter - Optional filter function (return true to include entity) * @returns Raycast hit info if hit, null otherwise */ raycast(origin: Vector2, direction: Vector2, length?: number, mask?: number, filter?: (entity: Entity) => boolean): RaycastHit | null; /** * Creates and adds a new entity * * @param config - Entity configuration * @returns Created entity */ createEntity(config: EntityConfig): Entity; /** * Removes an entity from the world * * @param entity - Entity to remove */ removeEntity(entity: Entity): void; /** * Gets all entities in the world * * @returns Array of entities */ getEntities(): Entity[]; /** * Gets an entity by UUID * * @param uuid - Entity UUID * @returns Entity or undefined */ getEntityByUUID(uuid: string): Entity | undefined; /** * Steps the physics simulation forward * * Updates all entities, detects and resolves collisions. */ step(): void; /** * Detects collisions using spatial partition * * @returns Array of collision infos */ /** * Detects collisions using spatial partition * * @returns Array of collision infos */ private detectCollisions; private sortCollisionsForDeterminism; private getCollisionKey; /** * Handles collision enter/exit events * * @param collisions - Current frame collisions */ private handleCollisionEvents; /** * Updates sleep state for entities */ private updateSleepState; /** * Clears all entities from the world */ clear(): void; private quantizeEntities; private quantizeValue; private refreshDynamicEntitiesInPartition; /** * Gets statistics about the world * * @returns Statistics object */ getStats(): { totalEntities: number; dynamicEntities: number; staticEntities: number; sleepingEntities: number; }; /** * Performs Continuous Collision Detection (CCD) for an entity * * @param entity - Entity to check */ /** * Updates entity tile position and triggers hooks * * @param entity - Entity to update * @param previousPosition - Position before integration */ private updateEntityTile; private performCCD; } //# sourceMappingURL=World.d.ts.map