ecspresso 0.0.4 → 0.0.5
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 +221 -189
- package/dist/bundle.d.ts +1 -1
- package/dist/ecspresso.d.ts +8 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +6 -6
- package/dist/system-builder.d.ts +10 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,21 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
__Note: This is a VERY early work in progress. The documention is being autogenerated while this ECSpresso being iterated on.__
|
|
6
6
|
|
|
7
|
-
To install dependencies:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
bun install
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
To run tests:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
bun test
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# ECSpresso
|
|
21
|
-
|
|
22
7
|
A lightweight, type-safe Entity Component System (ECS) library for TypeScript applications and games.
|
|
23
8
|
|
|
24
9
|
## Overview
|
|
@@ -30,6 +15,7 @@ ECSpresso is a flexible and efficient Entity Component System implementation tha
|
|
|
30
15
|
- **Resource Management**: Global state management through a dedicated resource manager
|
|
31
16
|
- **Bundle System**: Modular and reusable collections of components, resources, and systems
|
|
32
17
|
- **Query System**: Efficient entity filtering based on component presence/absence
|
|
18
|
+
- **Flexible System Creation**: Create systems directly or through bundles
|
|
33
19
|
|
|
34
20
|
## Core Concepts
|
|
35
21
|
|
|
@@ -46,7 +32,7 @@ The ECS pattern separates data (Components) from behavior (Systems) through Enti
|
|
|
46
32
|
### Key Features
|
|
47
33
|
|
|
48
34
|
- Type-safe queries to filter entities based on component combinations
|
|
49
|
-
- Fluent builder API for creating systems
|
|
35
|
+
- Fluent builder API for creating systems directly or through bundles
|
|
50
36
|
- Event handling with lifecycle hooks for systems
|
|
51
37
|
- Resource management for global state
|
|
52
38
|
- Simplified system API - all system methods receive the ECSpresso instance
|
|
@@ -55,9 +41,9 @@ The ECS pattern separates data (Components) from behavior (Systems) through Enti
|
|
|
55
41
|
|
|
56
42
|
All system methods (process, onAttach, onDetach, and event handlers) receive the ECSpresso instance as a parameter, which provides:
|
|
57
43
|
|
|
58
|
-
- Access to entity management via `
|
|
59
|
-
- Access to resources via `
|
|
60
|
-
- Access to events via `
|
|
44
|
+
- Access to entity management via `ecspresso.entityManager`
|
|
45
|
+
- Access to resources via `ecspresso.resourceManager`
|
|
46
|
+
- Access to events via `ecspresso.eventBus`
|
|
61
47
|
|
|
62
48
|
This design simplifies the API and allows systems access to all ECS functionality through a single reference. Benefits of this approach include:
|
|
63
49
|
|
|
@@ -81,63 +67,49 @@ npm install ecspresso
|
|
|
81
67
|
import ECSpresso, { Bundle } from 'ecspresso';
|
|
82
68
|
|
|
83
69
|
// Define your component types
|
|
84
|
-
interface
|
|
85
|
-
x: number;
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
interface Velocity {
|
|
90
|
-
dx: number;
|
|
91
|
-
dy: number;
|
|
70
|
+
interface MyComponents {
|
|
71
|
+
position: { x: number; y: number };
|
|
72
|
+
velocity: { dx: number; dy: number };
|
|
73
|
+
sprite: { url: string; width: number; height: number };
|
|
92
74
|
}
|
|
93
75
|
|
|
94
76
|
// Define your event types
|
|
95
|
-
interface
|
|
96
|
-
entityA: number;
|
|
97
|
-
|
|
77
|
+
interface MyEvents {
|
|
78
|
+
collision: { entityA: number; entityB: number };
|
|
79
|
+
playerSpawn: { id: number; position: { x: number; y: number } };
|
|
98
80
|
}
|
|
99
81
|
|
|
100
82
|
// Define your resource types
|
|
101
|
-
interface
|
|
102
|
-
score: number;
|
|
103
|
-
|
|
83
|
+
interface MyResources {
|
|
84
|
+
gameState: { score: number; level: number };
|
|
85
|
+
config: { debug: boolean; maxEntities: number };
|
|
104
86
|
}
|
|
105
87
|
|
|
106
88
|
// Create an ECS instance with your types
|
|
107
|
-
const
|
|
108
|
-
{ position: Position; velocity: Velocity },
|
|
109
|
-
{ collision: CollisionEvent },
|
|
110
|
-
{ gameState: GameState }
|
|
111
|
-
>();
|
|
89
|
+
const world = new ECSpresso<MyComponents, MyEvents, MyResources>();
|
|
112
90
|
|
|
113
91
|
// Add resources
|
|
114
|
-
|
|
92
|
+
world.addResource('gameState', { score: 0, level: 1 });
|
|
93
|
+
world.addResource('config', { debug: true, maxEntities: 1000 });
|
|
115
94
|
|
|
116
95
|
// Create an entity
|
|
117
|
-
const entity =
|
|
96
|
+
const entity = world.entityManager.createEntity();
|
|
118
97
|
|
|
119
98
|
// Add components to the entity
|
|
120
|
-
|
|
121
|
-
|
|
99
|
+
world.entityManager.addComponent(entity.id, 'position', { x: 0, y: 0 });
|
|
100
|
+
world.entityManager.addComponent(entity.id, 'velocity', { dx: 1, dy: 2 });
|
|
122
101
|
|
|
123
102
|
// Run the simulation
|
|
124
|
-
|
|
103
|
+
world.update(16.67); // Pass delta time in ms
|
|
125
104
|
```
|
|
126
105
|
|
|
127
|
-
### Creating Systems
|
|
106
|
+
### Creating Systems Directly
|
|
128
107
|
|
|
129
|
-
|
|
108
|
+
ECSpresso allows you to create systems directly on the ECSpresso instance:
|
|
130
109
|
|
|
131
110
|
```typescript
|
|
132
|
-
// Create a
|
|
133
|
-
|
|
134
|
-
{ position: Position; velocity: Velocity },
|
|
135
|
-
{ collision: CollisionEvent },
|
|
136
|
-
{ gameState: GameState }
|
|
137
|
-
>('gameBundle');
|
|
138
|
-
|
|
139
|
-
// Create a movement system within the bundle
|
|
140
|
-
const movementSystem = gameBundle
|
|
111
|
+
// Create a movement system directly on the ECSpresso instance
|
|
112
|
+
world
|
|
141
113
|
.addSystem('movement')
|
|
142
114
|
.addQuery('movable', {
|
|
143
115
|
with: ['position', 'velocity']
|
|
@@ -149,193 +121,253 @@ const movementSystem = gameBundle
|
|
|
149
121
|
position.x += velocity.dx * (deltaTime / 1000);
|
|
150
122
|
position.y += velocity.dy * (deltaTime / 1000);
|
|
151
123
|
}
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
// Install the bundle to add the system to the ECS
|
|
155
|
-
ecs.install(gameBundle);
|
|
124
|
+
})
|
|
125
|
+
.build(); // Important: Call build() to finalize the system
|
|
156
126
|
```
|
|
157
127
|
|
|
158
|
-
|
|
128
|
+
The `build()` method finalizes the system and registers it with the ECSpresso instance. Any lifecycle hooks like `onAttach` will be called immediately when the system is built.
|
|
159
129
|
|
|
160
|
-
|
|
161
|
-
// Create a physics bundle
|
|
162
|
-
const physicsBundle = new Bundle<
|
|
163
|
-
{ position: Position; velocity: Velocity },
|
|
164
|
-
{ collision: CollisionEvent },
|
|
165
|
-
{}
|
|
166
|
-
>('physics');
|
|
130
|
+
### System Lifecycle Hooks
|
|
167
131
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
132
|
+
You can add lifecycle hooks to systems that will be called when the system is attached or detached:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Create a rendering system with lifecycle hooks
|
|
136
|
+
world
|
|
137
|
+
.addSystem('renderer')
|
|
138
|
+
.addQuery('sprites', {
|
|
139
|
+
with: ['position', 'sprite']
|
|
140
|
+
})
|
|
141
|
+
.setOnAttach((ecs) => {
|
|
142
|
+
console.log('Render system attached');
|
|
143
|
+
// Initialize rendering resources
|
|
144
|
+
})
|
|
145
|
+
.setOnDetach((ecs) => {
|
|
146
|
+
console.log('Render system detached');
|
|
147
|
+
// Clean up rendering resources
|
|
173
148
|
})
|
|
174
149
|
.setProcess((queries, deltaTime, ecs) => {
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
ecs.install(physicsBundle);
|
|
150
|
+
// Render all sprites at their positions
|
|
151
|
+
for (const entity of queries.sprites) {
|
|
152
|
+
const { position, sprite } = entity.components;
|
|
153
|
+
// Render sprite at position
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
.build();
|
|
183
157
|
```
|
|
184
158
|
|
|
185
159
|
### Event Handling
|
|
186
160
|
|
|
187
|
-
|
|
188
|
-
// Create a bundle for the score system
|
|
189
|
-
const gameUIBundle = new Bundle<
|
|
190
|
-
{ position: Position; velocity: Velocity },
|
|
191
|
-
{ collision: CollisionEvent },
|
|
192
|
-
{ gameState: GameState }
|
|
193
|
-
>('gameUI');
|
|
161
|
+
Systems can handle events emitted by other systems:
|
|
194
162
|
|
|
163
|
+
```typescript
|
|
195
164
|
// Create a system that handles collision events
|
|
196
|
-
|
|
165
|
+
world
|
|
197
166
|
.addSystem('score')
|
|
198
167
|
.setEventHandlers({
|
|
199
168
|
collision: {
|
|
200
169
|
handler: (event, ecs) => {
|
|
201
170
|
// Handle collision event
|
|
202
|
-
const gameState = ecs.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
171
|
+
const gameState = ecs.getResourceOrThrow('gameState');
|
|
172
|
+
gameState.score += 10;
|
|
173
|
+
|
|
174
|
+
console.log(`Score: ${gameState.score}`);
|
|
206
175
|
}
|
|
207
176
|
}
|
|
177
|
+
})
|
|
178
|
+
.build();
|
|
179
|
+
|
|
180
|
+
// Emit an event from another system
|
|
181
|
+
world.eventBus.publish('collision', { entityA: entity.id, entityB: 2 });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Using Bundles for System Organization
|
|
185
|
+
|
|
186
|
+
Bundles allow you to group related systems, resources, and components:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Create a physics bundle
|
|
190
|
+
const physicsBundle = new Bundle<MyComponents, MyEvents, MyResources>('physics');
|
|
191
|
+
|
|
192
|
+
// Add a system to the bundle
|
|
193
|
+
const collisionSystem = physicsBundle
|
|
194
|
+
.addSystem('collision')
|
|
195
|
+
.addQuery('collidable', {
|
|
196
|
+
with: ['position']
|
|
197
|
+
})
|
|
198
|
+
.setProcess((queries, deltaTime, ecs) => {
|
|
199
|
+
// Check for collisions between entities
|
|
200
|
+
for (const entity of queries.collidable) {
|
|
201
|
+
// Collision detection logic
|
|
202
|
+
// ...
|
|
203
|
+
|
|
204
|
+
// Emit collision events when detected
|
|
205
|
+
ecs.eventBus.publish('collision', {
|
|
206
|
+
entityA: entity.id,
|
|
207
|
+
entityB: otherEntity.id
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Access the bundle for chaining
|
|
213
|
+
physicsBundle
|
|
214
|
+
.addSystem('movement')
|
|
215
|
+
.addQuery('movable', {
|
|
216
|
+
with: ['position', 'velocity']
|
|
217
|
+
})
|
|
218
|
+
.setProcess((queries, deltaTime, ecs) => {
|
|
219
|
+
for (const entity of queries.movable) {
|
|
220
|
+
const { position, velocity } = entity.components;
|
|
221
|
+
position.x += velocity.dx * (deltaTime / 1000);
|
|
222
|
+
position.y += velocity.dy * (deltaTime / 1000);
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
.bundle // Access bundle for chaining to add another system
|
|
226
|
+
.addSystem('friction')
|
|
227
|
+
.addQuery('moving', {
|
|
228
|
+
with: ['velocity']
|
|
229
|
+
})
|
|
230
|
+
.setProcess((queries, deltaTime, ecs) => {
|
|
231
|
+
for (const entity of queries.moving) {
|
|
232
|
+
const { velocity } = entity.components;
|
|
233
|
+
// Apply friction
|
|
234
|
+
velocity.dx *= 0.99;
|
|
235
|
+
velocity.dy *= 0.99;
|
|
236
|
+
}
|
|
208
237
|
});
|
|
209
238
|
|
|
210
|
-
//
|
|
211
|
-
|
|
239
|
+
// Install the bundle to add all systems to the ECSpresso instance
|
|
240
|
+
world.install(physicsBundle);
|
|
212
241
|
```
|
|
213
242
|
|
|
214
|
-
|
|
243
|
+
With bundles, you don't need to call `build()` on the systems. The systems are built when the bundle is installed.
|
|
244
|
+
|
|
245
|
+
### System Chaining with ECSpresso
|
|
246
|
+
|
|
247
|
+
When adding systems directly to ECSpresso, you can access the ECSpresso instance for chaining:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Create a system and access the ECSpresso instance for chaining
|
|
251
|
+
world
|
|
252
|
+
.addSystem('playerSystem')
|
|
253
|
+
.addQuery('players', {
|
|
254
|
+
with: ['position', 'velocity']
|
|
255
|
+
})
|
|
256
|
+
.setProcess((queries, deltaTime, ecs) => {
|
|
257
|
+
// Process player entities
|
|
258
|
+
})
|
|
259
|
+
.build()
|
|
260
|
+
.ecspresso // Access the ECSpresso instance after building
|
|
261
|
+
.addSystem('enemySystem')
|
|
262
|
+
.addQuery('enemies', {
|
|
263
|
+
with: ['position', 'velocity']
|
|
264
|
+
})
|
|
265
|
+
.setProcess((queries, deltaTime, ecs) => {
|
|
266
|
+
// Process enemy entities
|
|
267
|
+
})
|
|
268
|
+
.build();
|
|
269
|
+
```
|
|
215
270
|
|
|
216
271
|
### Merging Bundles
|
|
217
272
|
|
|
273
|
+
For larger applications, you can organize systems into multiple bundles and merge them:
|
|
274
|
+
|
|
218
275
|
```typescript
|
|
219
276
|
import { mergeBundles } from 'ecspresso';
|
|
220
277
|
|
|
221
|
-
//
|
|
278
|
+
// Create individual feature bundles
|
|
279
|
+
const physicsBundle = new Bundle<MyComponents, MyEvents, MyResources>('physics');
|
|
280
|
+
const renderBundle = new Bundle<MyComponents, MyEvents, MyResources>('render');
|
|
281
|
+
const aiBundle = new Bundle<MyComponents, MyEvents, MyResources>('ai');
|
|
282
|
+
|
|
283
|
+
// Add systems to each bundle
|
|
284
|
+
// ...
|
|
285
|
+
|
|
286
|
+
// Merge bundles into a game bundle
|
|
222
287
|
const gameBundle = mergeBundles(
|
|
223
288
|
'game',
|
|
224
289
|
physicsBundle,
|
|
225
290
|
renderBundle,
|
|
226
|
-
|
|
291
|
+
aiBundle
|
|
227
292
|
);
|
|
228
293
|
|
|
229
294
|
// Install the merged bundle
|
|
230
|
-
|
|
295
|
+
world.install(gameBundle);
|
|
231
296
|
```
|
|
232
297
|
|
|
233
|
-
|
|
298
|
+
## Advanced Features
|
|
299
|
+
|
|
300
|
+
### Removing Systems
|
|
301
|
+
|
|
302
|
+
You can remove systems by their label:
|
|
234
303
|
|
|
235
304
|
```typescript
|
|
236
|
-
//
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// Create a system with lifecycle hooks
|
|
244
|
-
renderBundle
|
|
245
|
-
.addSystem('render')
|
|
246
|
-
.setOnAttach((ecs) => {
|
|
247
|
-
// Initialize rendering resources
|
|
248
|
-
console.log('Render system attached');
|
|
249
|
-
// You could initialize renderer resources here
|
|
250
|
-
ecs.addResource('renderer', new Renderer());
|
|
251
|
-
})
|
|
252
|
-
.setOnDetach((ecs) => {
|
|
253
|
-
// Clean up rendering resources
|
|
254
|
-
console.log('Render system detached');
|
|
255
|
-
// You could clean up renderer resources here
|
|
256
|
-
const renderer = ecs.getResource('renderer');
|
|
257
|
-
if (renderer) {
|
|
258
|
-
renderer.dispose();
|
|
259
|
-
}
|
|
260
|
-
});
|
|
305
|
+
// Remove a system
|
|
306
|
+
const removed = world.removeSystem('movement');
|
|
307
|
+
console.log(`System removed: ${removed}`); // true if system was found and removed
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
When a system is removed, its `onDetach` lifecycle hook is called if defined.
|
|
261
311
|
|
|
262
|
-
|
|
263
|
-
|
|
312
|
+
### Adding Resources through Bundles
|
|
313
|
+
|
|
314
|
+
Bundles can also contain resources:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Create a bundle with resources
|
|
318
|
+
const uiBundle = new Bundle<MyComponents, MyEvents, MyResources>('ui');
|
|
319
|
+
|
|
320
|
+
// Add resources to the bundle
|
|
321
|
+
uiBundle.addResource('uiState', {
|
|
322
|
+
menuOpen: false,
|
|
323
|
+
currentScreen: 'main'
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Add systems to the bundle
|
|
327
|
+
uiBundle
|
|
328
|
+
.addSystem('uiRenderer')
|
|
329
|
+
// ...
|
|
330
|
+
|
|
331
|
+
// Install the bundle to add both resources and systems
|
|
332
|
+
world.install(uiBundle);
|
|
264
333
|
```
|
|
265
334
|
|
|
266
|
-
|
|
335
|
+
## TypeScript Integration
|
|
267
336
|
|
|
268
|
-
|
|
337
|
+
ECSpresso is designed to provide strong type safety. The type parameters for components, events, and resources flow through the entire API, ensuring type correctness at compile time.
|
|
269
338
|
|
|
270
339
|
```typescript
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
health: Health;
|
|
277
|
-
stunned: StunnedEffect;
|
|
278
|
-
player: PlayerTag;
|
|
279
|
-
},
|
|
280
|
-
{ enemySpottedPlayer: EnemySpottedEvent },
|
|
281
|
-
{ gameConfig: GameConfig }
|
|
282
|
-
>('enemyAI');
|
|
283
|
-
|
|
284
|
-
// Create a complex AI system that needs access to multiple ECS features
|
|
285
|
-
aiBundle
|
|
286
|
-
.addSystem('enemyAI')
|
|
287
|
-
.addQuery('enemies', {
|
|
288
|
-
with: ['position', 'ai', 'health'],
|
|
289
|
-
without: ['stunned']
|
|
290
|
-
})
|
|
291
|
-
.addQuery('players', {
|
|
292
|
-
with: ['position', 'player']
|
|
340
|
+
// Properly typed queries and component access
|
|
341
|
+
world
|
|
342
|
+
.addSystem('typeSafeSystem')
|
|
343
|
+
.addQuery('entities', {
|
|
344
|
+
with: ['position', 'velocity']
|
|
293
345
|
})
|
|
294
346
|
.setProcess((queries, deltaTime, ecs) => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// Process each enemy
|
|
300
|
-
for (const enemy of queries.enemies) {
|
|
301
|
-
// Find the nearest player
|
|
302
|
-
let nearestPlayer = null;
|
|
303
|
-
let shortestDistance = Infinity;
|
|
304
|
-
|
|
305
|
-
for (const player of queries.players) {
|
|
306
|
-
const distance = calculateDistance(
|
|
307
|
-
enemy.components.position,
|
|
308
|
-
player.components.position
|
|
309
|
-
);
|
|
310
|
-
|
|
311
|
-
if (distance < shortestDistance) {
|
|
312
|
-
nearestPlayer = player;
|
|
313
|
-
shortestDistance = distance;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
347
|
+
for (const entity of queries.entities) {
|
|
348
|
+
// TypeScript knows these components exist and their types
|
|
349
|
+
const position = entity.components.position; // { x: number, y: number }
|
|
350
|
+
const velocity = entity.components.velocity; // { dx: number, dy: number }
|
|
316
351
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (enemy.components.ai.state !== 'chasing') {
|
|
320
|
-
enemy.components.ai.state = 'chasing';
|
|
321
|
-
|
|
322
|
-
// Emit event that enemy spotted player
|
|
323
|
-
ecs.eventBus.publish('enemySpottedPlayer', {
|
|
324
|
-
enemyId: enemy.id,
|
|
325
|
-
playerId: nearestPlayer.id
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Move enemy toward player
|
|
330
|
-
moveToward(enemy, nearestPlayer, deltaTime);
|
|
331
|
-
}
|
|
352
|
+
// This would cause a TypeScript error - sprite not guaranteed to exist
|
|
353
|
+
// const sprite = entity.components.sprite;
|
|
332
354
|
}
|
|
333
|
-
})
|
|
355
|
+
})
|
|
356
|
+
.build();
|
|
357
|
+
```
|
|
334
358
|
|
|
335
|
-
|
|
336
|
-
|
|
359
|
+
## Development
|
|
360
|
+
|
|
361
|
+
To install dependencies:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
bun install
|
|
337
365
|
```
|
|
338
366
|
|
|
339
|
-
|
|
367
|
+
To run tests:
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
bun test
|
|
371
|
+
```
|
|
340
372
|
|
|
341
373
|
This project was created using `bun init` in bun v1.2.4. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
package/dist/bundle.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export default class Bundle<ComponentTypes extends Record<string, any> = Record<
|
|
|
31
31
|
* Get all systems defined in this bundle
|
|
32
32
|
* Returns built System objects instead of SystemBuilders
|
|
33
33
|
*/
|
|
34
|
-
getSystems():
|
|
34
|
+
getSystems(): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[];
|
|
35
35
|
/**
|
|
36
36
|
* Get all resources defined in this bundle
|
|
37
37
|
*/
|
package/dist/ecspresso.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import EntityManager from "./entity-manager";
|
|
|
2
2
|
import EventBus from "./event-bus";
|
|
3
3
|
import ResourceManager from "./resource-manager";
|
|
4
4
|
import type Bundle from "./bundle";
|
|
5
|
+
import { SystemBuilder } from "./system-builder";
|
|
5
6
|
/**
|
|
6
7
|
* The main ECS (Entity Component System) container class
|
|
7
8
|
*
|
|
@@ -29,7 +30,7 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = Reco
|
|
|
29
30
|
* @param bundles One or more bundles to install
|
|
30
31
|
* @returns This ECSpresso instance for method chaining
|
|
31
32
|
*/
|
|
32
|
-
install<Bundles extends Array<Bundle<any, any, any
|
|
33
|
+
install<Bundles extends Array<Bundle<any, any, any> | null>>(...bundles: Bundles): this;
|
|
33
34
|
/**
|
|
34
35
|
* Remove a system by its label
|
|
35
36
|
* Calls the system's onDetach method with this ECSpresso instance if defined
|
|
@@ -74,4 +75,10 @@ export default class ECSpresso<ComponentTypes extends Record<string, any> = Reco
|
|
|
74
75
|
* Get all installed bundle IDs
|
|
75
76
|
*/
|
|
76
77
|
get installedBundles(): string[];
|
|
78
|
+
/**
|
|
79
|
+
* Add a system directly to this ECSpresso instance
|
|
80
|
+
* @param label Unique identifier for the system
|
|
81
|
+
* @returns A SystemBuilder instance for method chaining
|
|
82
|
+
*/
|
|
83
|
+
addSystem(label: string): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, {}>;
|
|
77
84
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class M{nextId=1;entities=new Map;componentIndices=new Map;createEntity(){let f=this.nextId++,g={id:f,components:{}};return this.entities.set(f,g),g}addComponent(f,g,j){let J=typeof f==="number"?this.entities.get(f):f;if(!J)throw new Error(`Entity ${f} does not exist`);if(J.components[g]=j,!this.componentIndices.has(g))this.componentIndices.set(g,new Set);return this.componentIndices.get(g)?.add(J.id),this}removeComponent(f,g){let j=this.entities.get(f);if(!j)throw new Error(`Entity ${f} does not exist`);delete j.components[g],this.componentIndices.get(g)?.delete(f)}getComponent(f,g){let j=this.entities.get(f);if(!j)throw new Error(`Entity ${f} does not exist`);return j.components[g]||null}getEntitiesWithComponents(f=[],g=[]){if(f.length===0){if(g.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((D)=>{return g.every((F)=>!(F in D.components))})}let j=f.reduce((D,F)=>{let K=this.componentIndices.get(F),V=K?K.size:0,X=this.componentIndices.get(D)?.size??1/0;return V<X?F:D},f[0]);return Array.from(this.componentIndices.get(j)||[]).filter((D)=>{let F=this.entities.get(D);return F&&f.every((K)=>(K in F.components))&&g.every((K)=>!(K in F.components))}).map((D)=>this.entities.get(D))}removeEntity(f){let g=this.entities.get(f);if(!g)return!1;for(let j of Object.keys(g.components))this.componentIndices.get(j)?.delete(f);return this.entities.delete(f)}getEntity(f){return this.entities.get(f)}}class P{handlers=new Map;subscribe(f,g){return this.addHandler(f,g,!1)}once(f,g){return this.addHandler(f,g,!0)}addHandler(f,g,j){if(!this.handlers.has(f))this.handlers.set(f,[]);let J={callback:g,once:j};return this.handlers.get(f).push(J),()=>{let D=this.handlers.get(f);if(D){let F=D.indexOf(J);if(F!==-1)D.splice(F,1)}}}publish(f,g=void 0){let j=this.handlers.get(f);if(!j)return;let J=[...j],D=[];for(let F of J)if(F.callback(g),F.once)D.push(F);if(D.length>0)for(let F of D){let K=j.indexOf(F);if(K!==-1)j.splice(K,1)}}clear(){this.handlers.clear()}clearEvent(f){this.handlers.delete(f)}}class Q{resources=new Map;add(f,g){return this.resources.set(f,g),this}get(f){let g=this.resources.get(f);if(g===void 0)throw new Error(`Resource ${String(f)} not found`);return g}getOptional(f){return this.resources.get(f)}has(f){return this.resources.has(f)}remove(f){return this.resources.delete(f)}getKeys(){return Array.from(this.resources.keys())}}class L{_label;_ecspresso;_bundle;queries={};processFunction;attachFunction;detachFunction;eventHandlers;constructor(f,g=null,j=null){this._label=f;this._ecspresso=g;this._bundle=j}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}addQuery(f,g){let j=this;return j.queries={...this.queries,[f]:g},j}setProcess(f){return this.processFunction=f,this}setOnAttach(f){return this.attachFunction=f,this}setOnDetach(f){return this.detachFunction=f,this}setEventHandlers(f){return this.eventHandlers=f,this}build(){let f={label:this._label,entityQueries:this.queries};if(this.processFunction)f.process=this.processFunction;if(this.attachFunction)f.onAttach=this.attachFunction;if(this.detachFunction)f.onDetach=this.detachFunction;if(this.eventHandlers)f.eventHandlers=this.eventHandlers;if(this._ecspresso&&!this._bundle){let g=f;if(this._ecspresso._systems.push(g),g.onAttach)g.onAttach(this._ecspresso);if(g.eventHandlers)for(let j in g.eventHandlers){let J=g.eventHandlers[j];if(J?.handler){let D=(F)=>{J.handler(F,this._ecspresso)};this._ecspresso.eventBus.subscribe(j,D)}}}return this}}var Y="0.0.5";class W{static VERSION=Y;_entityManager;_systems=[];_eventBus;_resourceManager;_installedBundles=new Set;constructor(){this._entityManager=new M,this._eventBus=new P,this._resourceManager=new Q}install(...f){for(let g of f){if(!g)return this;if(this._installedBundles.has(g.id)){console.warn(`Bundle ${g.id} is already installed`);continue}let j=g.getSystems();if(!j.length)console.warn(`Bundle ${g.id} has no systems`);for(let D of j){let F=D;if(this._systems.push(F),F.onAttach)F.onAttach(this);if(F.eventHandlers)for(let K in F.eventHandlers){let V=F.eventHandlers[K];if(V?.handler){let X=(Z)=>{V.handler(Z,this)};this._eventBus.subscribe(K,X)}}}let J=g.getResources();for(let[D,F]of J.entries())this._resourceManager.add(D,F);this._installedBundles.add(g.id)}return this}removeSystem(f){let g=this._systems.findIndex((J)=>J.label===f);if(g===-1)return!1;let j=this._systems[g];if(!j)return!1;return j.onDetach?.(this),this._systems.splice(g,1),!0}hasResource(f){return this._resourceManager.has(f)}getResource(f){return this._resourceManager.getOptional(f)}getResourceOrThrow(f){return this._resourceManager.get(f)}addResource(f,g){return this._resourceManager.add(f,g),this}hasComponent(f,g){return this._entityManager.getComponent(f,g)!==null}getEntitiesWithComponents(f,g=[]){return this._entityManager.getEntitiesWithComponents(f,g)}update(f){for(let g of this._systems){if(!g.process)continue;let j={};if(g.entityQueries){for(let J in g.entityQueries){let D=g.entityQueries[J];if(D)j[J]=this._entityManager.getEntitiesWithComponents(D.with,D.without||[])}g.process(j,f,this)}else g.process([],f,this)}}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}get resourceManager(){return this._resourceManager}get installedBundles(){return Array.from(this._installedBundles)}addSystem(f){return new L(f,this)}}function $(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class U{_systems=[];_resources=new Map;_id;constructor(f){this._id=f||$()}get id(){return this._id}set id(f){this._id=f}addSystem(f){let g=new L(f,null,this);return this._systems.push(g),g}addResource(f,g){return this._resources.set(f,g),this}getSystems(){return this._systems.map((f)=>f.build())}getResources(){return new Map(this._resources)}getResource(f){return this._resources.get(f)}getSystemBuilders(){return[...this._systems]}hasResource(f){return this._resources.has(f)}}function G(f,...g){if(g.length===0)return new U(f);let j=new U(f);for(let J of g){for(let D of J.getSystemBuilders())j.addSystem(D);for(let[D,F]of J.getResources().entries())j.addResource(D,F)}return j}var c=W;export{G as mergeBundles,c as default,L as SystemBuilder,Q as ResourceManager,P as EventBus,M as EntityManager,U as Bundle};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=682FE990012EF59564756E2164756E21
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/entity-manager.ts", "../src/event-bus.ts", "../src/resource-manager.ts", "../src/
|
|
3
|
+
"sources": ["../src/entity-manager.ts", "../src/event-bus.ts", "../src/resource-manager.ts", "../src/system-builder.ts", "../src/ecspresso.ts", "../src/bundle.ts", "../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import type { Entity, FilteredEntity } from \"./types\";\n\nexport default\nclass EntityManager<ComponentTypes> {\n\tprivate nextId: number = 1;\n\tprivate entities: Map<number, Entity<ComponentTypes>> = new Map();\n\tprivate componentIndices: Map<keyof ComponentTypes, Set<number>> = new Map();\n\t\n\tcreateEntity(): Entity<ComponentTypes> {\n\t\tconst id = this.nextId++;\n\t\tconst entity: Entity<ComponentTypes> = { id, components: {} };\n\t\tthis.entities.set(id, entity);\n\t\treturn entity;\n\t}\n\n\t// TODO: Component object pooling if(/when) garbage collection is an issue...?\n\taddComponent<ComponentName extends keyof ComponentTypes>(\n\t\tentityOrId: number | Entity<ComponentTypes>,\n\t\tcomponentName: ComponentName,\n\t\tdata: ComponentTypes[ComponentName]\n\t) {\n\t\tconst entity = typeof entityOrId === 'number' ?\n\t\t\tthis.entities.get(entityOrId) :\n\t\t\tentityOrId;\n\n\t\tif (!entity) throw new Error(`Entity ${entityOrId} does not exist`);\n\n\t\tentity.components[componentName] = data;\n\t\t\n\t\t// Update component index\n\t\tif (!this.componentIndices.has(componentName)) {\n\t\t\tthis.componentIndices.set(componentName, new Set());\n\t\t}\n\t\tthis.componentIndices.get(componentName)?.add(entity.id);\n\t\treturn this;\n\t}\n\n\tremoveComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName) {\n\t\tconst entity = this.entities.get(entityId);\n\t\tif (!entity) throw new Error(`Entity ${entityId} does not exist`);\n\n\t\tdelete entity.components[componentName];\n\t\t\n\t\t// Update component index\n\t\tthis.componentIndices.get(componentName)?.delete(entityId);\n\t}\n\n\tgetComponent<ComponentName extends keyof ComponentTypes>(entityId: number, componentName: ComponentName): ComponentTypes[ComponentName] | null {\n\t\tconst entity = this.entities.get(entityId);\n\n\t\tif (!entity) throw new Error(`Entity ${entityId} does not exist`);\n\n\t\treturn entity.components[componentName] || null;\n\t}\n\n\tgetEntitiesWithComponents<\n\t\tWithComponents extends keyof ComponentTypes = never,\n\t\tWithoutComponents extends keyof ComponentTypes = never\n\t>(\n\t\trequired: ReadonlyArray<WithComponents> = [] as any, \n\t\texcluded: ReadonlyArray<WithoutComponents> = [] as any,\n\t): Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>> {\n\t\t// Use the smallest component set as base for better performance\n\t\tif (required.length === 0) {\n\t\t\tif (excluded.length === 0) {\n\t\t\t\treturn Array.from(this.entities.values()) as any;\n\t\t\t}\n\n\t\t\treturn Array\n\t\t\t\t.from(this.entities.values())\n\t\t\t\t.filter((entity) => {\n\t\t\t\t\treturn excluded.every(comp => !(comp in entity.components));\n\t\t\t\t}) as any;\n\t\t}\n\t\t\n\t\t// Find the component with the smallest entity set to start with\n\t\tconst smallestComponent = required.reduce((smallest, comp) => {\n\t\t\tconst set = this.componentIndices.get(comp);\n\t\t\tconst currentSize = set ? set.size : 0;\n\t\t\tconst smallestSize = this.componentIndices.get(smallest!)?.size ?? Infinity;\n\t\t\t\n\t\t\treturn currentSize < smallestSize ? comp : smallest;\n\t\t}, required[0])!;\n\n\t\t// Start with the entities from the smallest component set\n\t\tconst candidates = Array.from(this.componentIndices.get(smallestComponent) || []);\n\n\t\t// Return full entity objects, not just IDs\n\t\treturn candidates\n\t\t\t.filter(id => {\n\t\t\t\tconst entity = this.entities.get(id);\n\t\t\t\treturn (\n\t\t\t\t\tentity &&\n\t\t\t\t\trequired.every(comp => comp in entity.components) && \n\t\t\t\t\texcluded.every(comp => !(comp in entity.components))\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map(id => this.entities.get(id)!) as Array<FilteredEntity<ComponentTypes, WithComponents extends never ? never : WithComponents, WithoutComponents extends never ? never : WithoutComponents>>;\n\t}\n\n\tremoveEntity(entityId: number): boolean {\n\t\tconst entity = this.entities.get(entityId);\n\t\tif (!entity) return false;\n\t\t\n\t\t// Remove entity from all component indices\n\t\tfor (const componentName of Object.keys(entity.components) as Array<keyof ComponentTypes>) {\n\t\t\tthis.componentIndices.get(componentName)?.delete(entityId);\n\t\t}\n\t\t\n\t\t// Remove the entity itself\n\t\treturn this.entities.delete(entityId);\n\t}\n\n\tgetEntity(entityId: number): Entity<ComponentTypes> | undefined {\n\t\treturn this.entities.get(entityId);\n\t}\n}\n",
|
|
6
6
|
"import type { EventHandler } from \"./types\";\n\nexport default\nclass EventBus<EventTypes> {\n\tprivate handlers: Map<keyof EventTypes, Array<EventHandler<any>>> = new Map();\n\n\t/**\n\t * Subscribe to an event\n\t */\n\tsubscribe<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void\n\t): () => void {\n\t\treturn this.addHandler(eventType, callback, false);\n\t}\n\n\t/**\n\t * Subscribe to an event once\n\t */\n\tonce<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void\n\t): () => void {\n\t\treturn this.addHandler(eventType, callback, true);\n\t}\n\n\t/**\n\t * Internal method to add an event handler\n\t */\n\tprivate addHandler<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tcallback: (data: EventTypes[E]) => void,\n\t\tonce: boolean\n\t): () => void {\n\t\tif (!this.handlers.has(eventType)) {\n\t\t\tthis.handlers.set(eventType, []);\n\t\t}\n\n\t\tconst handler: EventHandler<EventTypes[E]> = {\n\t\t\tcallback,\n\t\t\tonce\n\t\t};\n\n\t\tthis.handlers.get(eventType)!.push(handler);\n\n\t\t// Return unsubscribe function\n\t\treturn () => {\n\t\t\tconst handlers = this.handlers.get(eventType);\n\t\t\tif (handlers) {\n\t\t\t\tconst index = handlers.indexOf(handler);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\thandlers.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublish<E extends keyof EventTypes>(\n\t\teventType: E,\n\t\tdata: EventTypes[E] = undefined as EventTypes[E]\n\t): void {\n\t\tconst handlers = this.handlers.get(eventType);\n\t\tif (!handlers) return;\n\n\t\t// Create a copy of handlers to avoid issues with handlers that modify the array\n\t\tconst handlersToCall = [...handlers];\n\t\t\n\t\t// Call all handlers and collect handlers to remove\n\t\tconst handlersToRemove: EventHandler<any>[] = [];\n\t\t\n\t\tfor (const handler of handlersToCall) {\n\t\t\thandler.callback(data);\n\t\t\tif (handler.once) {\n\t\t\t\thandlersToRemove.push(handler);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (handlersToRemove.length > 0) {\n\t\t\tfor (const handler of handlersToRemove) {\n\t\t\t\tconst index = handlers.indexOf(handler);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\thandlers.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.handlers.clear();\n\t}\n\n\tclearEvent<E extends keyof EventTypes>(eventType: E): void {\n\t\tthis.handlers.delete(eventType);\n\t}\n}\n",
|
|
7
7
|
"export default\nclass ResourceManager<ResourceTypes extends Record<string, any> = Record<string, any>> {\n\tprivate resources: Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]> = new Map();\n\n\t/**\n\t * Add a resource to the manager\n\t * @param label The resource key\n\t * @param resource The resource value\n\t * @returns The resource manager instance for chaining\n\t */\n\tadd<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K]) {\n\t\tthis.resources.set(label, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get a resource from the manager\n\t * @param label The resource key\n\t * @returns The resource value\n\t * @throws Error if resource not found\n\t */\n\tget<K extends keyof ResourceTypes>(label: K): ResourceTypes[K] {\n\t\tconst resource = this.resources.get(label);\n\n\t\tif (resource === undefined) {\n\t\t\tthrow new Error(`Resource ${String(label)} not found`);\n\t\t}\n\n\t\treturn resource;\n\t}\n\n\t/**\n\t * Get a resource from the manager, returning undefined if not found\n\t * @param label The resource key\n\t * @returns The resource value or undefined if not found\n\t */\n\tgetOptional<K extends keyof ResourceTypes>(label: K): ResourceTypes[K] | undefined {\n\t\tconst resource = this.resources.get(label);\n\t\treturn resource as ResourceTypes[K] | undefined;\n\t}\n\n\t/**\n\t * Check if a resource exists\n\t * @param label The resource key\n\t * @returns True if the resource exists\n\t */\n\thas<K extends keyof ResourceTypes>(label: K): boolean {\n\t\treturn this.resources.has(label);\n\t}\n\n\t/**\n\t * Remove a resource\n\t * @param label The resource key\n\t * @returns True if the resource was removed\n\t */\n\tremove<K extends keyof ResourceTypes>(label: K): boolean {\n\t\treturn this.resources.delete(label);\n\t}\n\n\t/**\n\t * Get all resource keys\n\t * @returns Array of resource keys\n\t */\n\tgetKeys(): Array<keyof ResourceTypes> {\n\t\treturn Array.from(this.resources.keys());\n\t}\n}\n",
|
|
8
|
-
"import
|
|
9
|
-
"import
|
|
10
|
-
"import
|
|
8
|
+
"import Bundle from \"./bundle\";\nimport ECSpresso from \"./ecspresso\";\nimport type { FilteredEntity, System } from \"./types\";\n\n/**\n * Builder class for creating type-safe ECS Systems with proper query inference\n */\nexport class SystemBuilder<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>> = {},\n> {\n\tprivate queries: Queries = {} as Queries;\n\tprivate processFunction?: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>;\n\tprivate attachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate detachFunction?: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>;\n\tprivate eventHandlers?: {\n\t\t[EventName in keyof EventTypes]?: {\n\t\t\thandler(\n\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\tecs: ECSpresso<\n\t\t\t\t\tComponentTypes & Record<string, any>,\n\t\t\t\t\tEventTypes,\n\t\t\t\t\tResourceTypes\n\t\t\t\t>,\n\t\t\t): void;\n\t\t};\n\t};\n\n\tconstructor(\n\t\tprivate _label: string,\n\t\tprivate _ecspresso: ECSpresso<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t\tprivate _bundle: Bundle<ComponentTypes, EventTypes, ResourceTypes> | null = null,\n\t) {}\n\n\tget label() {\n\t\treturn this._label;\n\t}\n\n\tget bundle() {\n\t\treturn this._bundle;\n\t}\n\n\tget ecspresso() {\n\t\treturn this._ecspresso;\n\t}\n\n\t/**\n\t * Add a query definition to the system\n\t */\n\taddQuery<\n\t\tQueryName extends string,\n\t\tWithComponents extends keyof ComponentTypes,\n\t\tWithoutComponents extends keyof ComponentTypes = never,\n\t>(\n\t\tname: QueryName,\n\t\tdefinition: {\n\t\t\twith: ReadonlyArray<WithComponents>;\n\t\t\twithout?: ReadonlyArray<WithoutComponents>;\n\t\t}\n\t): SystemBuilder<\n\t\tComponentTypes,\n\t\tEventTypes,\n\t\tResourceTypes,\n\t\tQueries & Record<QueryName, QueryDefinition<ComponentTypes, WithComponents, WithoutComponents>>\n\t> {\n\t\t// Cast is needed because TypeScript can't preserve the type information\n\t\t// when modifying an object property\n\t\tconst newBuilder = this as any;\n\t\tnewBuilder.queries = {\n\t\t\t...this.queries,\n\t\t\t[name]: definition,\n\t\t};\n\t\treturn newBuilder;\n\t}\n\n\t/**\n\t * Set the system's process function that runs each update\n\t * @param process Function to process entities matching the system's queries each update\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetProcess(\n\t\tprocess: ProcessFunction<ComponentTypes, EventTypes, ResourceTypes, Queries>\n\t): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\t\tthis.processFunction = process;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onAttach lifecycle hook\n\t * Called when the system is attached to the ECS\n\t * @param onAttach Function to run when this system is attached to the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnAttach(\n\t\tonAttach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\t\tthis.attachFunction = onAttach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the onDetach lifecycle hook\n\t * Called when the system is removed from the ECS\n\t * @param onDetach Function to run when this system is detached from the ECS\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetOnDetach(\n\t\tonDetach: LifecycleFunction<ComponentTypes, EventTypes, ResourceTypes>\n\t): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\t\tthis.detachFunction = onDetach;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set event handlers for the system\n\t * These handlers will be automatically subscribed when the system is attached\n\t * @param handlers Object mapping event names to handler functions\n\t * @returns This SystemBuilder instance for method chaining\n\t */\n\tsetEventHandlers(\n\t\thandlers: {\n\t\t\t[EventName in keyof EventTypes]?: {\n\t\t\t\thandler(\n\t\t\t\t\tdata: EventTypes[EventName],\n\t\t\t\t\tecs: ECSpresso<\n\t\t\t\t\t\tComponentTypes & Record<string, any>,\n\t\t\t\t\t\tEventTypes,\n\t\t\t\t\t\tResourceTypes\n\t\t\t\t\t>\n\t\t\t\t): void;\n\t\t\t};\n\t\t}\n\t): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries> {\n\t\tthis.eventHandlers = handlers;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build the final system object\n\t */\n\tbuild() {\n\t\tconst system: System<ComponentTypes, any, any, EventTypes, ResourceTypes> = {\n\t\t\tlabel: this._label,\n\t\t\tentityQueries: this.queries as any,\n\t\t};\n\n\t\tif (this.processFunction) {\n\t\t\tsystem.process = this.processFunction as any;\n\t\t}\n\n\t\tif (this.attachFunction) {\n\t\t\tsystem.onAttach = this.attachFunction;\n\t\t}\n\n\t\tif (this.detachFunction) {\n\t\t\tsystem.onDetach = this.detachFunction;\n\t\t}\n\n\t\tif (this.eventHandlers) {\n\t\t\tsystem.eventHandlers = this.eventHandlers;\n\t\t}\n\n\t\t// If this system is being built directly from an ECSpresso instance (not via a bundle),\n\t\t// then register it with the ECSpresso instance\n\t\tif (this._ecspresso && !this._bundle) {\n\t\t\tconst typedSystem = system as System<ComponentTypes, any, any, EventTypes, ResourceTypes>;\n\t\t\tthis._ecspresso[\"_systems\"].push(typedSystem);\n\n\t\t\t// Call onAttach lifecycle hook if defined\n\t\t\tif (typedSystem.onAttach) {\n\t\t\t\ttypedSystem.onAttach(this._ecspresso);\n\t\t\t}\n\n\t\t\t// Auto-subscribe to events if eventHandlers are defined\n\t\t\tif (typedSystem.eventHandlers) {\n\t\t\t\tfor (const eventName in typedSystem.eventHandlers) {\n\t\t\t\t\tconst handler = typedSystem.eventHandlers[eventName];\n\t\t\t\t\tif (handler?.handler) {\n\t\t\t\t\t\t// Create a wrapper that passes the additional parameters to the handler\n\t\t\t\t\t\tconst wrappedHandler = (data: any) => {\n\t\t\t\t\t\t\thandler.handler(data, this._ecspresso!);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tthis._ecspresso.eventBus.subscribe(eventName, wrappedHandler);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n}\n\n// Helper type definitions\ntype QueryDefinition<\n\tComponentTypes,\n\tWithComponents extends keyof ComponentTypes = any,\n\tWithoutComponents extends keyof ComponentTypes = any,\n> = {\n\twith: ReadonlyArray<WithComponents>;\n\twithout?: ReadonlyArray<WithoutComponents>;\n};\n\ntype QueryResults<\n\tComponentTypes,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = {\n\t[QueryName in keyof Queries]: QueryName extends string\n\t\t? FilteredEntity<\n\t\t\tComponentTypes,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, infer W, any> ? W : never,\n\t\t\tQueries[QueryName] extends QueryDefinition<ComponentTypes, any, infer WO> ? WO : never\n\t\t>[]\n\t\t: never;\n};\n\n/**\n * Function signature for system process methods\n * @param queries Results of entity queries defined by the system\n * @param deltaTime Time elapsed since last update in seconds\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype ProcessFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n\tQueries extends Record<string, QueryDefinition<ComponentTypes>>,\n> = (\n\tqueries: QueryResults<ComponentTypes, Queries>,\n\tdeltaTime: number,\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>\n) => void;\n\n/**\n * Function signature for system lifecycle hooks (onAttach and onDetach)\n * @param ecs The ECSpresso instance providing access to all ECS functionality\n */\ntype LifecycleFunction<\n\tComponentTypes,\n\tEventTypes extends Record<string, any>,\n\tResourceTypes extends Record<string, any>,\n> = (\n\tecs: ECSpresso<\n\t\tComponentTypes & Record<string, any>,\n\t\tEventTypes,\n\t\tResourceTypes\n\t>,\n) => void;\n\n// // Factory function for easier creation\n// function createSystem<\n// \tComponentTypes,\n// \tEventTypes = any,\n// \tResourceTypes = any\n// >(\n// \tlabel: string\n// ): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes> {\n// \treturn new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(label);\n// }\n",
|
|
9
|
+
"import EntityManager from \"./entity-manager\";\nimport EventBus from \"./event-bus\";\nimport ResourceManager from \"./resource-manager\";\nimport type { System } from \"./types\";\nimport type Bundle from \"./bundle\";\nimport { SystemBuilder } from \"./system-builder\";\nimport { version } from \"../package.json\";\n\n\n/**\n * The main ECS (Entity Component System) container class\n *\n * This class manages entities, components, systems, resources, and events.\n *\n * Systems interact with the ECS through a single parameter that provides access\n * to the entire ECSpresso instance. This provides a simplified API for systems\n * and allows them access to all ECS functionality through a single reference.\n *\n * @template ComponentTypes Record of component types used in this ECS instance\n * @template EventTypes Record of event types used in this ECS instance\n * @template ResourceTypes Record of resource types used in this ECS instance\n */\nexport default\nclass ECSpresso<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n> {\n\tpublic static readonly VERSION = version;\n\tprivate _entityManager: EntityManager<ComponentTypes>;\n\tprivate _systems: System<ComponentTypes, any, any, EventTypes, ResourceTypes>[] = [];\n\tprivate _eventBus: EventBus<EventTypes>;\n\tprivate _resourceManager: ResourceManager<ResourceTypes>;\n\tprivate _installedBundles: Set<string> = new Set();\n\n\tconstructor() {\n\t\tthis._entityManager = new EntityManager<ComponentTypes>();\n\t\tthis._eventBus = new EventBus<EventTypes>();\n\t\tthis._resourceManager = new ResourceManager<ResourceTypes>();\n\t}\n\n\t/**\n\t * Install one or more bundles into this ECS instance\n\t * Systems in the bundle will have their onAttach method called with this ECSpresso instance\n\t * @param bundles One or more bundles to install\n\t * @returns This ECSpresso instance for method chaining\n\t */\n\tinstall<\n\t\tBundles extends Array<Bundle<any, any, any> | null>\n\t>(...bundles: Bundles): this {\n\t\tfor (const bundle of bundles) {\n\t\t\tif (!bundle) return this;\n\n\t\t\t// Check if this bundle is already installed\n\t\t\tif (this._installedBundles.has(bundle.id)) {\n\t\t\t\tconsole.warn(`Bundle ${bundle.id} is already installed`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst systems = bundle.getSystems();\n\n\t\t\t// Check if bundle has systems\n\t\t\tif (!systems.length) {\n\t\t\t\tconsole.warn(`Bundle ${bundle.id} has no systems`);\n\t\t\t}\n\n\t\t\t// Register all systems from the bundle\n\t\t\tfor (const system of systems) {\n\t\t\t\t// Need to cast here because we can't fully type the system generics\n\t\t\t\tconst typedSystem = system as unknown as System<ComponentTypes, any, any, EventTypes, ResourceTypes>;\n\t\t\t\tthis._systems.push(typedSystem);\n\n\t\t\t\t// Call onAttach lifecycle hook if defined\n\t\t\t\tif (typedSystem.onAttach) {\n\t\t\t\t\ttypedSystem.onAttach(\n\t\t\t\t\t\tthis\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Auto-subscribe to events if eventHandlers are defined\n\t\t\t\tif (typedSystem.eventHandlers) {\n\t\t\t\t\tfor (const eventName in typedSystem.eventHandlers) {\n\t\t\t\t\t\tconst handler = typedSystem.eventHandlers[eventName];\n\t\t\t\t\t\tif (handler?.handler) {\n\t\t\t\t\t\t\t// Create a wrapper that passes the additional parameters to the handler\n\t\t\t\t\t\t\tconst wrappedHandler = (data: any) => {\n\t\t\t\t\t\t\t\thandler.handler(\n\t\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tthis._eventBus.subscribe(eventName, wrappedHandler);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Register all resources from the bundle\n\t\t\tconst resources = bundle.getResources();\n\t\t\tfor (const [key, value] of resources.entries()) {\n\t\t\t\t// We need to cast here because TypeScript can't verify the type compatibility\n\t\t\t\t// between bundles, but we trust that the bundle's resource types are compatible\n\t\t\t\tthis._resourceManager.add(key as unknown as keyof ResourceTypes, value as any);\n\t\t\t}\n\n\t\t\t// Mark this bundle as installed\n\t\t\tthis._installedBundles.add(bundle.id);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a system by its label\n\t * Calls the system's onDetach method with this ECSpresso instance if defined\n\t * @param label The unique label of the system to remove\n\t * @returns true if the system was found and removed, false otherwise\n\t */\n\tremoveSystem(label: string): boolean {\n\t\tconst index = this._systems.findIndex(system => system.label === label);\n\t\tif (index === -1) return false;\n\n\t\tconst system = this._systems[index];\n\t\tif (!system) return false;\n\n\t\tsystem.onDetach?.(\n\t\t\tthis\n\t\t);\n\n\t\t// Remove system\n\t\tthis._systems.splice(index, 1);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Check if a resource exists\n\t */\n\thasResource<K extends keyof ResourceTypes>(key: K): boolean {\n\t\treturn this._resourceManager.has(key);\n\t}\n\n\t/**\n\t * Get a resource if it exists, or undefined if not\n\t */\n\tgetResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] | undefined {\n\t\treturn this._resourceManager.getOptional(key);\n\t}\n\n\t/**\n\t * Get a resource, throws error if not found\n\t */\n\tgetResourceOrThrow<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] {\n\t\treturn this._resourceManager.get(key);\n\t}\n\n\t/**\n\t * Add a resource to the ECS instance\n\t */\n\taddResource<K extends keyof ResourceTypes>(key: K, resource: ResourceTypes[K]): this {\n\t\tthis._resourceManager.add(key, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Check if an entity has a component\n\t */\n\thasComponent<K extends keyof ComponentTypes>(\n\t\tentityId: number,\n\t\tcomponentName: K\n\t): boolean {\n\t\tconst component = this._entityManager.getComponent(entityId, componentName);\n\t\treturn component !== null;\n\t}\n\n\t/**\n\t * Get all entities with specific components\n\t */\n\tgetEntitiesWithComponents(\n\t\twithComponents: (keyof ComponentTypes)[],\n\t\twithoutComponents: (keyof ComponentTypes)[] = []\n\t) {\n\t\treturn this._entityManager.getEntitiesWithComponents(\n\t\t\twithComponents,\n\t\t\twithoutComponents\n\t\t);\n\t}\n\n\t/**\n\t * Update all systems\n\t * Calls each system's process method with this ECSpresso instance\n\t * @param deltaTime Time elapsed since the last update in seconds\n\t */\n\tupdate(deltaTime: number) {\n\t\tfor (const system of this._systems) {\n\t\t\tif (!system.process) continue;\n\n\t\t\t// Prepare query results\n\t\t\tconst queryResults: Record<string, any[]> = {};\n\n\t\t\t// Process entity queries if defined\n\t\t\tif (system.entityQueries) {\n\t\t\t\tfor (const queryName in system.entityQueries) {\n\t\t\t\t\tconst query = system.entityQueries[queryName];\n\t\t\t\t\tif (query) {\n\t\t\t\t\t\tqueryResults[queryName] = this._entityManager.getEntitiesWithComponents(\n\t\t\t\t\t\t\tquery.with,\n\t\t\t\t\t\t\tquery.without || []\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Call the system's process method\n\t\t\t\tsystem.process(\n\t\t\t\t\tqueryResults,\n\t\t\t\t\tdeltaTime,\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// No queries defined, pass an empty array\n\t\t\t\tsystem.process(\n\t\t\t\t\t[],\n\t\t\t\t\tdeltaTime,\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Getters for the internal managers\n\tget entityManager() {\n\t\treturn this._entityManager;\n\t}\n\n\tget eventBus() {\n\t\treturn this._eventBus;\n\t}\n\n\tget resourceManager() {\n\t\treturn this._resourceManager;\n\t}\n\n\t/**\n\t * Get all installed bundle IDs\n\t */\n\tget installedBundles(): string[] {\n\t\treturn Array.from(this._installedBundles);\n\t}\n\n\t/**\n\t * Add a system directly to this ECSpresso instance\n\t * @param label Unique identifier for the system\n\t * @returns A SystemBuilder instance for method chaining\n\t */\n\taddSystem(label: string) {\n\t\tconst system = new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(label, this);\n\n\t\t// When the system builder is finalized (typically from user code),\n\t\t// the build method will automatically register the system with this ECSpresso instance\n\n\t\treturn system;\n\t}\n}\n",
|
|
10
|
+
"import { SystemBuilder } from './system-builder';\n\n/**\n * Generates a unique ID for a bundle\n */\nfunction generateBundleId(): string {\n\treturn `bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Bundle class that encapsulates a set of components, resources, events, and systems\n * that can be merged into a ECSpresso instance\n */\nexport default class Bundle<\n\tComponentTypes extends Record<string, any> = Record<string, any>,\n\tEventTypes extends Record<string, any> = Record<string, any>,\n\tResourceTypes extends Record<string, any> = Record<string, any>,\n> {\n\tprivate _systems: SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[] = [];\n\tprivate _resources: Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]> = new Map();\n\tprivate _id: string;\n\n\tconstructor(id?: string) {\n\t\tthis._id = id || generateBundleId();\n\t}\n\n\t/**\n\t * Get the unique ID of this bundle\n\t */\n\tget id(): string {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Set the ID of this bundle\n\t * @internal Used by combineBundles\n\t */\n\tset id(value: string) {\n\t\tthis._id = value;\n\t}\n\n\t/**\n\t * Add a system to this bundle\n\t */\n\taddSystem(label: string) {\n\t\tconst system = new SystemBuilder<ComponentTypes, EventTypes, ResourceTypes>(label, null, this);\n\n\t\tthis._systems.push(system);\n\n\t\treturn system;\n\t}\n\n\t/**\n\t * Add a resource to this bundle\n\t * @param label The resource key\n\t * @param resource The resource value\n\t */\n\taddResource<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K]) {\n\t\tthis._resources.set(label, resource);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get all systems defined in this bundle\n\t * Returns built System objects instead of SystemBuilders\n\t */\n\tgetSystems() {\n\t\treturn this._systems.map(system => system.build());\n\t}\n\n\t/**\n\t * Get all resources defined in this bundle\n\t */\n\tgetResources(): Map<keyof ResourceTypes, ResourceTypes[keyof ResourceTypes]> {\n\t\treturn new Map(this._resources);\n\t}\n\n\t/**\n\t * Get a specific resource by key\n\t * @param key The resource key\n\t * @returns The resource value or undefined if not found\n\t */\n\tgetResource<K extends keyof ResourceTypes>(key: K): ResourceTypes[K] | undefined {\n\t\treturn this._resources.get(key) as ResourceTypes[K] | undefined;\n\t}\n\n\t/**\n\t * Get all system builders in this bundle\n\t */\n\tgetSystemBuilders(): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, any>[] {\n\t\treturn [...this._systems];\n\t}\n\n\t/**\n\t * Check if this bundle has a specific resource\n\t * @param key The resource key to check\n\t * @returns True if the resource exists\n\t */\n\thasResource<K extends keyof ResourceTypes>(key: K): boolean {\n\t\treturn this._resources.has(key);\n\t}\n}\n\n/**\n * Utility type for merging two types\n */\n// This sets props with the same name but different type to \"never\". Maybe we want this?\nexport type Merge<T1, T2> = T1 & T2;\n// This makes the later prop types override the earlier ones. Maybe we want this instead?\n// export type Merge<T1, T2> = Omit<T1, keyof T2> & T2;\n// Or maybe this, which sets props with the same name to a union of the two types\n// export type Merge<T1, T2> = {\n// \t[K in keyof T1 | keyof T2]: K extends keyof T1 & keyof T2\n// \t\t? T1[K] | T2[K]\n// \t\t: K extends keyof T1\n// \t\t\t? T1[K]\n// \t\t\t: K extends keyof T2\n// \t\t\t\t? T2[K]\n// \t\t\t\t: never;\n// };\n\nexport type MergeAll<T extends any[]> = T extends [infer First, ...infer Rest] ?\n\tRest extends [] ?\n\t\tFirst: Merge<First, MergeAll<Rest>>:\n\t{};\n\nexport function mergeBundles<\n\tBundles extends Array<Bundle<any, any, any>>\n>(\n\tid: string,\n\t...bundles: Bundles\n): Bundle<\n\tMergeAll<{ [K in keyof Bundles]: Bundles[K] extends Bundle<infer C, any, any> ? C : never }>,\n\tMergeAll<{ [K in keyof Bundles]: Bundles[K] extends Bundle<any, infer E, any> ? E : never }>,\n\tMergeAll<{ [K in keyof Bundles]: Bundles[K] extends Bundle<any, any, infer R> ? R : never }>\n> {\n\tif (bundles.length === 0) {\n\t\treturn new Bundle(id);\n\t}\n\n\tconst combined = new Bundle(id);\n\n\tfor (const bundle of bundles) {\n\t\tfor (const system of bundle.getSystemBuilders()) {\n\t\t\tcombined.addSystem(system as any);\n\t\t}\n\n\t\t// Add resources from this bundle\n\t\tfor (const [label, resource] of bundle.getResources().entries()) {\n\t\t\tcombined.addResource(label as any, resource);\n\t\t}\n\t}\n\n\treturn combined as any;\n}\n",
|
|
11
11
|
"import ECSpresso from './ecspresso';\nimport { SystemBuilder } from './system-builder';\nimport Bundle, { mergeBundles } from './bundle';\n\nexport * from './types';\nexport { default as EntityManager } from './entity-manager';\nexport { default as EventBus } from './event-bus';\nexport { default as ResourceManager } from './resource-manager';\nexport { SystemBuilder };\nexport { Bundle, mergeBundles };\nexport default ECSpresso;\n"
|
|
12
12
|
],
|
|
13
|
-
"mappings": "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
|
|
14
|
-
"debugId": "
|
|
13
|
+
"mappings": "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",
|
|
14
|
+
"debugId": "682FE990012EF59564756E2164756E21",
|
|
15
15
|
"names": []
|
|
16
16
|
}
|
package/dist/system-builder.d.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import Bundle from "./bundle";
|
|
2
|
-
import
|
|
2
|
+
import ECSpresso from "./ecspresso";
|
|
3
|
+
import type { FilteredEntity } from "./types";
|
|
3
4
|
/**
|
|
4
5
|
* Builder class for creating type-safe ECS Systems with proper query inference
|
|
5
6
|
*/
|
|
6
7
|
export declare class SystemBuilder<ComponentTypes extends Record<string, any> = Record<string, any>, EventTypes extends Record<string, any> = Record<string, any>, ResourceTypes extends Record<string, any> = Record<string, any>, Queries extends Record<string, QueryDefinition<ComponentTypes>> = {}> {
|
|
7
8
|
private _label;
|
|
9
|
+
private _ecspresso;
|
|
8
10
|
private _bundle;
|
|
9
11
|
private queries;
|
|
10
12
|
private processFunction?;
|
|
11
13
|
private attachFunction?;
|
|
12
14
|
private detachFunction?;
|
|
13
15
|
private eventHandlers?;
|
|
14
|
-
constructor(_label: string, _bundle?: Bundle<ComponentTypes, EventTypes, ResourceTypes>);
|
|
16
|
+
constructor(_label: string, _ecspresso?: ECSpresso<ComponentTypes, EventTypes, ResourceTypes> | null, _bundle?: Bundle<ComponentTypes, EventTypes, ResourceTypes> | null);
|
|
15
17
|
get label(): string;
|
|
16
|
-
get bundle(): Bundle<ComponentTypes, EventTypes, ResourceTypes
|
|
18
|
+
get bundle(): Bundle<ComponentTypes, EventTypes, ResourceTypes> | null;
|
|
19
|
+
get ecspresso(): ECSpresso<ComponentTypes, EventTypes, ResourceTypes> | null;
|
|
17
20
|
/**
|
|
18
21
|
* Add a query definition to the system
|
|
19
22
|
*/
|
|
@@ -49,13 +52,13 @@ export declare class SystemBuilder<ComponentTypes extends Record<string, any> =
|
|
|
49
52
|
*/
|
|
50
53
|
setEventHandlers(handlers: {
|
|
51
54
|
[EventName in keyof EventTypes]?: {
|
|
52
|
-
handler(data: EventTypes[EventName], ecs:
|
|
55
|
+
handler(data: EventTypes[EventName], ecs: ECSpresso<ComponentTypes & Record<string, any>, EventTypes, ResourceTypes>): void;
|
|
53
56
|
};
|
|
54
57
|
}): SystemBuilder<ComponentTypes, EventTypes, ResourceTypes, Queries>;
|
|
55
58
|
/**
|
|
56
59
|
* Build the final system object
|
|
57
60
|
*/
|
|
58
|
-
build():
|
|
61
|
+
build(): this;
|
|
59
62
|
}
|
|
60
63
|
type QueryDefinition<ComponentTypes, WithComponents extends keyof ComponentTypes = any, WithoutComponents extends keyof ComponentTypes = any> = {
|
|
61
64
|
with: ReadonlyArray<WithComponents>;
|
|
@@ -70,10 +73,10 @@ type QueryResults<ComponentTypes, Queries extends Record<string, QueryDefinition
|
|
|
70
73
|
* @param deltaTime Time elapsed since last update in seconds
|
|
71
74
|
* @param ecs The ECSpresso instance providing access to all ECS functionality
|
|
72
75
|
*/
|
|
73
|
-
type ProcessFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>, Queries extends Record<string, QueryDefinition<ComponentTypes>>> = (queries: QueryResults<ComponentTypes, Queries>, deltaTime: number, ecs:
|
|
76
|
+
type ProcessFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>, Queries extends Record<string, QueryDefinition<ComponentTypes>>> = (queries: QueryResults<ComponentTypes, Queries>, deltaTime: number, ecs: ECSpresso<ComponentTypes & Record<string, any>, EventTypes, ResourceTypes>) => void;
|
|
74
77
|
/**
|
|
75
78
|
* Function signature for system lifecycle hooks (onAttach and onDetach)
|
|
76
79
|
* @param ecs The ECSpresso instance providing access to all ECS functionality
|
|
77
80
|
*/
|
|
78
|
-
type LifecycleFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>> = (ecs:
|
|
81
|
+
type LifecycleFunction<ComponentTypes, EventTypes extends Record<string, any>, ResourceTypes extends Record<string, any>> = (ecs: ECSpresso<ComponentTypes & Record<string, any>, EventTypes, ResourceTypes>) => void;
|
|
79
82
|
export {};
|