ecspresso
Version:
A minimal Entity-Component-System library for typescript and javascript.
136 lines (135 loc) • 4.76 kB
TypeScript
/**
* Detection Plugin for ECSpresso
*
* Provides automatic proximity detection for entities. Entities with a
* `detector` component get their `detectedEntities` populated each frame
* with nearby entities that match the configured collision layer filter,
* sorted by distance ascending (nearest first).
*
* Uses the spatial-index plugin for efficient range queries.
*/
import { type BasePluginOptions } from 'ecspresso';
import type { ComponentsConfig, EventsConfig, ResourcesConfig } from 'ecspresso';
import type { TransformWorldConfig } from '../spatial/transform';
import type { SpatialIndexResourceTypes } from '../spatial/spatial-index';
import type { CollisionComponentTypes } from '../physics/collision';
/**
* Configures proximity detection for an entity.
*/
export interface Detector {
/** Detection radius in world units */
range: number;
/** Only detect entities on these collision layers */
layerFilter: readonly string[];
/** Maximum number of results to track (default: 32) */
maxResults: number;
}
/**
* A detected entity with its squared distance from the detector.
*/
export interface DetectedEntry {
entityId: number;
distanceSq: number;
}
/**
* Auto-populated list of detected entities, sorted by distance ascending.
*/
export interface DetectedEntities {
entities: readonly DetectedEntry[];
}
/**
* Component types provided by the detection plugin.
*/
export interface DetectionComponentTypes {
detector: Detector;
detectedEntities: DetectedEntities;
}
/**
* Event fired when a new entity enters detection range.
*/
export interface DetectionGainedEvent {
/** The entity doing the detecting */
entityId: number;
/** The entity that was detected */
detectedId: number;
}
/**
* Event fired when an entity leaves detection range.
*/
export interface DetectionLostEvent {
/** The entity doing the detecting */
entityId: number;
/** The entity that was lost */
lostId: number;
}
/**
* Event types provided by the detection plugin.
*/
export interface DetectionEventTypes {
detectionGained: DetectionGainedEvent;
detectionLost: DetectionLostEvent;
}
/**
* WorldConfig representing the detection plugin's provided types.
*/
export type DetectionWorldConfig = ComponentsConfig<DetectionComponentTypes> & EventsConfig<DetectionEventTypes>;
export interface DetectionPluginOptions<G extends string = 'ai'> extends BasePluginOptions<G> {
}
/**
* Create a detector component.
*
* @param range Detection radius in world units
* @param layerFilter Only detect entities on these collision layers
* @param maxResults Maximum results to track (default: 32)
* @returns Component object suitable for spreading into spawn()
*
* @example
* ```typescript
* ecs.spawn({
* ...createDetector(300, ['enemy']),
* ...createLocalTransform(400, 400),
* });
* ```
*/
export declare function createDetector(range: number, layerFilter: readonly string[], maxResults?: number): Pick<DetectionComponentTypes, 'detector'>;
/**
* Check whether an entity has any detected targets.
*
* @param ecs ECS world instance
* @param entityId Entity with a detector component
* @returns true if detectedEntities contains at least one entry
*
* @example
* ```typescript
* if (hasDetectedTargets(ecs, guardId)) {
* // transition to chase
* }
* ```
*/
export declare function hasDetectedTargets(ecs: {
getComponent(entityId: number, name: 'detectedEntities'): DetectedEntities | undefined;
}, entityId: number): boolean;
/**
* Create a detection plugin for ECSpresso.
*
* Populates `detectedEntities` each frame with nearby entities matching
* the detector's layer filter, sorted by distance (nearest first).
* Publishes `detectionGained`/`detectionLost` events on transitions.
*
* Requires the spatial-index and transform plugins to be installed.
*
* @example
* ```typescript
* const ecs = ECSpresso.create()
* .withPlugin(createTransformPlugin())
* .withPlugin(createCollisionPlugin({ layers }))
* .withPlugin(createSpatialIndexPlugin())
* .withPlugin(createDetectionPlugin())
* .build();
*
* // Read nearest detected entity:
* const detected = ecs.getComponent(turretId, 'detectedEntities');
* const nearest = detected?.entities[0];
* ```
*/
export declare function createDetectionPlugin<G extends string = 'ai'>(options?: DetectionPluginOptions<G>): import("ecspresso").Plugin<import("ecspresso").WithEvents<import("ecspresso").WithComponents<import("ecspresso").EmptyConfig, DetectionComponentTypes>, DetectionEventTypes>, TransformWorldConfig & ComponentsConfig<Pick<CollisionComponentTypes<string>, "collisionLayer">> & ResourcesConfig<SpatialIndexResourceTypes>, "detection-scan", G, never, never>;