@ue-too/ecs 0.9.5 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,364 @@
1
- # ecs
2
- This is an experimental implementation of the Entity Component System architecture.
1
+ # @ue-too/ecs
3
2
 
4
- Following the tutorial from [Austin Morlan](https://austinmorlan.com/posts/entity_component_system/).
3
+ High-performance Entity Component System (ECS) architecture for TypeScript.
5
4
 
6
- Please _**DO NOT**_ use this in production.
5
+ [![npm version](https://img.shields.io/npm/v/@ue-too/ecs.svg)](https://www.npmjs.com/package/@ue-too/ecs)
6
+ [![license](https://img.shields.io/npm/l/@ue-too/ecs.svg)](https://github.com/ue-too/ue-too/blob/main/LICENSE.txt)
7
7
 
8
- Detailed information would be added in the future.
8
+ > **Experimental**: This package is an experimental implementation based on [Austin Morlan's ECS tutorial](https://austinmorlan.com/posts/entity_component_system/). Please **DO NOT** use this in production.
9
+
10
+ ## Overview
11
+
12
+ `@ue-too/ecs` provides a lightweight Entity Component System implementation for TypeScript. ECS is an architectural pattern commonly used in game development that promotes composition over inheritance and enables high-performance iteration over game objects.
13
+
14
+ ### Key Features
15
+
16
+ - **Efficient Storage**: Component arrays using sparse-set data structure for O(1) lookups
17
+ - **Fast Iteration**: Dense packing enables cache-friendly iteration over components
18
+ - **Type Safety**: Full TypeScript generics for component type safety
19
+ - **Signature Matching**: Automatic system updates when entity component composition changes
20
+ - **Entity Pooling**: Entity ID recycling for memory efficiency
21
+ - **Minimal Overhead**: Lightweight architecture with predictable performance
22
+
23
+ ## Installation
24
+
25
+ Using Bun:
26
+ ```bash
27
+ bun add @ue-too/ecs
28
+ ```
29
+
30
+ Using npm:
31
+ ```bash
32
+ npm install @ue-too/ecs
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ Here's a simple example demonstrating the core ECS workflow:
38
+
39
+ ```typescript
40
+ import { Coordinator } from '@ue-too/ecs';
41
+
42
+ // 1. Define component types
43
+ type Position = { x: number; y: number };
44
+ type Velocity = { x: number; y: number };
45
+ type Health = { current: number; max: number };
46
+
47
+ // 2. Create coordinator
48
+ const ecs = new Coordinator();
49
+
50
+ // 3. Register components
51
+ ecs.registerComponent<Position>('Position');
52
+ ecs.registerComponent<Velocity>('Velocity');
53
+ ecs.registerComponent<Health>('Health');
54
+
55
+ // 4. Create entities and add components
56
+ const player = ecs.createEntity();
57
+ ecs.addComponentToEntity('Position', player, { x: 0, y: 0 });
58
+ ecs.addComponentToEntity('Velocity', player, { x: 5, y: 0 });
59
+ ecs.addComponentToEntity('Health', player, { current: 100, max: 100 });
60
+
61
+ const enemy = ecs.createEntity();
62
+ ecs.addComponentToEntity('Position', enemy, { x: 50, y: 50 });
63
+ ecs.addComponentToEntity('Health', enemy, { current: 50, max: 50 });
64
+
65
+ // 5. Query and update components
66
+ const playerPos = ecs.getComponentFromEntity<Position>('Position', player);
67
+ const playerVel = ecs.getComponentFromEntity<Velocity>('Velocity', player);
68
+
69
+ if (playerPos && playerVel) {
70
+ playerPos.x += playerVel.x;
71
+ playerPos.y += playerVel.y;
72
+ }
73
+
74
+ // 6. Clean up
75
+ ecs.destroyEntity(enemy);
76
+ ```
77
+
78
+ ## ECS Architecture
79
+
80
+ The Entity Component System pattern separates data from logic:
81
+
82
+ - **Entities**: Unique identifiers (numbers) representing game objects
83
+ - **Components**: Plain data containers (no logic)
84
+ - **Systems**: Functions that operate on entities with specific component combinations
85
+
86
+ ### Why ECS?
87
+
88
+ Traditional object-oriented hierarchies can become complex and rigid. ECS promotes:
89
+
90
+ - **Composition over inheritance**: Build entities by combining components
91
+ - **Data locality**: Components are stored in dense arrays for better cache performance
92
+ - **Flexibility**: Easy to add/remove behaviors by adding/removing components
93
+ - **Parallelization**: Systems can operate independently on entity subsets
94
+
95
+ ## Core APIs
96
+
97
+ ### Coordinator
98
+
99
+ The main ECS coordinator that manages all subsystems.
100
+
101
+ ```typescript
102
+ const ecs = new Coordinator();
103
+ ```
104
+
105
+ **Entity Management:**
106
+ - `createEntity(): Entity` - Creates a new entity, returns entity ID
107
+ - `destroyEntity(entity: Entity): void` - Destroys entity and removes all components
108
+
109
+ **Component Management:**
110
+ - `registerComponent<T>(name: string): void` - Registers a component type
111
+ - `addComponentToEntity<T>(name: string, entity: Entity, component: T): void` - Adds component to entity
112
+ - `removeComponentFromEntity<T>(name: string, entity: Entity): void` - Removes component from entity
113
+ - `getComponentFromEntity<T>(name: string, entity: Entity): T | null` - Retrieves component data
114
+ - `getComponentType(name: string): ComponentType | null` - Gets component type ID
115
+
116
+ **System Management:**
117
+ - `registerSystem(name: string, system: System): void` - Registers a system
118
+ - `setSystemSignature(name: string, signature: ComponentSignature): void` - Sets which components a system requires
119
+
120
+ ### System Interface
121
+
122
+ Systems maintain a set of entities that match their component signature:
123
+
124
+ ```typescript
125
+ interface System {
126
+ entities: Set<Entity>;
127
+ }
128
+ ```
129
+
130
+ ### Component Signature
131
+
132
+ Bit flags indicating which components an entity has:
133
+
134
+ ```typescript
135
+ type ComponentSignature = number; // Bit field
136
+ type ComponentType = number; // Component type ID (0-31)
137
+ type Entity = number; // Entity ID
138
+ ```
139
+
140
+ ## Common Use Cases
141
+
142
+ ### Movement System
143
+
144
+ Update positions based on velocities:
145
+
146
+ ```typescript
147
+ import { Coordinator, System } from '@ue-too/ecs';
148
+
149
+ const ecs = new Coordinator();
150
+
151
+ // Register components
152
+ ecs.registerComponent<Position>('Position');
153
+ ecs.registerComponent<Velocity>('Velocity');
154
+
155
+ // Create movement system
156
+ const movementSystem: System = {
157
+ entities: new Set()
158
+ };
159
+
160
+ ecs.registerSystem('Movement', movementSystem);
161
+
162
+ // Set signature: entities with Position AND Velocity
163
+ const posType = ecs.getComponentType('Position')!;
164
+ const velType = ecs.getComponentType('Velocity')!;
165
+ const signature = (1 << posType) | (1 << velType);
166
+ ecs.setSystemSignature('Movement', signature);
167
+
168
+ // Update loop
169
+ function update(deltaTime: number) {
170
+ movementSystem.entities.forEach(entity => {
171
+ const pos = ecs.getComponentFromEntity<Position>('Position', entity)!;
172
+ const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity)!;
173
+
174
+ pos.x += vel.x * deltaTime;
175
+ pos.y += vel.y * deltaTime;
176
+ });
177
+ }
178
+
179
+ // Game loop
180
+ setInterval(() => update(0.016), 16); // ~60 FPS
181
+ ```
182
+
183
+ ### Damage System
184
+
185
+ Process health and damage components:
186
+
187
+ ```typescript
188
+ type Health = { current: number; max: number };
189
+ type Damage = { amount: number; source: Entity };
190
+
191
+ ecs.registerComponent<Health>('Health');
192
+ ecs.registerComponent<Damage>('Damage');
193
+
194
+ const damageSystem: System = { entities: new Set() };
195
+ ecs.registerSystem('Damage', damageSystem);
196
+
197
+ const healthType = ecs.getComponentType('Health')!;
198
+ const damageType = ecs.getComponentType('Damage')!;
199
+ const damageSignature = (1 << healthType) | (1 << damageType);
200
+ ecs.setSystemSignature('Damage', damageSignature);
201
+
202
+ function processDamage() {
203
+ damageSystem.entities.forEach(entity => {
204
+ const health = ecs.getComponentFromEntity<Health>('Health', entity)!;
205
+ const damage = ecs.getComponentFromEntity<Damage>('Damage', entity)!;
206
+
207
+ health.current -= damage.amount;
208
+
209
+ if (health.current <= 0) {
210
+ console.log(`Entity ${entity} destroyed`);
211
+ ecs.destroyEntity(entity);
212
+ } else {
213
+ // Remove damage component after processing
214
+ ecs.removeComponentFromEntity<Damage>('Damage', entity);
215
+ }
216
+ });
217
+ }
218
+ ```
219
+
220
+ ### Rendering System
221
+
222
+ Render entities with position and sprite components:
223
+
224
+ ```typescript
225
+ type Sprite = { imageSrc: string; width: number; height: number };
226
+
227
+ ecs.registerComponent<Sprite>('Sprite');
228
+
229
+ const renderSystem: System = { entities: new Set() };
230
+ ecs.registerSystem('Render', renderSystem);
231
+
232
+ const spriteType = ecs.getComponentType('Sprite')!;
233
+ const renderSignature = (1 << posType) | (1 << spriteType);
234
+ ecs.setSystemSignature('Render', renderSignature);
235
+
236
+ function render(ctx: CanvasRenderingContext2D) {
237
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
238
+
239
+ renderSystem.entities.forEach(entity => {
240
+ const pos = ecs.getComponentFromEntity<Position>('Position', entity)!;
241
+ const sprite = ecs.getComponentFromEntity<Sprite>('Sprite', entity)!;
242
+
243
+ // Draw sprite at position
244
+ const img = new Image();
245
+ img.src = sprite.imageSrc;
246
+ ctx.drawImage(img, pos.x, pos.y, sprite.width, sprite.height);
247
+ });
248
+ }
249
+ ```
250
+
251
+ ### Component Signature Building
252
+
253
+ Build complex component requirements:
254
+
255
+ ```typescript
256
+ // Entities that have Position, Velocity, AND Sprite
257
+ const movingRenderables =
258
+ (1 << ecs.getComponentType('Position')!) |
259
+ (1 << ecs.getComponentType('Velocity')!) |
260
+ (1 << ecs.getComponentType('Sprite')!);
261
+
262
+ // Helper function for cleaner syntax
263
+ function buildSignature(ecs: Coordinator, ...componentNames: string[]): number {
264
+ return componentNames.reduce((signature, name) => {
265
+ const type = ecs.getComponentType(name);
266
+ return type !== null ? signature | (1 << type) : signature;
267
+ }, 0);
268
+ }
269
+
270
+ // Usage
271
+ const signature = buildSignature(ecs, 'Position', 'Velocity', 'Health');
272
+ ecs.setSystemSignature('MySystem', signature);
273
+ ```
274
+
275
+ ## Configuration
276
+
277
+ The package provides configuration constants:
278
+
279
+ ```typescript
280
+ export const MAX_ENTITIES = 10000; // Maximum simultaneous entities
281
+ export const MAX_COMPONENTS = 32; // Maximum component types (bit limit)
282
+ ```
283
+
284
+ To customize, you can create your own EntityManager:
285
+
286
+ ```typescript
287
+ import { EntityManager } from '@ue-too/ecs';
288
+
289
+ const entityManager = new EntityManager(5000); // Custom max entities
290
+ ```
291
+
292
+ ## API Reference
293
+
294
+ For complete API documentation with detailed type information, see the [TypeDoc-generated documentation](../../docs/ecs).
295
+
296
+ ## TypeScript Support
297
+
298
+ This package is written in TypeScript with complete type definitions:
299
+
300
+ ```typescript
301
+ // Component types are fully typed
302
+ type Position = { x: number; y: number };
303
+ ecs.registerComponent<Position>('Position');
304
+
305
+ // Type-safe component retrieval
306
+ const pos = ecs.getComponentFromEntity<Position>('Position', entity);
307
+ if (pos) {
308
+ pos.x += 10; // TypeScript knows pos has x and y properties
309
+ }
310
+
311
+ // Generic component arrays
312
+ import { ComponentArray } from '@ue-too/ecs';
313
+ const positions = new ComponentArray<Position>(1000);
314
+ ```
315
+
316
+ ## Design Principles
317
+
318
+ This ECS implementation follows these principles:
319
+
320
+ - **Simplicity**: Minimal API surface for easy learning
321
+ - **Performance**: Sparse-set data structure for O(1) operations
322
+ - **Type Safety**: Leverage TypeScript's type system
323
+ - **Flexibility**: Components are plain data objects
324
+ - **Explicit**: No magic, predictable behavior
325
+
326
+ ## Performance Considerations
327
+
328
+ - **Entity Creation**: O(1) - pops from available entity pool
329
+ - **Component Lookup**: O(1) - sparse-set provides constant-time access
330
+ - **Component Iteration**: O(n) - dense array iteration for cache efficiency
331
+ - **Signature Matching**: O(m) where m is number of systems (typically small)
332
+
333
+ **Performance Tips:**
334
+ - Keep component data small and focused
335
+ - Process components in batches (system-by-system) rather than entity-by-entity
336
+ - Reuse entities when possible instead of create/destroy cycles
337
+ - Limit number of component types (max 32 due to bit signature)
338
+
339
+ ## Limitations
340
+
341
+ - **Max 32 component types**: Component signatures use 32-bit integers
342
+ - **No component queries**: Must register systems with signatures upfront
343
+ - **No hierarchical entities**: Flat entity structure only
344
+ - **No built-in serialization**: Component data must be manually serialized
345
+
346
+ ## Related Packages
347
+
348
+ - **[@ue-too/being](../being)**: State machine library for entity AI and behavior
349
+ - **[@ue-too/math](../math)**: Vector and transformation utilities for component data
350
+ - **[@ue-too/board](../board)**: Canvas rendering system that can integrate with ECS
351
+
352
+ ## Further Reading
353
+
354
+ - [Austin Morlan's ECS Tutorial](https://austinmorlan.com/posts/entity_component_system/) - Original tutorial this implementation is based on
355
+ - [ECS FAQ](https://github.com/SanderMertens/ecs-faq) - Comprehensive ECS concepts and patterns
356
+ - [Data-Oriented Design](https://www.dataorienteddesign.com/dodbook/) - Principles behind ECS architecture
357
+
358
+ ## License
359
+
360
+ MIT
361
+
362
+ ## Repository
363
+
364
+ [https://github.com/ue-too/ue-too](https://github.com/ue-too/ue-too)
package/index.d.ts CHANGED
@@ -1,9 +1,134 @@
1
- /** This is a direct port of the tutorial from https://austinmorlan.com/posts/entity_component_system/ with slight modifications */
1
+ /**
2
+ * @packageDocumentation
3
+ * Entity Component System (ECS) implementation for TypeScript.
4
+ *
5
+ * @remarks
6
+ * The `@ue-too/ecs` package provides a high-performance Entity Component System architecture
7
+ * based on the tutorial from https://austinmorlan.com/posts/entity_component_system/
8
+ *
9
+ * ## ECS Architecture
10
+ *
11
+ * - **Entities**: Unique identifiers (numbers) representing game objects
12
+ * - **Components**: Data containers attached to entities
13
+ * - **Systems**: Logic that operates on entities with specific component combinations
14
+ * - **Signatures**: Bit flags indicating which components an entity has
15
+ *
16
+ * ## Key Features
17
+ *
18
+ * - **Efficient Storage**: Component arrays using sparse-set data structure
19
+ * - **Fast Iteration**: Dense packing for cache-friendly iteration
20
+ * - **Type-Safe**: TypeScript generics for component type safety
21
+ * - **Signature Matching**: Automatic system updates when entity signatures change
22
+ * - **Pooling**: Entity ID recycling for memory efficiency
23
+ *
24
+ * ## Core Classes
25
+ *
26
+ * - {@link Coordinator}: Main ECS coordinator managing all subsystems
27
+ * - {@link EntityManager}: Creates and destroys entities
28
+ * - {@link ComponentManager}: Registers components and manages component data
29
+ * - {@link SystemManager}: Registers systems and maintains entity sets
30
+ * - {@link ComponentArray}: Efficient sparse-set storage for component data
31
+ *
32
+ * @example
33
+ * Basic ECS usage
34
+ * ```typescript
35
+ * import { Coordinator } from '@ue-too/ecs';
36
+ *
37
+ * // Define component types
38
+ * type Position = { x: number; y: number };
39
+ * type Velocity = { x: number; y: number };
40
+ *
41
+ * // Create coordinator
42
+ * const coordinator = new Coordinator();
43
+ *
44
+ * // Register components
45
+ * coordinator.registerComponent<Position>('Position');
46
+ * coordinator.registerComponent<Velocity>('Velocity');
47
+ *
48
+ * // Create entity with components
49
+ * const entity = coordinator.createEntity();
50
+ * coordinator.addComponentToEntity('Position', entity, { x: 0, y: 0 });
51
+ * coordinator.addComponentToEntity('Velocity', entity, { x: 1, y: 1 });
52
+ *
53
+ * // Query components
54
+ * const pos = coordinator.getComponentFromEntity<Position>('Position', entity);
55
+ * console.log('Position:', pos);
56
+ * ```
57
+ *
58
+ * @example
59
+ * System registration
60
+ * ```typescript
61
+ * import { Coordinator, System } from '@ue-too/ecs';
62
+ *
63
+ * const coordinator = new Coordinator();
64
+ * coordinator.registerComponent<Position>('Position');
65
+ * coordinator.registerComponent<Velocity>('Velocity');
66
+ *
67
+ * // Create a movement system
68
+ * const movementSystem: System = {
69
+ * entities: new Set()
70
+ * };
71
+ *
72
+ * coordinator.registerSystem('Movement', movementSystem);
73
+ *
74
+ * // Set signature (entities with Position AND Velocity)
75
+ * const posType = coordinator.getComponentType('Position')!;
76
+ * const velType = coordinator.getComponentType('Velocity')!;
77
+ * const signature = (1 << posType) | (1 << velType);
78
+ * coordinator.setSystemSignature('Movement', signature);
79
+ *
80
+ * // Update loop
81
+ * function update(deltaTime: number) {
82
+ * movementSystem.entities.forEach(entity => {
83
+ * const pos = coordinator.getComponentFromEntity<Position>('Position', entity)!;
84
+ * const vel = coordinator.getComponentFromEntity<Velocity>('Velocity', entity)!;
85
+ * pos.x += vel.x * deltaTime;
86
+ * pos.y += vel.y * deltaTime;
87
+ * });
88
+ * }
89
+ * ```
90
+ *
91
+ * @see {@link Coordinator} for the main ECS API
92
+ */
93
+ /**
94
+ * Maximum number of entities that can exist simultaneously.
95
+ * @category Configuration
96
+ */
2
97
  export declare const MAX_ENTITIES = 10000;
98
+ /**
99
+ * Maximum number of component types that can be registered.
100
+ * @category Configuration
101
+ */
3
102
  export declare const MAX_COMPONENTS = 32;
103
+ /**
104
+ * Component signature type (bit field indicating which components an entity has).
105
+ * @category Types
106
+ */
4
107
  export type ComponentSignature = number;
108
+ /**
109
+ * Component type identifier.
110
+ * @category Types
111
+ */
5
112
  export type ComponentType = number;
113
+ /**
114
+ * Entity identifier (unique number).
115
+ * @category Types
116
+ */
6
117
  export type Entity = number;
118
+ /**
119
+ * Manages entity lifecycle and signatures.
120
+ *
121
+ * @remarks
122
+ * The EntityManager handles:
123
+ * - Creating new entities (recycling IDs from a pool)
124
+ * - Destroying entities (returning IDs to the pool)
125
+ * - Storing and updating component signatures for each entity
126
+ *
127
+ * Entities are represented as simple numbers (IDs) and the manager maintains
128
+ * a signature (bit field) for each entity indicating which components it has.
129
+ *
130
+ * @category Managers
131
+ */
7
132
  export declare class EntityManager {
8
133
  private _availableEntities;
9
134
  private _signatures;
@@ -15,9 +140,32 @@ export declare class EntityManager {
15
140
  setSignature(entity: Entity, signature: ComponentSignature): void;
16
141
  getSignature(entity: Entity): ComponentSignature | null;
17
142
  }
143
+ /**
144
+ * Internal interface for component array lifecycle hooks.
145
+ * @internal
146
+ */
18
147
  export interface CArray {
19
148
  entityDestroyed(entity: Entity): void;
20
149
  }
150
+ /**
151
+ * Efficient sparse-set data structure for storing component data.
152
+ *
153
+ * @remarks
154
+ * ComponentArray uses a sparse-set implementation for O(1) insertion, deletion,
155
+ * and lookup while maintaining dense packing for cache-efficient iteration.
156
+ *
157
+ * The sparse-set consists of:
158
+ * - **Dense array**: Packed component data for iteration
159
+ * - **Sparse array**: Maps entity ID to dense array index
160
+ * - **Reverse array**: Maps dense array index back to entity ID
161
+ *
162
+ * This structure allows fast component access by entity ID and fast iteration
163
+ * over all components without gaps.
164
+ *
165
+ * @typeParam T - The component data type
166
+ *
167
+ * @category Data Structures
168
+ */
21
169
  export declare class ComponentArray<T> implements CArray {
22
170
  private denseArray;
23
171
  private sparse;
@@ -29,6 +177,21 @@ export declare class ComponentArray<T> implements CArray {
29
177
  removeData(entity: Entity): void;
30
178
  entityDestroyed(entity: Entity): void;
31
179
  }
180
+ /**
181
+ * Manages component registration and component data storage.
182
+ *
183
+ * @remarks
184
+ * The ComponentManager handles:
185
+ * - Registering new component types and assigning unique type IDs
186
+ * - Creating ComponentArray storage for each component type
187
+ * - Adding, removing, and querying component data for entities
188
+ * - Cleaning up component data when entities are destroyed
189
+ *
190
+ * Each component type gets a unique ID (0-31) and its own ComponentArray
191
+ * for efficient storage and retrieval.
192
+ *
193
+ * @category Managers
194
+ */
32
195
  export declare class ComponentManager {
33
196
  private _componentNameToTypeMap;
34
197
  private _nextAvailableComponentType;
@@ -40,9 +203,58 @@ export declare class ComponentManager {
40
203
  entityDestroyed(entity: Entity): void;
41
204
  private _getComponentArray;
42
205
  }
206
+ /**
207
+ * System interface for processing entities with specific component combinations.
208
+ *
209
+ * @remarks
210
+ * A System maintains a set of entities that match its component signature.
211
+ * The ECS automatically updates this set when entities are created, destroyed,
212
+ * or have their components modified.
213
+ *
214
+ * Systems contain only the logic for processing entities - the `entities` set
215
+ * is automatically managed by the SystemManager.
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * const movementSystem: System = {
220
+ * entities: new Set()
221
+ * };
222
+ *
223
+ * // System logic (called in game loop)
224
+ * function updateMovement(deltaTime: number) {
225
+ * movementSystem.entities.forEach(entity => {
226
+ * const pos = ecs.getComponentFromEntity<Position>('Position', entity);
227
+ * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);
228
+ * if (pos && vel) {
229
+ * pos.x += vel.x * deltaTime;
230
+ * pos.y += vel.y * deltaTime;
231
+ * }
232
+ * });
233
+ * }
234
+ * ```
235
+ *
236
+ * @category Types
237
+ */
43
238
  export interface System {
44
239
  entities: Set<Entity>;
45
240
  }
241
+ /**
242
+ * Manages system registration and entity-system matching.
243
+ *
244
+ * @remarks
245
+ * The SystemManager handles:
246
+ * - Registering systems with their component signature requirements
247
+ * - Maintaining the set of entities that match each system's signature
248
+ * - Automatically adding/removing entities from systems when signatures change
249
+ * - Cleaning up system entity sets when entities are destroyed
250
+ *
251
+ * When an entity's component signature changes (components added/removed),
252
+ * the SystemManager checks all registered systems and updates their entity sets.
253
+ * An entity is added to a system's set if its signature contains all components
254
+ * required by the system's signature.
255
+ *
256
+ * @category Managers
257
+ */
46
258
  export declare class SystemManager {
47
259
  private _systems;
48
260
  registerSystem(systemName: string, system: System): void;
@@ -50,6 +262,48 @@ export declare class SystemManager {
50
262
  entityDestroyed(entity: Entity): void;
51
263
  entitySignatureChanged(entity: Entity, signature: ComponentSignature): void;
52
264
  }
265
+ /**
266
+ * Main ECS coordinator that manages entities, components, and systems.
267
+ *
268
+ * @remarks
269
+ * The Coordinator is the central API for working with the ECS. It provides a unified
270
+ * interface for:
271
+ * - Creating and destroying entities
272
+ * - Registering and managing components
273
+ * - Registering and configuring systems
274
+ * - Querying component data
275
+ *
276
+ * The Coordinator automatically keeps entity signatures up-to-date and notifies
277
+ * systems when entities match their component requirements.
278
+ *
279
+ * @example
280
+ * Complete ECS workflow
281
+ * ```typescript
282
+ * const ecs = new Coordinator();
283
+ *
284
+ * // Setup
285
+ * ecs.registerComponent<Position>('Position');
286
+ * ecs.registerComponent<Velocity>('Velocity');
287
+ *
288
+ * // Create entity
289
+ * const entity = ecs.createEntity();
290
+ * ecs.addComponentToEntity('Position', entity, { x: 0, y: 0 });
291
+ * ecs.addComponentToEntity('Velocity', entity, { x: 1, y: 0 });
292
+ *
293
+ * // Update
294
+ * const pos = ecs.getComponentFromEntity<Position>('Position', entity);
295
+ * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);
296
+ * if (pos && vel) {
297
+ * pos.x += vel.x;
298
+ * pos.y += vel.y;
299
+ * }
300
+ *
301
+ * // Cleanup
302
+ * ecs.destroyEntity(entity);
303
+ * ```
304
+ *
305
+ * @category Core
306
+ */
53
307
  export declare class Coordinator {
54
308
  private _entityManager;
55
309
  private _componentManager;
package/index.js CHANGED
@@ -1,267 +1,3 @@
1
- // src/index.ts
2
- var MAX_ENTITIES = 1e4;
3
- var MAX_COMPONENTS = 32;
1
+ var O=1e4,W=32;class G{_availableEntities=[];_signatures=[];_maxEntities;_livingEntityCount=0;constructor(b=1e4){this._maxEntities=b;for(let j=0;j<this._maxEntities;j++)this._availableEntities.push(j),this._signatures.push(0)}createEntity(){if(this._livingEntityCount>=this._maxEntities)throw Error("Max entities reached");let b=this._availableEntities.shift();if(b===void 0)throw Error("No available entities");return this._signatures[b]=0,this._livingEntityCount++,b}destroyEntity(b){if(b>=this._maxEntities||b<0)throw Error("Invalid entity out of range");this._signatures[b]=0,this._availableEntities.push(b),this._livingEntityCount--}setSignature(b,j){if(b>=this._maxEntities||b<0)throw Error("Invalid entity out of range");this._signatures[b]=j}getSignature(b){if(b>=this._maxEntities||b<0)return null;return this._signatures[b]}}class H{denseArray;sparse;reverse;_count;constructor(b){this._count=0,this.denseArray=Array(b),this.sparse=Array(b),this.reverse=Array(b)}insertData(b,j){if(this.getData(b)!==null)this.removeData(b);if(this.sparse.length<b)this.sparse=[...this.sparse,...Array(b-this.sparse.length).fill(null)];this.denseArray[this._count]=j,this.reverse[this._count]=b,this.sparse[b]=this._count,this._count++}getData(b){if(this.sparse.length<=b)return null;let j=this.sparse[b];if(j===void 0||j===null||j>=this._count)return null;if(this.reverse[j]!==b)return null;return this.denseArray[j]}removeData(b){let j=this.sparse[b];if(j===void 0||j===null||j>=this._count)return;let z=this.reverse[this._count-1];if(z===null)return;this.denseArray[j]=this.denseArray[this._count-1],this.reverse[j]=z,this.sparse[z]=j,this.sparse[b]=null,this._count--}entityDestroyed(b){this.removeData(b)}}class J{_componentNameToTypeMap=new Map;_nextAvailableComponentType=0;registerComponent(b){if(this._componentNameToTypeMap.has(b))console.warn(`Component ${b} already registered; registering with the given new type`);let j=this._nextAvailableComponentType;this._componentNameToTypeMap.set(b,{componentType:j,componentArray:new H(1e4)}),this._nextAvailableComponentType++}getComponentType(b){return this._componentNameToTypeMap.get(b)?.componentType??null}addComponentToEntity(b,j,z){let B=this._getComponentArray(b);if(B===null)return;B.insertData(j,z)}removeComponentFromEntity(b,j){let z=this._getComponentArray(b);if(z===null)return;z.removeData(j)}getComponentFromEntity(b,j){let z=this._getComponentArray(b);if(z===null)return null;return z.getData(j)}entityDestroyed(b){for(let j of this._componentNameToTypeMap.values())j.componentArray.entityDestroyed(b)}_getComponentArray(b){let j=this._componentNameToTypeMap.get(b);if(j===void 0)return console.warn(`Component ${b} not registered`),null;return j.componentArray}}class K{_systems=new Map;registerSystem(b,j){if(this._systems.has(b)){console.warn(`System ${b} already registered`);return}this._systems.set(b,{system:j,signature:0})}setSignature(b,j){if(!this._systems.has(b)){console.warn(`System ${b} not registered`);return}let z=this._systems.get(b);if(z===void 0){console.warn(`System ${b} not registered`);return}z.signature=j}entityDestroyed(b){for(let j of this._systems.values())j.system.entities.delete(b)}entitySignatureChanged(b,j){for(let z of this._systems.values()){let B=z.signature;if((B&j)===B)z.system.entities.add(b);else z.system.entities.delete(b)}}}class L{_entityManager;_componentManager;_systemManager;constructor(){this._entityManager=new G,this._componentManager=new J,this._systemManager=new K}createEntity(){return this._entityManager.createEntity()}destroyEntity(b){this._entityManager.destroyEntity(b),this._componentManager.entityDestroyed(b),this._systemManager.entityDestroyed(b)}registerComponent(b){this._componentManager.registerComponent(b)}addComponentToEntity(b,j,z){this._componentManager.addComponentToEntity(b,j,z);let B=this._entityManager.getSignature(j);if(B===null)B=0;let D=this._componentManager.getComponentType(b);if(D===null){console.warn(`Component ${b} not registered`);return}B|=1<<D,this._entityManager.setSignature(j,B),this._systemManager.entitySignatureChanged(j,B)}removeComponentFromEntity(b,j){this._componentManager.removeComponentFromEntity(b,j);let z=this._entityManager.getSignature(j);if(z===null)z=0;let B=this._componentManager.getComponentType(b);if(B===null)return;z&=~(1<<B),this._entityManager.setSignature(j,z),this._systemManager.entitySignatureChanged(j,z)}getComponentFromEntity(b,j){return this._componentManager.getComponentFromEntity(b,j)}getComponentType(b){return this._componentManager.getComponentType(b)??null}registerSystem(b,j){this._systemManager.registerSystem(b,j)}setSystemSignature(b,j){this._systemManager.setSignature(b,j)}}export{K as SystemManager,O as MAX_ENTITIES,W as MAX_COMPONENTS,G as EntityManager,L as Coordinator,J as ComponentManager,H as ComponentArray};
4
2
 
5
- class EntityManager {
6
- _availableEntities = [];
7
- _signatures = [];
8
- _maxEntities;
9
- _livingEntityCount = 0;
10
- constructor(maxEntities = MAX_ENTITIES) {
11
- this._maxEntities = maxEntities;
12
- for (let i = 0;i < this._maxEntities; i++) {
13
- this._availableEntities.push(i);
14
- this._signatures.push(0);
15
- }
16
- }
17
- createEntity() {
18
- if (this._livingEntityCount >= this._maxEntities) {
19
- throw new Error("Max entities reached");
20
- }
21
- const entity = this._availableEntities.shift();
22
- if (entity === undefined) {
23
- throw new Error("No available entities");
24
- }
25
- this._signatures[entity] = 0;
26
- this._livingEntityCount++;
27
- return entity;
28
- }
29
- destroyEntity(entity) {
30
- if (entity >= this._maxEntities || entity < 0) {
31
- throw new Error("Invalid entity out of range");
32
- }
33
- this._signatures[entity] = 0;
34
- this._availableEntities.push(entity);
35
- this._livingEntityCount--;
36
- }
37
- setSignature(entity, signature) {
38
- if (entity >= this._maxEntities || entity < 0) {
39
- throw new Error("Invalid entity out of range");
40
- }
41
- this._signatures[entity] = signature;
42
- }
43
- getSignature(entity) {
44
- if (entity >= this._maxEntities || entity < 0) {
45
- return null;
46
- }
47
- return this._signatures[entity];
48
- }
49
- }
50
-
51
- class ComponentArray {
52
- denseArray;
53
- sparse;
54
- reverse;
55
- _count;
56
- constructor(maxEntities) {
57
- this._count = 0;
58
- this.denseArray = new Array(maxEntities);
59
- this.sparse = new Array(maxEntities);
60
- this.reverse = new Array(maxEntities);
61
- }
62
- insertData(entity, data) {
63
- if (this.getData(entity) !== null) {
64
- this.removeData(entity);
65
- }
66
- if (this.sparse.length < entity) {
67
- this.sparse = [...this.sparse, ...new Array(entity - this.sparse.length).fill(null)];
68
- }
69
- this.denseArray[this._count] = data;
70
- this.reverse[this._count] = entity;
71
- this.sparse[entity] = this._count;
72
- this._count++;
73
- }
74
- getData(entity) {
75
- if (this.sparse.length <= entity) {
76
- return null;
77
- }
78
- const denseIndex = this.sparse[entity];
79
- if (denseIndex === undefined || denseIndex === null || denseIndex >= this._count) {
80
- return null;
81
- }
82
- if (this.reverse[denseIndex] !== entity) {
83
- return null;
84
- }
85
- return this.denseArray[denseIndex];
86
- }
87
- removeData(entity) {
88
- const denseIndex = this.sparse[entity];
89
- if (denseIndex === undefined || denseIndex === null || denseIndex >= this._count) {
90
- return;
91
- }
92
- const lastEntity = this.reverse[this._count - 1];
93
- if (lastEntity === null) {
94
- return;
95
- }
96
- this.denseArray[denseIndex] = this.denseArray[this._count - 1];
97
- this.reverse[denseIndex] = lastEntity;
98
- this.sparse[lastEntity] = denseIndex;
99
- this.sparse[entity] = null;
100
- this._count--;
101
- }
102
- entityDestroyed(entity) {
103
- this.removeData(entity);
104
- }
105
- }
106
-
107
- class ComponentManager {
108
- _componentNameToTypeMap = new Map;
109
- _nextAvailableComponentType = 0;
110
- registerComponent(componentName) {
111
- if (this._componentNameToTypeMap.has(componentName)) {
112
- console.warn(`Component ${componentName} already registered; registering with the given new type`);
113
- }
114
- const componentType = this._nextAvailableComponentType;
115
- this._componentNameToTypeMap.set(componentName, { componentType, componentArray: new ComponentArray(MAX_ENTITIES) });
116
- this._nextAvailableComponentType++;
117
- }
118
- getComponentType(componentName) {
119
- return this._componentNameToTypeMap.get(componentName)?.componentType ?? null;
120
- }
121
- addComponentToEntity(componentName, entity, component) {
122
- const componentArray = this._getComponentArray(componentName);
123
- if (componentArray === null) {
124
- return;
125
- }
126
- componentArray.insertData(entity, component);
127
- }
128
- removeComponentFromEntity(componentName, entity) {
129
- const componentArray = this._getComponentArray(componentName);
130
- if (componentArray === null) {
131
- return;
132
- }
133
- componentArray.removeData(entity);
134
- }
135
- getComponentFromEntity(componentName, entity) {
136
- const componentArray = this._getComponentArray(componentName);
137
- if (componentArray === null) {
138
- return null;
139
- }
140
- return componentArray.getData(entity);
141
- }
142
- entityDestroyed(entity) {
143
- for (const component of this._componentNameToTypeMap.values()) {
144
- component.componentArray.entityDestroyed(entity);
145
- }
146
- }
147
- _getComponentArray(componentName) {
148
- const component = this._componentNameToTypeMap.get(componentName);
149
- if (component === undefined) {
150
- console.warn(`Component ${componentName} not registered`);
151
- return null;
152
- }
153
- return component.componentArray;
154
- }
155
- }
156
-
157
- class SystemManager {
158
- _systems = new Map;
159
- registerSystem(systemName, system) {
160
- if (this._systems.has(systemName)) {
161
- console.warn(`System ${systemName} already registered`);
162
- return;
163
- }
164
- this._systems.set(systemName, { system, signature: 0 });
165
- }
166
- setSignature(systemName, signature) {
167
- if (!this._systems.has(systemName)) {
168
- console.warn(`System ${systemName} not registered`);
169
- return;
170
- }
171
- const system = this._systems.get(systemName);
172
- if (system === undefined) {
173
- console.warn(`System ${systemName} not registered`);
174
- return;
175
- }
176
- system.signature = signature;
177
- }
178
- entityDestroyed(entity) {
179
- for (const system of this._systems.values()) {
180
- system.system.entities.delete(entity);
181
- }
182
- }
183
- entitySignatureChanged(entity, signature) {
184
- for (const system of this._systems.values()) {
185
- const systemSignature = system.signature;
186
- if ((systemSignature & signature) === systemSignature) {
187
- system.system.entities.add(entity);
188
- } else {
189
- system.system.entities.delete(entity);
190
- }
191
- }
192
- }
193
- }
194
-
195
- class Coordinator {
196
- _entityManager;
197
- _componentManager;
198
- _systemManager;
199
- constructor() {
200
- this._entityManager = new EntityManager;
201
- this._componentManager = new ComponentManager;
202
- this._systemManager = new SystemManager;
203
- }
204
- createEntity() {
205
- return this._entityManager.createEntity();
206
- }
207
- destroyEntity(entity) {
208
- this._entityManager.destroyEntity(entity);
209
- this._componentManager.entityDestroyed(entity);
210
- this._systemManager.entityDestroyed(entity);
211
- }
212
- registerComponent(componentName) {
213
- this._componentManager.registerComponent(componentName);
214
- }
215
- addComponentToEntity(componentName, entity, component) {
216
- this._componentManager.addComponentToEntity(componentName, entity, component);
217
- let signature = this._entityManager.getSignature(entity);
218
- if (signature === null) {
219
- signature = 0;
220
- }
221
- const componentType = this._componentManager.getComponentType(componentName);
222
- if (componentType === null) {
223
- console.warn(`Component ${componentName} not registered`);
224
- return;
225
- }
226
- signature |= 1 << componentType;
227
- this._entityManager.setSignature(entity, signature);
228
- this._systemManager.entitySignatureChanged(entity, signature);
229
- }
230
- removeComponentFromEntity(componentName, entity) {
231
- this._componentManager.removeComponentFromEntity(componentName, entity);
232
- let signature = this._entityManager.getSignature(entity);
233
- if (signature === null) {
234
- signature = 0;
235
- }
236
- const componentType = this._componentManager.getComponentType(componentName);
237
- if (componentType === null) {
238
- return;
239
- }
240
- signature &= ~(1 << componentType);
241
- this._entityManager.setSignature(entity, signature);
242
- this._systemManager.entitySignatureChanged(entity, signature);
243
- }
244
- getComponentFromEntity(componentName, entity) {
245
- return this._componentManager.getComponentFromEntity(componentName, entity);
246
- }
247
- getComponentType(componentName) {
248
- return this._componentManager.getComponentType(componentName) ?? null;
249
- }
250
- registerSystem(systemName, system) {
251
- this._systemManager.registerSystem(systemName, system);
252
- }
253
- setSystemSignature(systemName, signature) {
254
- this._systemManager.setSignature(systemName, signature);
255
- }
256
- }
257
- export {
258
- SystemManager,
259
- MAX_ENTITIES,
260
- MAX_COMPONENTS,
261
- EntityManager,
262
- Coordinator,
263
- ComponentManager,
264
- ComponentArray
265
- };
266
-
267
- //# debugId=840788BF2D72B20064756E2164756E21
3
+ //# debugId=983008DE2E282BA464756E2164756E21
package/index.js.map CHANGED
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
4
  "sourcesContent": [
5
- "/** This is a direct port of the tutorial from https://austinmorlan.com/posts/entity_component_system/ with slight modifications */\n\nexport const MAX_ENTITIES = 10000;\nexport const MAX_COMPONENTS = 32;\n\nexport type ComponentSignature = number;\nexport type ComponentType = number;\n\nexport type Entity = number;\n\n\nexport class EntityManager {\n\n private _availableEntities: Entity[] = [];\n private _signatures: ComponentSignature[] = [];\n private _maxEntities: number;\n\n private _livingEntityCount = 0;\n\n constructor(maxEntities: number = MAX_ENTITIES) {\n this._maxEntities = maxEntities;\n for (let i = 0; i < this._maxEntities; i++) {\n this._availableEntities.push(i);\n this._signatures.push(0);\n }\n }\n\n createEntity(): Entity {\n if(this._livingEntityCount >= this._maxEntities) {\n throw new Error('Max entities reached');\n }\n const entity = this._availableEntities.shift();\n if(entity === undefined) {\n throw new Error('No available entities');\n }\n this._signatures[entity] = 0;\n this._livingEntityCount++;\n return entity;\n }\n\n destroyEntity(entity: Entity): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = 0;\n this._availableEntities.push(entity);\n this._livingEntityCount--;\n }\n\n setSignature(entity: Entity, signature: ComponentSignature): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = signature;\n }\n\n getSignature(entity: Entity): ComponentSignature | null {\n if(entity >= this._maxEntities || entity < 0) {\n return null;\n }\n return this._signatures[entity];\n }\n}\n\ntype Tuple<T, N extends number> = N extends N\n ? number extends N\n ? T[]\n : _TupleOf<T, N, []>\n : never;\n\ntype _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N\n ? R\n : _TupleOf<T, N, [...R, T]>;\n\n// Usage\n\nexport interface CArray {\n entityDestroyed(entity: Entity): void;\n}\n\nexport class ComponentArray<T> implements CArray {\n\n private denseArray: T[]; // packed array of data\n private sparse: (Entity | null)[]; // maps entity to index in dense array\n private reverse: (Entity | null)[]; // maps index in dense array to entity\n private _count: number;\n\n constructor(maxEntities: number) {\n this._count = 0;\n this.denseArray = new Array(maxEntities);\n this.sparse = new Array(maxEntities);\n this.reverse = new Array(maxEntities);\n }\n\n insertData(entity: Entity, data: T): void {\n if(this.getData(entity) !== null) {\n this.removeData(entity);\n }\n if(this.sparse.length < entity){\n // resize the array for the new entity but normally this should not happen\n this.sparse = [...this.sparse, ...new Array(entity - this.sparse.length).fill(null)];\n }\n\n this.denseArray[this._count] = data;\n this.reverse[this._count] = entity;\n this.sparse[entity] = this._count;\n this._count++;\n }\n\n getData(entity: Entity): T | null {\n if(this.sparse.length <= entity){\n return null;\n }\n\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return null;\n }\n\n if(this.reverse[denseIndex] !== entity) {\n return null;\n }\n\n return this.denseArray[denseIndex];\n }\n\n removeData(entity: Entity): void {\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return;\n }\n\n const lastEntity = this.reverse[this._count - 1];\n\n if(lastEntity === null) {\n return;\n }\n\n this.denseArray[denseIndex] = this.denseArray[this._count - 1];\n this.reverse[denseIndex] = lastEntity;\n this.sparse[lastEntity] = denseIndex;\n this.sparse[entity] = null;\n\n this._count--;\n }\n\n entityDestroyed(entity: Entity): void {\n this.removeData(entity);\n }\n}\n\nexport class ComponentManager {\n\n private _componentNameToTypeMap: Map<string, {componentType: ComponentType, componentArray: CArray}> = new Map();\n private _nextAvailableComponentType: ComponentType = 0;\n \n registerComponent<T>(componentName: string){\n if(this._componentNameToTypeMap.has(componentName)) {\n console.warn(`Component ${componentName} already registered; registering with the given new type`);\n }\n const componentType = this._nextAvailableComponentType;\n this._componentNameToTypeMap.set(componentName, {componentType, componentArray: new ComponentArray<T>(MAX_ENTITIES)});\n this._nextAvailableComponentType++;\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentNameToTypeMap.get(componentName)?.componentType ?? null;\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.insertData(entity, component);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.removeData(entity);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return null;\n }\n return componentArray.getData(entity);\n }\n\n entityDestroyed(entity: Entity){\n for(const component of this._componentNameToTypeMap.values()){\n component.componentArray.entityDestroyed(entity);\n }\n }\n\n private _getComponentArray<T>(componentName: string): ComponentArray<T> | null {\n const component = this._componentNameToTypeMap.get(componentName);\n if(component === undefined) {\n console.warn(`Component ${componentName} not registered`);\n return null;\n }\n return component.componentArray as ComponentArray<T>;\n }\n\n}\n\nexport interface System {\n entities: Set<Entity>;\n}\n\nexport class SystemManager {\n private _systems: Map<string, {system: System, signature: ComponentSignature}> = new Map();\n\n registerSystem(systemName: string, system: System){\n if(this._systems.has(systemName)) {\n console.warn(`System ${systemName} already registered`);\n return;\n }\n this._systems.set(systemName, {system, signature: 0});\n }\n\n setSignature(systemName: string, signature: ComponentSignature){\n if(!this._systems.has(systemName)) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n const system = this._systems.get(systemName);\n if(system === undefined) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n system.signature = signature;\n }\n\n entityDestroyed(entity: Entity){\n for(const system of this._systems.values()){\n system.system.entities.delete(entity);\n }\n }\n\n entitySignatureChanged(entity: Entity, signature: ComponentSignature){\n for(const system of this._systems.values()){\n const systemSignature = system.signature;\n if((systemSignature & signature) === systemSignature){\n system.system.entities.add(entity);\n } else {\n system.system.entities.delete(entity);\n }\n }\n }\n}\n\nexport class Coordinator {\n private _entityManager: EntityManager;\n private _componentManager: ComponentManager;\n private _systemManager: SystemManager;\n\n constructor(){\n this._entityManager = new EntityManager();\n this._componentManager = new ComponentManager();\n this._systemManager = new SystemManager();\n }\n\n createEntity(): Entity {\n return this._entityManager.createEntity();\n }\n\n destroyEntity(entity: Entity): void {\n this._entityManager.destroyEntity(entity);\n this._componentManager.entityDestroyed(entity);\n this._systemManager.entityDestroyed(entity);\n }\n\n registerComponent<T>(componentName: string): void {\n this._componentManager.registerComponent<T>(componentName);\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T): void {\n this._componentManager.addComponentToEntity<T>(componentName, entity, component);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n console.warn(`Component ${componentName} not registered`);\n return;\n }\n signature |= 1 << componentType;\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity): void {\n this._componentManager.removeComponentFromEntity<T>(componentName, entity);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n return;\n }\n signature &= ~(1 << componentType);\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n return this._componentManager.getComponentFromEntity<T>(componentName, entity);\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentManager.getComponentType(componentName) ?? null;\n }\n\n registerSystem(systemName: string, system: System): void {\n this._systemManager.registerSystem(systemName, system);\n }\n\n setSystemSignature(systemName: string, signature: ComponentSignature): void {\n this._systemManager.setSignature(systemName, signature);\n }\n}\n"
5
+ "/**\n * @packageDocumentation\n * Entity Component System (ECS) implementation for TypeScript.\n *\n * @remarks\n * The `@ue-too/ecs` package provides a high-performance Entity Component System architecture\n * based on the tutorial from https://austinmorlan.com/posts/entity_component_system/\n *\n * ## ECS Architecture\n *\n * - **Entities**: Unique identifiers (numbers) representing game objects\n * - **Components**: Data containers attached to entities\n * - **Systems**: Logic that operates on entities with specific component combinations\n * - **Signatures**: Bit flags indicating which components an entity has\n *\n * ## Key Features\n *\n * - **Efficient Storage**: Component arrays using sparse-set data structure\n * - **Fast Iteration**: Dense packing for cache-friendly iteration\n * - **Type-Safe**: TypeScript generics for component type safety\n * - **Signature Matching**: Automatic system updates when entity signatures change\n * - **Pooling**: Entity ID recycling for memory efficiency\n *\n * ## Core Classes\n *\n * - {@link Coordinator}: Main ECS coordinator managing all subsystems\n * - {@link EntityManager}: Creates and destroys entities\n * - {@link ComponentManager}: Registers components and manages component data\n * - {@link SystemManager}: Registers systems and maintains entity sets\n * - {@link ComponentArray}: Efficient sparse-set storage for component data\n *\n * @example\n * Basic ECS usage\n * ```typescript\n * import { Coordinator } from '@ue-too/ecs';\n *\n * // Define component types\n * type Position = { x: number; y: number };\n * type Velocity = { x: number; y: number };\n *\n * // Create coordinator\n * const coordinator = new Coordinator();\n *\n * // Register components\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create entity with components\n * const entity = coordinator.createEntity();\n * coordinator.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * coordinator.addComponentToEntity('Velocity', entity, { x: 1, y: 1 });\n *\n * // Query components\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity);\n * console.log('Position:', pos);\n * ```\n *\n * @example\n * System registration\n * ```typescript\n * import { Coordinator, System } from '@ue-too/ecs';\n *\n * const coordinator = new Coordinator();\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create a movement system\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * coordinator.registerSystem('Movement', movementSystem);\n *\n * // Set signature (entities with Position AND Velocity)\n * const posType = coordinator.getComponentType('Position')!;\n * const velType = coordinator.getComponentType('Velocity')!;\n * const signature = (1 << posType) | (1 << velType);\n * coordinator.setSystemSignature('Movement', signature);\n *\n * // Update loop\n * function update(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity)!;\n * const vel = coordinator.getComponentFromEntity<Velocity>('Velocity', entity)!;\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * });\n * }\n * ```\n *\n * @see {@link Coordinator} for the main ECS API\n */\n\n/**\n * Maximum number of entities that can exist simultaneously.\n * @category Configuration\n */\nexport const MAX_ENTITIES = 10000;\n\n/**\n * Maximum number of component types that can be registered.\n * @category Configuration\n */\nexport const MAX_COMPONENTS = 32;\n\n/**\n * Component signature type (bit field indicating which components an entity has).\n * @category Types\n */\nexport type ComponentSignature = number;\n\n/**\n * Component type identifier.\n * @category Types\n */\nexport type ComponentType = number;\n\n/**\n * Entity identifier (unique number).\n * @category Types\n */\nexport type Entity = number;\n\n/**\n * Manages entity lifecycle and signatures.\n *\n * @remarks\n * The EntityManager handles:\n * - Creating new entities (recycling IDs from a pool)\n * - Destroying entities (returning IDs to the pool)\n * - Storing and updating component signatures for each entity\n *\n * Entities are represented as simple numbers (IDs) and the manager maintains\n * a signature (bit field) for each entity indicating which components it has.\n *\n * @category Managers\n */\nexport class EntityManager {\n\n private _availableEntities: Entity[] = [];\n private _signatures: ComponentSignature[] = [];\n private _maxEntities: number;\n\n private _livingEntityCount = 0;\n\n constructor(maxEntities: number = MAX_ENTITIES) {\n this._maxEntities = maxEntities;\n for (let i = 0; i < this._maxEntities; i++) {\n this._availableEntities.push(i);\n this._signatures.push(0);\n }\n }\n\n createEntity(): Entity {\n if(this._livingEntityCount >= this._maxEntities) {\n throw new Error('Max entities reached');\n }\n const entity = this._availableEntities.shift();\n if(entity === undefined) {\n throw new Error('No available entities');\n }\n this._signatures[entity] = 0;\n this._livingEntityCount++;\n return entity;\n }\n\n destroyEntity(entity: Entity): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = 0;\n this._availableEntities.push(entity);\n this._livingEntityCount--;\n }\n\n setSignature(entity: Entity, signature: ComponentSignature): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = signature;\n }\n\n getSignature(entity: Entity): ComponentSignature | null {\n if(entity >= this._maxEntities || entity < 0) {\n return null;\n }\n return this._signatures[entity];\n }\n}\n\ntype Tuple<T, N extends number> = N extends N\n ? number extends N\n ? T[]\n : _TupleOf<T, N, []>\n : never;\n\ntype _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N\n ? R\n : _TupleOf<T, N, [...R, T]>;\n\n// Usage\n\n/**\n * Internal interface for component array lifecycle hooks.\n * @internal\n */\nexport interface CArray {\n entityDestroyed(entity: Entity): void;\n}\n\n/**\n * Efficient sparse-set data structure for storing component data.\n *\n * @remarks\n * ComponentArray uses a sparse-set implementation for O(1) insertion, deletion,\n * and lookup while maintaining dense packing for cache-efficient iteration.\n *\n * The sparse-set consists of:\n * - **Dense array**: Packed component data for iteration\n * - **Sparse array**: Maps entity ID to dense array index\n * - **Reverse array**: Maps dense array index back to entity ID\n *\n * This structure allows fast component access by entity ID and fast iteration\n * over all components without gaps.\n *\n * @typeParam T - The component data type\n *\n * @category Data Structures\n */\nexport class ComponentArray<T> implements CArray {\n\n private denseArray: T[]; // packed array of data\n private sparse: (Entity | null)[]; // maps entity to index in dense array\n private reverse: (Entity | null)[]; // maps index in dense array to entity\n private _count: number;\n\n constructor(maxEntities: number) {\n this._count = 0;\n this.denseArray = new Array(maxEntities);\n this.sparse = new Array(maxEntities);\n this.reverse = new Array(maxEntities);\n }\n\n insertData(entity: Entity, data: T): void {\n if(this.getData(entity) !== null) {\n this.removeData(entity);\n }\n if(this.sparse.length < entity){\n // resize the array for the new entity but normally this should not happen\n this.sparse = [...this.sparse, ...new Array(entity - this.sparse.length).fill(null)];\n }\n\n this.denseArray[this._count] = data;\n this.reverse[this._count] = entity;\n this.sparse[entity] = this._count;\n this._count++;\n }\n\n getData(entity: Entity): T | null {\n if(this.sparse.length <= entity){\n return null;\n }\n\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return null;\n }\n\n if(this.reverse[denseIndex] !== entity) {\n return null;\n }\n\n return this.denseArray[denseIndex];\n }\n\n removeData(entity: Entity): void {\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return;\n }\n\n const lastEntity = this.reverse[this._count - 1];\n\n if(lastEntity === null) {\n return;\n }\n\n this.denseArray[denseIndex] = this.denseArray[this._count - 1];\n this.reverse[denseIndex] = lastEntity;\n this.sparse[lastEntity] = denseIndex;\n this.sparse[entity] = null;\n\n this._count--;\n }\n\n entityDestroyed(entity: Entity): void {\n this.removeData(entity);\n }\n}\n\n/**\n * Manages component registration and component data storage.\n *\n * @remarks\n * The ComponentManager handles:\n * - Registering new component types and assigning unique type IDs\n * - Creating ComponentArray storage for each component type\n * - Adding, removing, and querying component data for entities\n * - Cleaning up component data when entities are destroyed\n *\n * Each component type gets a unique ID (0-31) and its own ComponentArray\n * for efficient storage and retrieval.\n *\n * @category Managers\n */\nexport class ComponentManager {\n\n private _componentNameToTypeMap: Map<string, {componentType: ComponentType, componentArray: CArray}> = new Map();\n private _nextAvailableComponentType: ComponentType = 0;\n \n registerComponent<T>(componentName: string){\n if(this._componentNameToTypeMap.has(componentName)) {\n console.warn(`Component ${componentName} already registered; registering with the given new type`);\n }\n const componentType = this._nextAvailableComponentType;\n this._componentNameToTypeMap.set(componentName, {componentType, componentArray: new ComponentArray<T>(MAX_ENTITIES)});\n this._nextAvailableComponentType++;\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentNameToTypeMap.get(componentName)?.componentType ?? null;\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.insertData(entity, component);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.removeData(entity);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return null;\n }\n return componentArray.getData(entity);\n }\n\n entityDestroyed(entity: Entity){\n for(const component of this._componentNameToTypeMap.values()){\n component.componentArray.entityDestroyed(entity);\n }\n }\n\n private _getComponentArray<T>(componentName: string): ComponentArray<T> | null {\n const component = this._componentNameToTypeMap.get(componentName);\n if(component === undefined) {\n console.warn(`Component ${componentName} not registered`);\n return null;\n }\n return component.componentArray as ComponentArray<T>;\n }\n\n}\n\n/**\n * System interface for processing entities with specific component combinations.\n *\n * @remarks\n * A System maintains a set of entities that match its component signature.\n * The ECS automatically updates this set when entities are created, destroyed,\n * or have their components modified.\n *\n * Systems contain only the logic for processing entities - the `entities` set\n * is automatically managed by the SystemManager.\n *\n * @example\n * ```typescript\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * // System logic (called in game loop)\n * function updateMovement(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = ecs.getComponentFromEntity<Position>('Position', entity);\n * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);\n * if (pos && vel) {\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * }\n * });\n * }\n * ```\n *\n * @category Types\n */\nexport interface System {\n entities: Set<Entity>;\n}\n\n/**\n * Manages system registration and entity-system matching.\n *\n * @remarks\n * The SystemManager handles:\n * - Registering systems with their component signature requirements\n * - Maintaining the set of entities that match each system's signature\n * - Automatically adding/removing entities from systems when signatures change\n * - Cleaning up system entity sets when entities are destroyed\n *\n * When an entity's component signature changes (components added/removed),\n * the SystemManager checks all registered systems and updates their entity sets.\n * An entity is added to a system's set if its signature contains all components\n * required by the system's signature.\n *\n * @category Managers\n */\nexport class SystemManager {\n private _systems: Map<string, {system: System, signature: ComponentSignature}> = new Map();\n\n registerSystem(systemName: string, system: System){\n if(this._systems.has(systemName)) {\n console.warn(`System ${systemName} already registered`);\n return;\n }\n this._systems.set(systemName, {system, signature: 0});\n }\n\n setSignature(systemName: string, signature: ComponentSignature){\n if(!this._systems.has(systemName)) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n const system = this._systems.get(systemName);\n if(system === undefined) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n system.signature = signature;\n }\n\n entityDestroyed(entity: Entity){\n for(const system of this._systems.values()){\n system.system.entities.delete(entity);\n }\n }\n\n entitySignatureChanged(entity: Entity, signature: ComponentSignature){\n for(const system of this._systems.values()){\n const systemSignature = system.signature;\n if((systemSignature & signature) === systemSignature){\n system.system.entities.add(entity);\n } else {\n system.system.entities.delete(entity);\n }\n }\n }\n}\n\n/**\n * Main ECS coordinator that manages entities, components, and systems.\n *\n * @remarks\n * The Coordinator is the central API for working with the ECS. It provides a unified\n * interface for:\n * - Creating and destroying entities\n * - Registering and managing components\n * - Registering and configuring systems\n * - Querying component data\n *\n * The Coordinator automatically keeps entity signatures up-to-date and notifies\n * systems when entities match their component requirements.\n *\n * @example\n * Complete ECS workflow\n * ```typescript\n * const ecs = new Coordinator();\n *\n * // Setup\n * ecs.registerComponent<Position>('Position');\n * ecs.registerComponent<Velocity>('Velocity');\n *\n * // Create entity\n * const entity = ecs.createEntity();\n * ecs.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * ecs.addComponentToEntity('Velocity', entity, { x: 1, y: 0 });\n *\n * // Update\n * const pos = ecs.getComponentFromEntity<Position>('Position', entity);\n * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);\n * if (pos && vel) {\n * pos.x += vel.x;\n * pos.y += vel.y;\n * }\n *\n * // Cleanup\n * ecs.destroyEntity(entity);\n * ```\n *\n * @category Core\n */\nexport class Coordinator {\n private _entityManager: EntityManager;\n private _componentManager: ComponentManager;\n private _systemManager: SystemManager;\n\n constructor(){\n this._entityManager = new EntityManager();\n this._componentManager = new ComponentManager();\n this._systemManager = new SystemManager();\n }\n\n createEntity(): Entity {\n return this._entityManager.createEntity();\n }\n\n destroyEntity(entity: Entity): void {\n this._entityManager.destroyEntity(entity);\n this._componentManager.entityDestroyed(entity);\n this._systemManager.entityDestroyed(entity);\n }\n\n registerComponent<T>(componentName: string): void {\n this._componentManager.registerComponent<T>(componentName);\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T): void {\n this._componentManager.addComponentToEntity<T>(componentName, entity, component);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n console.warn(`Component ${componentName} not registered`);\n return;\n }\n signature |= 1 << componentType;\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity): void {\n this._componentManager.removeComponentFromEntity<T>(componentName, entity);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n return;\n }\n signature &= ~(1 << componentType);\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n return this._componentManager.getComponentFromEntity<T>(componentName, entity);\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentManager.getComponentType(componentName) ?? null;\n }\n\n registerSystem(systemName: string, system: System): void {\n this._systemManager.registerSystem(systemName, system);\n }\n\n setSystemSignature(systemName: string, signature: ComponentSignature): void {\n this._systemManager.setSignature(systemName, signature);\n }\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "840788BF2D72B20064756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "983008DE2E282BA464756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@ue-too/ecs",
3
3
  "author": "niuee",
4
4
  "type": "module",
5
- "version": "0.9.5",
5
+ "version": "0.10.0",
6
6
  "description": "Entity Component System for uē-tôo",
7
7
  "license": "MIT",
8
8
  "repository": {