UNPKG

@rpgjs/physic

Version:

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

338 lines 10.1 kB
import { World, WorldConfig } from '../world/World'; import { Entity, EntityConfig } from '../physics/Entity'; import { RegionManager, RegionManagerConfig } from '../region/RegionManager'; import { EventSystem } from '../world/events'; import { Vector2 } from '../core/math/Vector2'; import { AABB } from '../core/math/AABB'; import { PolygonConfig } from '../collision/PolygonCollider'; import { RaycastHit } from '../collision/raycast'; import { SweepResult } from '../collision/sweep'; import { MovementManager } from '../movement/MovementManager'; import { ZoneManager } from './ZoneManager'; /** * Physics engine configuration */ export interface PhysicsEngineConfig extends WorldConfig { /** Enable region-based simulation (default: false) */ enableRegions?: boolean; /** Region manager configuration (required if enableRegions is true) */ regionConfig?: RegionManagerConfig; } /** * Main physics engine interface * * Provides a high-level, gameplay-oriented API for physics simulation. * Supports both single-world and multi-region simulation modes. * * @example * ```typescript * const engine = new PhysicsEngine({ timeStep: 1/60 }); * const entity = engine.createEntity({ * position: { x: 0, y: 0 }, * radius: 10, * mass: 1 * }); * * engine.step(); * ``` */ export declare class PhysicsEngine { private world; private regionManager; private useRegions; private movementManager; private zoneManager; private tick; /** * Creates a new physics engine * * @param config - Engine configuration */ constructor(config?: PhysicsEngineConfig); /** * Gets the movement manager bound to this engine. * * The manager is lazily created and reused. * * @returns Movement manager instance */ getMovementManager(): MovementManager; /** * Gets the zone manager bound to this engine. * * The manager is lazily created and reused. Zones allow detecting entities * within circular or cone-shaped areas without physical collisions (useful * for vision, skill ranges, explosions, etc.). * * **Important:** Call `zoneManager.update()` after each physics step to * keep zones synchronized: * * ```typescript * engine.step(); * engine.getZoneManager().update(); * ``` * * @returns Zone manager instance * * @example * ```typescript * const zones = engine.getZoneManager(); * const visionZone = zones.createAttachedZone(player, { * radius: 100, * angle: 90, * direction: 'right', * }, { * onEnter: (entities) => console.log('Player sees:', entities), * }); * * engine.step(); * zones.update(); * ``` */ getZoneManager(): ZoneManager; /** * Updates all registered movement strategies. * * @param dt - Time delta in seconds (defaults to the world's time step) */ updateMovements(dt?: number): void; /** * Updates movements and then steps the simulation. * * @param dt - Time delta in seconds (defaults to the world's time step) */ stepWithMovements(dt?: number): void; /** * Advances the simulation by exactly one fixed tick. * * This helper is equivalent to {@link step} but returns the tick index after the step, * making it convenient for client-side prediction loops. * * @returns Current tick index after stepping */ stepOneTick(): number; /** * Advances the simulation by a fixed number of ticks. * * @param ticks - Number of ticks to simulate (>= 1) * @returns Current tick index after stepping */ stepTicks(ticks: number): number; /** * Creates a new entity * * @param config - Entity configuration * @returns Created entity * * @example * ```typescript * const entity = engine.createEntity({ * position: { x: 100, y: 100 }, * radius: 15, * mass: 1, * velocity: { x: 5, y: 0 } * }); * ``` */ createEntity(config: EntityConfig): Entity; /** * Adds an existing entity to the engine * * @param entity - Entity to add * @returns The added entity */ addEntity(entity: Entity): Entity; /** * Removes an entity from the engine * * @param entity - Entity to remove */ removeEntity(entity: Entity): void; /** * Gets all entities * * @returns Array of all 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; /** * Gets the event system * * @returns Event system instance */ getEvents(): EventSystem; /** * Applies a force to an entity * * @param entity - Entity to apply force to * @param force - Force vector */ applyForce(entity: Entity, force: Vector2): void; /** * Applies an impulse to an entity * * @param entity - Entity to apply impulse to * @param impulse - Impulse vector */ applyImpulse(entity: Entity, impulse: Vector2): void; /** * Teleports an entity to a new position * * @param entity - Entity to teleport * @param position - New position */ teleport(entity: Entity, position: Vector2 | { x: number; y: number; }): void; /** * Freezes an entity (makes it static) * * @param entity - Entity to freeze */ freeze(entity: Entity): void; /** * Unfreezes an entity (makes it dynamic) * * @param entity - Entity to unfreeze */ unfreeze(entity: Entity): void; /** * Queries entities in an AABB region * * @param bounds - AABB to query * @returns Array of entities in the region */ queryAABB(bounds: AABB): Entity[]; /** * Clears all entities from the engine */ clear(): void; /** * Assigns a polygon collider to an entity (supports convex or concave via convex parts). * * Design: the collider is attached via a registry and used by the detector on demand. * This keeps entities lightweight and preserves the separation of detection/resolution. * * @param entity - Target entity * @param config - Polygon configuration * @example * ```typescript * engine.assignPolygonCollider(entity, { vertices: [new Vector2(-1,-1), new Vector2(1,-1), new Vector2(1,1), new Vector2(-1,1)], isConvex: true }); * ``` */ assignPolygonCollider(entity: Entity, config: PolygonConfig): void; /** * Casts a ray in the physics world and returns the nearest hit, if any. * Uses the world's spatial partition for broad-phase and shape-specific narrow-phase tests. * * @param origin - Ray origin * @param direction - Ray direction (any length) * @param maxDistance - Maximum cast length * @param mask - Optional collision mask (layer) * @param filter - Optional filter function (return true to include entity) * @returns Raycast hit or null * @example * ```typescript * const hit = engine.raycast(new Vector2(0,0), new Vector2(1,0), 1000); * ``` */ raycast(origin: Vector2, direction: Vector2, maxDistance: number, mask?: number, filter?: (entity: Entity) => boolean): RaycastHit | null; /** * Computes continuous collision detection (sweep test) time-of-impact between two entities * over the next step of duration `dt`, using relative motion. * * @param a - First entity * @param b - Second entity * @param dt - Time step duration * @returns Sweep result or null if no hit in [0,1] * @example * ```typescript * const toi = engine.sweep(entityA, entityB, 1/60); * if (toi) { * // pre-resolve or clamp motion * } * ``` */ sweep(a: Entity, b: Entity, dt: number): SweepResult | null; /** * Gets statistics about the engine * * @returns Statistics object */ getStats(): { totalEntities: number; dynamicEntities: number; staticEntities: number; sleepingEntities: number; regions?: { total: number; active: number; }; }; /** * Gets the underlying world instance * * @returns World instance */ getWorld(): World; /** * Gets the current simulation tick. * * @returns Tick counter (starts at 0 and increments after each {@link step}) */ getTick(): number; /** * Captures a lightweight snapshot of the current world state. * * The snapshot only stores the minimum data required for client-side prediction: * position, velocity, rotation, angular velocity and sleeping flag per entity. * * @returns Snapshot object */ takeSnapshot(): PhysicsSnapshot; /** * Restores a snapshot previously produced by {@link takeSnapshot}. * * Entities that cannot be found in the current engine are skipped silently. * * @param snapshot - Snapshot to restore */ restoreSnapshot(snapshot: PhysicsSnapshot): void; /** * Gets the region manager (if regions are enabled) * * @returns Region manager or null */ getRegionManager(): RegionManager | null; } export interface PhysicsSnapshot { tick: number; entities: Array<{ uuid: string; position: { x: number; y: number; }; velocity: { x: number; y: number; }; rotation: number; angularVelocity: number; sleeping: boolean; }>; } //# sourceMappingURL=PhysicsEngine.d.ts.map