UNPKG

ecspresso

Version:

A minimal Entity-Component-System library for typescript and javascript.

99 lines (98 loc) 4.17 kB
/** * Spatial Index 3D Plugin for ECSpresso * * Provides a uniform-grid spatial hash for broadphase collision detection * and proximity queries in 3D. Rebuilds the grid each frame from entity * transforms. Replaces O(n²) brute-force with O(n·d) where d = local density. * * Standalone usage: queryBox / queryRadius for proximity queries. * Automatic acceleration: collision3D and physics3D plugins detect the * spatialIndex3D resource at runtime and use it for broadphase when present. */ import type { Transform3DComponentTypes } from './transform3D'; import { type SpatialIndex3D } from '../../utils/spatial-hash3D'; /** * 3D axis-aligned bounding box collider component. * Defined here (spatial layer) so collision3D can import rather than redefine. */ export interface AABB3DCollider { width: number; height: number; depth: number; offsetX?: number; offsetY?: number; offsetZ?: number; } /** * Sphere collider component. * Defined here (spatial layer) so collision3D can import rather than redefine. */ export interface SphereCollider { radius: number; offsetX?: number; offsetY?: number; offsetZ?: number; } export interface Spatial3DColliderComponentTypes { aabb3DCollider: AABB3DCollider; sphereCollider: SphereCollider; } export interface SpatialIndex3DResourceTypes { spatialIndex3D: SpatialIndex3D; } type SpatialIndex3DComponentTypes = Transform3DComponentTypes & Spatial3DColliderComponentTypes; export type SpatialIndex3DPhase = 'fixedUpdate' | 'postUpdate'; export interface SpatialIndex3DPluginOptions<G extends string = 'spatialIndex3D'> { /** Cell size for the spatial hash grid (default: 64) */ cellSize?: number; /** System group name (default: 'spatialIndex3D') */ systemGroup?: G; /** Priority for rebuild systems (default: 2000, before collision) */ priority?: number; /** * Phases to register rebuild systems in (default: ['fixedUpdate', 'postUpdate']). * * When both phases are registered, the `postUpdate` rebuild is * automatically skipped on cycles where: * 1. The `fixedUpdate` rebuild already ran this cycle, AND * 2. No entity hierarchy exists. * * In flat-hierarchy scenes `transform3d-propagation` copies * `localTransform3D → worldTransform3D` unchanged, so the postUpdate * grid would duplicate the fixedUpdate one. The skip is automatic * and re-engages once any parent relationship is set, or whenever * `fixedUpdate` doesn't run that cycle (sub-fixed-DT frames). * * Edge case: if you write to `worldTransform3D` directly between * phases without using `transform3d-propagation` or entity hierarchy, * the auto-skip will leave your writes unindexed. Set * `phases: ['postUpdate']` explicitly to bypass the auto-skip. */ phases?: ReadonlyArray<SpatialIndex3DPhase>; } /** * Create a 3D spatial index plugin for ECSpresso. * * Provides a uniform-grid spatial hash that accelerates 3D collision detection. * When installed alongside the collision3D or physics3D plugins, they * automatically use the spatial index for broadphase instead of O(n²) * brute-force. * * Also provides proximity query methods for game logic (e.g. "find all * enemies within 200 units"). * * @example * ```typescript * const ecs = ECSpresso.create() * .withPlugin(createTransform3DPlugin()) * .withPlugin(createCollision3DPlugin({ layers })) * .withPlugin(createSpatialIndex3DPlugin({ cellSize: 128 })) * .build(); * * // Proximity query in a system: * const si = ecs.getResource('spatialIndex3D'); * const nearby = si.queryRadius(playerX, playerY, playerZ, 200); * ``` */ export declare function createSpatialIndex3DPlugin<G extends string = 'spatialIndex3D'>(options?: SpatialIndex3DPluginOptions<G>): import("ecspresso").Plugin<import("ecspresso").WithResources<import("ecspresso").WithComponents<import("ecspresso").EmptyConfig, SpatialIndex3DComponentTypes>, SpatialIndex3DResourceTypes>, import("ecspresso").EmptyConfig, "spatial-index3D-rebuild-fixedUpdate" | "spatial-index3D-rebuild-postUpdate", G, never, never>; export {};