@jael-ecs/core 1.0.3 → 1.1.1
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 +68 -43
- package/dist/ComponentManager.d.ts +10 -9
- package/dist/EntityManager.d.ts +8 -9
- package/dist/EventRegistry.d.ts +9 -6
- package/dist/Query.d.ts +12 -7
- package/dist/World.d.ts +9 -7
- package/dist/jael-build.cjs +1 -1
- package/dist/jael-build.js +106 -65
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,8 @@ _A modern, performant, and user-friendly Entity Component System library written
|
|
|
32
32
|
|
|
33
33
|
- **User Friendly API** - Clean, fluent api that's easy to learn
|
|
34
34
|
- **High Performance** - Optimized SparseSet implementation for fast entity lookups
|
|
35
|
-
- **
|
|
35
|
+
- **Query System** - Optimized cache query system for entity packets
|
|
36
|
+
- **Minimal Bundle size** - Compact bundle size without dependencies.(38kb 📦)
|
|
36
37
|
|
|
37
38
|
## Installation
|
|
38
39
|
|
|
@@ -60,13 +61,19 @@ interface Velocity {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
// Create entities
|
|
63
|
-
const
|
|
64
|
-
world.addComponent(
|
|
65
|
-
world.addComponent(
|
|
64
|
+
const playerId = world.create();
|
|
65
|
+
world.addComponent(playerId, "position", { x: 0, y: 0 });
|
|
66
|
+
world.addComponent(playerId, "velocity", { dx: 1, dy: 1 });
|
|
66
67
|
|
|
67
|
-
const
|
|
68
|
-
world.addComponent(
|
|
69
|
-
world.addComponent(
|
|
68
|
+
const enemyId = world.create();
|
|
69
|
+
world.addComponent(enemyId, "position", { x: 10, y: 10 });
|
|
70
|
+
world.addComponent(enemyId, "velocity", { dx: -1, dy: 0 });
|
|
71
|
+
|
|
72
|
+
// Using Entity Proxy
|
|
73
|
+
const playerId = world.create();
|
|
74
|
+
const player = world.getEntity(playerId);
|
|
75
|
+
player.add("position", { x: 0, y: 0 });
|
|
76
|
+
player.add("velocity", { dx: 1, dy: 1 });
|
|
70
77
|
|
|
71
78
|
// Create a system
|
|
72
79
|
const movementSystem: System = {
|
|
@@ -74,10 +81,20 @@ const movementSystem: System = {
|
|
|
74
81
|
update() {
|
|
75
82
|
const query = world.include("position", "velocity");
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
// Get direct proxy access
|
|
85
|
+
query.entities.forEach((entity) => {
|
|
78
86
|
const position = entity.get<Position>("position");
|
|
79
87
|
const velocity = entity.get<Velocity>("velocity");
|
|
80
88
|
|
|
89
|
+
position.x += velocity.dx * (Time.delta || 0.016);
|
|
90
|
+
position.y += velocity.dy * (Time.delta || 0.016);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Get entity ids from query
|
|
94
|
+
for (const entityId of query.ids) {
|
|
95
|
+
const position = this.world.getComponent<Position>(entityId, "position");
|
|
96
|
+
const velocity = this.world.getComponent<Velocity>(entityId, "velocity");
|
|
97
|
+
|
|
81
98
|
position.x += velocity.dx * (Time.delta || 0.016);
|
|
82
99
|
position.y += velocity.dy * (Time.delta || 0.016);
|
|
83
100
|
}
|
|
@@ -111,29 +128,26 @@ The central hub that manages entities, components, and systems.
|
|
|
111
128
|
|
|
112
129
|
```typescript
|
|
113
130
|
// Create a new entity
|
|
114
|
-
const
|
|
131
|
+
const entityId = world.create();
|
|
115
132
|
|
|
116
133
|
// Destroy an entity
|
|
117
|
-
world.destroy(
|
|
134
|
+
world.destroy(entityId);
|
|
118
135
|
|
|
119
136
|
// Check if entity exists
|
|
120
|
-
const exists = world.exist(
|
|
137
|
+
const exists = world.exist(entityId);
|
|
121
138
|
```
|
|
122
139
|
|
|
123
140
|
#### Component Management
|
|
124
141
|
|
|
125
142
|
```typescript
|
|
126
143
|
// Add component
|
|
127
|
-
world.addComponent(
|
|
144
|
+
world.addComponent(entityId, "position", { x: 0, y: 0 });
|
|
128
145
|
|
|
129
146
|
// Remove component
|
|
130
|
-
world.removeComponent(
|
|
147
|
+
world.removeComponent(entityId, "position");
|
|
131
148
|
|
|
132
149
|
// Get component
|
|
133
|
-
const position =
|
|
134
|
-
|
|
135
|
-
// Check if entity has component
|
|
136
|
-
const hasPosition = entity.has("position");
|
|
150
|
+
const position = world.getComponent<Position>(entityId, "position");
|
|
137
151
|
```
|
|
138
152
|
|
|
139
153
|
#### System Management
|
|
@@ -149,7 +163,7 @@ world.removeSystem(yourSystem);
|
|
|
149
163
|
#### Events
|
|
150
164
|
|
|
151
165
|
```typescript
|
|
152
|
-
// Listen to world events
|
|
166
|
+
// Listen to world events ( returns entity proxy for easy reading )
|
|
153
167
|
world.on("entityCreated", ({ entity }) => {
|
|
154
168
|
console.log("Entity created:", entity);
|
|
155
169
|
});
|
|
@@ -173,11 +187,12 @@ world.on("updated", () => {
|
|
|
173
187
|
|
|
174
188
|
### Entity
|
|
175
189
|
|
|
176
|
-
Base entity class for intuitive component management
|
|
190
|
+
Base entity class for intuitive component management as proxy around id
|
|
177
191
|
|
|
178
192
|
```typescript
|
|
179
193
|
// Create entity
|
|
180
|
-
const
|
|
194
|
+
const entityId = world.create();
|
|
195
|
+
const entity = world.getEntity(entityId); // Returns Entity class proxy
|
|
181
196
|
|
|
182
197
|
// Add component
|
|
183
198
|
entity.add("position", { x: 0, y: 0 });
|
|
@@ -190,6 +205,9 @@ const posExist = entity.has("position");
|
|
|
190
205
|
|
|
191
206
|
// Get curren value of the component
|
|
192
207
|
const compSchema = entity.get("position");
|
|
208
|
+
|
|
209
|
+
entity.id // Returns unique entity id from proxy
|
|
210
|
+
|
|
193
211
|
```
|
|
194
212
|
|
|
195
213
|
### System
|
|
@@ -199,7 +217,7 @@ Systems contain the game logic that processes entities with specific components.
|
|
|
199
217
|
```typescript
|
|
200
218
|
interface System {
|
|
201
219
|
priority: number; // Execution order (lower = earlier)
|
|
202
|
-
init?(): void // Runs when added to the world
|
|
220
|
+
init?(): void; // Runs when added to the world
|
|
203
221
|
exit?(): void; // Cleanup when removed
|
|
204
222
|
update(): void; // Main update logic
|
|
205
223
|
}
|
|
@@ -218,13 +236,13 @@ const renderSystem: System = {
|
|
|
218
236
|
update(dt) {
|
|
219
237
|
const renderableQuery = world.include("position", "sprite");
|
|
220
238
|
|
|
221
|
-
|
|
239
|
+
renderableQuery.entities.forEach((entity) => {
|
|
222
240
|
const position = entity.get<Position>("position");
|
|
223
241
|
const sprite = entity.get<Sprite>("sprite");
|
|
224
242
|
|
|
225
243
|
// Render entity
|
|
226
244
|
drawSprite(sprite, position.x, position.y);
|
|
227
|
-
}
|
|
245
|
+
})
|
|
228
246
|
},
|
|
229
247
|
|
|
230
248
|
exit() {
|
|
@@ -266,29 +284,36 @@ const complexQuery2 = world.include("position", "health").exclude("static");
|
|
|
266
284
|
#### Accessing Results
|
|
267
285
|
|
|
268
286
|
```typescript
|
|
269
|
-
// Iterate through entities
|
|
270
|
-
|
|
271
|
-
// Process
|
|
287
|
+
// Iterate through entities as proxy
|
|
288
|
+
query.entities.forEach((entity) => {
|
|
289
|
+
// Process Entity proxy
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Iterate through entities ids
|
|
293
|
+
for(const entityId of query.ids){
|
|
294
|
+
// Process Entity id
|
|
272
295
|
}
|
|
273
296
|
|
|
297
|
+
|
|
298
|
+
|
|
274
299
|
// Get the first value of the query
|
|
275
|
-
const first = query.entities
|
|
300
|
+
const first = query.entities[0];
|
|
301
|
+
const firstId = query.ids.first()
|
|
276
302
|
|
|
277
303
|
// Check query size
|
|
278
|
-
const count = query.
|
|
304
|
+
const count = query.size();
|
|
279
305
|
|
|
280
306
|
// Check if query has any entities
|
|
281
|
-
const isEmpty = query.
|
|
307
|
+
const isEmpty = query.size() === 0;
|
|
282
308
|
|
|
283
309
|
// Subscribe to query events
|
|
284
|
-
query.on(
|
|
285
|
-
// Entity added
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
query.on('removed', (entity: Entity) => {
|
|
310
|
+
query.on("added", (entityId: number) => {
|
|
289
311
|
// Entity added
|
|
290
|
-
})
|
|
312
|
+
});
|
|
291
313
|
|
|
314
|
+
query.on("removed", (entityId: number) => {
|
|
315
|
+
// Entity removed
|
|
316
|
+
});
|
|
292
317
|
```
|
|
293
318
|
|
|
294
319
|
### SparseSet
|
|
@@ -353,8 +378,8 @@ interface WorldEvents {
|
|
|
353
378
|
}
|
|
354
379
|
|
|
355
380
|
interface QueryEvents {
|
|
356
|
-
added:
|
|
357
|
-
removed:
|
|
381
|
+
added: number; //EntityId added to query entities
|
|
382
|
+
removed: number; //EntityId removed to query entities
|
|
358
383
|
}
|
|
359
384
|
|
|
360
385
|
// Listen to events
|
|
@@ -369,7 +394,7 @@ world.emit("entityCreated", { entity: someEntity });
|
|
|
369
394
|
world.off("entityCreated", handler);
|
|
370
395
|
|
|
371
396
|
// Romeve all listeners of a type
|
|
372
|
-
world.clearEvent(
|
|
397
|
+
world.clearEvent("type");
|
|
373
398
|
|
|
374
399
|
// Remove all listeners
|
|
375
400
|
world.clearAllEvents();
|
|
@@ -425,8 +450,8 @@ class MovementSystem implements System {
|
|
|
425
450
|
}
|
|
426
451
|
|
|
427
452
|
update() {
|
|
428
|
-
for
|
|
429
|
-
// Process movement
|
|
453
|
+
for(const entityId of this.movementQuery.ids){
|
|
454
|
+
// Process movement using entityId
|
|
430
455
|
}
|
|
431
456
|
}
|
|
432
457
|
}
|
|
@@ -438,13 +463,13 @@ type MovementSystem = { movementQuery: Query | null } & System;
|
|
|
438
463
|
const movementSystem: MovementSystem = {
|
|
439
464
|
movementQuery: null;
|
|
440
465
|
priority: 1;
|
|
441
|
-
|
|
466
|
+
|
|
442
467
|
init(){
|
|
443
468
|
this.movementQuery = world.include('position', 'velocity');
|
|
444
469
|
}
|
|
445
470
|
|
|
446
471
|
update(){
|
|
447
|
-
for (const
|
|
472
|
+
for (const entityId of this.movementQuery.ids) {
|
|
448
473
|
// Process movement
|
|
449
474
|
}
|
|
450
475
|
}
|
|
@@ -461,7 +486,7 @@ update() {
|
|
|
461
486
|
|
|
462
487
|
```typescript
|
|
463
488
|
// Remember to clean up when removing entities
|
|
464
|
-
world.destroy(
|
|
489
|
+
world.destroy(entityId); // Automatically removes all components
|
|
465
490
|
|
|
466
491
|
// Clean up systems if they have resources
|
|
467
492
|
system.exit?.(); // Called automatically when removed from world
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import { Entity } from './EntityManager';
|
|
2
1
|
import { default as EventRegistry } from './EventRegistry';
|
|
3
2
|
import { default as World } from './World';
|
|
4
3
|
export type ComponentSchema = Record<string, any>;
|
|
5
4
|
export interface ComponentManagerEvents {
|
|
6
5
|
add: {
|
|
7
|
-
|
|
6
|
+
entityId: number;
|
|
8
7
|
component: keyof ComponentSchema;
|
|
9
8
|
};
|
|
10
9
|
remove: {
|
|
11
|
-
|
|
10
|
+
entityId: number;
|
|
12
11
|
component: keyof ComponentSchema;
|
|
13
12
|
};
|
|
14
13
|
}
|
|
15
14
|
export declare class ComponentManager extends EventRegistry<ComponentManagerEvents> {
|
|
16
|
-
componentSet:
|
|
15
|
+
componentSet: {
|
|
16
|
+
[k: number]: ComponentSchema;
|
|
17
|
+
};
|
|
17
18
|
world: World;
|
|
18
19
|
constructor(world: World);
|
|
19
|
-
clearComponentSchema(
|
|
20
|
-
addComponent<K extends keyof ComponentSchema>(
|
|
21
|
-
getComponent<K extends keyof ComponentSchema>(
|
|
22
|
-
hasComponent<K extends keyof ComponentSchema>(
|
|
23
|
-
removeComponent<K extends keyof ComponentSchema>(
|
|
20
|
+
clearComponentSchema(entityId: number): void;
|
|
21
|
+
addComponent<K extends keyof ComponentSchema>(entityId: number, key: K, value: ComponentSchema[K]): void;
|
|
22
|
+
getComponent<K extends keyof ComponentSchema>(entityId: number, key: K): ComponentSchema[K] | undefined;
|
|
23
|
+
hasComponent<K extends keyof ComponentSchema>(entityId: number, key: K): boolean;
|
|
24
|
+
removeComponent<K extends keyof ComponentSchema>(entityId: number, key: K): void;
|
|
24
25
|
}
|
package/dist/EntityManager.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as EventRegistry } from './EventRegistry';
|
|
2
2
|
import { SparseSet } from './SparseSet';
|
|
3
3
|
import { default as World } from './World';
|
|
4
|
-
declare class Entity {
|
|
4
|
+
export declare class Entity {
|
|
5
5
|
readonly id: number;
|
|
6
6
|
private _world;
|
|
7
7
|
constructor(world: World, id: number);
|
|
@@ -30,18 +30,17 @@ declare class Entity {
|
|
|
30
30
|
get<T = any>(compType: string): T;
|
|
31
31
|
}
|
|
32
32
|
export declare class EntityManager extends EventRegistry<EntityManagerEvents> {
|
|
33
|
-
entityMap: SparseSet<
|
|
33
|
+
entityMap: SparseSet<number>;
|
|
34
34
|
nextId: number;
|
|
35
35
|
_world: World;
|
|
36
36
|
constructor(world: World);
|
|
37
|
-
get entities(): SparseSet<
|
|
38
|
-
create():
|
|
39
|
-
exist(
|
|
37
|
+
get entities(): SparseSet<number>;
|
|
38
|
+
create(): number;
|
|
39
|
+
exist(id: number): boolean;
|
|
40
40
|
size(): number;
|
|
41
|
-
destroy(
|
|
41
|
+
destroy(id: number): number;
|
|
42
42
|
}
|
|
43
43
|
export interface EntityManagerEvents {
|
|
44
|
-
create:
|
|
45
|
-
destroy:
|
|
44
|
+
create: number;
|
|
45
|
+
destroy: number;
|
|
46
46
|
}
|
|
47
|
-
export { type Entity };
|
package/dist/EventRegistry.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
export type Event<
|
|
2
|
-
|
|
1
|
+
export type Event<V> = {
|
|
2
|
+
[key: string]: V;
|
|
3
|
+
};
|
|
4
|
+
export type EventCallback<V> = (event: V[keyof V]) => void;
|
|
5
|
+
export default class EventRegistry<E extends Event<any> = {}> {
|
|
3
6
|
private _listeners;
|
|
4
|
-
on(type: keyof E, callback:
|
|
5
|
-
off(type: keyof E, callback:
|
|
6
|
-
once(type: keyof E, callback:
|
|
7
|
+
on(type: keyof E, callback: EventCallback<E>): void;
|
|
8
|
+
off(type: keyof E, callback: EventCallback<E>): void;
|
|
9
|
+
once(type: keyof E, callback: EventCallback<E>): void;
|
|
7
10
|
clearEvent(type: keyof E): void;
|
|
8
11
|
clearAllEvents(): void;
|
|
9
|
-
contains(type: keyof E, callback:
|
|
12
|
+
contains(type: keyof E, callback: EventCallback<E>): boolean;
|
|
10
13
|
emit(type: keyof E, data: E[keyof E]): void;
|
|
11
14
|
}
|
package/dist/Query.d.ts
CHANGED
|
@@ -7,16 +7,21 @@ export interface QueryConfig {
|
|
|
7
7
|
exclude: string[];
|
|
8
8
|
}
|
|
9
9
|
export interface QueryEvents {
|
|
10
|
-
added:
|
|
11
|
-
removed:
|
|
10
|
+
added: number;
|
|
11
|
+
removed: number;
|
|
12
12
|
}
|
|
13
13
|
export declare class Query extends EventRegistry<QueryEvents> {
|
|
14
|
-
config
|
|
15
|
-
entityMap
|
|
16
|
-
|
|
14
|
+
private config;
|
|
15
|
+
private entityMap;
|
|
16
|
+
private entityInstancesCache;
|
|
17
|
+
private world;
|
|
17
18
|
constructor(config: QueryConfig, world: World);
|
|
18
|
-
hasComponents(
|
|
19
|
-
|
|
19
|
+
hasComponents(entityId: number): boolean;
|
|
20
|
+
size(): number;
|
|
21
|
+
get hash(): number;
|
|
22
|
+
get ids(): SparseSet<number>;
|
|
23
|
+
private getCachedEntity;
|
|
24
|
+
get entities(): Entity[];
|
|
20
25
|
include(...comps: string[]): Query;
|
|
21
26
|
exclude(...comps: string[]): Query;
|
|
22
27
|
private _checkExistingEntities;
|
package/dist/World.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentManager, ComponentSchema } from './ComponentManager';
|
|
2
|
-
import {
|
|
2
|
+
import { Entity, EntityManager } from './EntityManager';
|
|
3
3
|
import { default as EventRegistry } from './EventRegistry';
|
|
4
4
|
import { Query, QueryConfig } from './Query';
|
|
5
5
|
import { SparseSet } from './SparseSet';
|
|
@@ -27,17 +27,19 @@ export default class World extends EventRegistry<WorldEvents> {
|
|
|
27
27
|
systemManager: SystemManager;
|
|
28
28
|
queries: Map<number, Query>;
|
|
29
29
|
constructor();
|
|
30
|
-
|
|
30
|
+
getEntity(id: number): Entity | undefined;
|
|
31
|
+
get entityIds(): SparseSet<number>;
|
|
31
32
|
query(config: QueryConfig): Query;
|
|
32
33
|
private _updateQueries;
|
|
33
|
-
exist(
|
|
34
|
+
exist(entityId: number): boolean;
|
|
34
35
|
include(...comps: string[]): Query;
|
|
35
36
|
exclude(...comps: string[]): Query;
|
|
36
|
-
create():
|
|
37
|
-
destroy(
|
|
37
|
+
create(): number;
|
|
38
|
+
destroy(entityId: number): void;
|
|
38
39
|
addSystem(sys: System): void;
|
|
39
40
|
removeSystem(sys: System): void;
|
|
40
|
-
addComponent(
|
|
41
|
-
|
|
41
|
+
addComponent(entityId: number, compKey: string, compValue: any): void;
|
|
42
|
+
getComponent<T>(entityId: number, compKey: string): T;
|
|
43
|
+
removeComponent(entityId: number, compKey: string): void;
|
|
42
44
|
update(): void;
|
|
43
45
|
}
|
package/dist/jael-build.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class o{_listeners=new Map;on(e,t){if(this.contains(e,t))return;const s=this._listeners.get(e);s?s.add(t):this._listeners.set(e,new Set([t]))}off(e,t){if(!this.contains(e,t))return;const s=this._listeners.get(e);s&&s.delete(t)}once(e,t){const s=(
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class o{_listeners=new Map;on(e,t){if(this.contains(e,t))return;const s=this._listeners.get(e);s?s.add(t):this._listeners.set(e,new Set([t]))}off(e,t){if(!this.contains(e,t))return;const s=this._listeners.get(e);s&&s.delete(t)}once(e,t){const s=(n=>{t(n),this.off(e,s)});this.on(e,s)}clearEvent(e){this._listeners.get(e)&&this._listeners.get(e)?.clear()}clearAllEvents(){this._listeners.forEach(e=>e.clear()),this._listeners.clear()}contains(e,t){return this._listeners.get(e)?this._listeners.get(e).has(t):!1}emit(e,t){this._listeners.get(e)&&this._listeners.get(e)?.forEach(s=>{s(t)})}}class u{systemList=[];addSystem(e){this.systemList.push(e),e.init?.(),this.reorder()}reorder(){this.systemList.sort((e,t)=>e.priority-t.priority)}has(e){return this.systemList.indexOf(e)>0}removeSystem(e){if(!this.has(e))return;const t=this.systemList.indexOf(e);t>=0&&(this.systemList.splice(t,1),e.exit?.(),this.reorder())}}class d{denseValues=[];sparse=new Map;[Symbol.iterator](){let e=this.values.length;const t={value:void 0,done:!1};return{next:()=>(t.value=this.values[--e],t.done=e<0,t)}}get values(){return this.denseValues}first(){return this.denseValues[0]}add(e){this.has(e)||(this.denseValues.push(e),this.sparse.set(e,this.denseValues.length-1))}indexOf(e){const t=this.sparse.get(e);return t!==void 0?t:-1}remove(e){if(!this.has(e))return;const t=this.sparse.get(e);this.sparse.delete(e);const s=this.denseValues[this.denseValues.length-1];s!==e&&(this.denseValues[t]=s,this.sparse.set(s,t)),this.denseValues.pop()}forEach(e){for(let t of this)e(t)}size(){return this.denseValues.length}clear(){for(let e of this)this.remove(e)}has(e){return this.sparse.has(e)}}class a{id;_world;constructor(e,t){this.id=t,this._world=e}add(e,t){this._world.addComponent(this.id,e,t)}remove(e){this._world.removeComponent(this.id,e)}has(e){return this._world.componentManager.hasComponent(this.id,e)}get(e){return this._world.componentManager.getComponent(this.id,e)}}class l extends o{entityMap=new d;nextId=0;_world;constructor(e){super(),this._world=e}get entities(){return this.entityMap}create(){const e=this.nextId++;return this.entities.add(e),this.emit("create",e),e}exist(e){return this.entities.has(e)}size(){return this.entities.size()}destroy(e){return this.entities.remove(e),this.emit("destroy",e),e}}class m extends o{componentSet={};world;constructor(e){super(),this.world=e}clearComponentSchema(e){this.componentSet[e]&&delete this.componentSet[e]}addComponent(e,t,s){if(!this.world.exist(e))return;const n=this.componentSet[e];n?n[t]=s:this.componentSet[e]={[t]:s},this.emit("add",{entityId:e,component:t})}getComponent(e,t){if(this.hasComponent(e,t))return this.componentSet[e][t]}hasComponent(e,t){const s=this.componentSet[e];return s?t in s:!1}removeComponent(e,t){if(!this.componentSet[e])return;const s=this.componentSet[e];s&&s[t]!==void 0&&(delete s[t],Object.keys(s).length===0&&delete this.componentSet[e],this.emit("remove",{entityId:e,component:t}))}}class c extends o{config;entityMap;entityInstancesCache;world;constructor(e,t){super(),this.config=e,this.world=t,this.entityInstancesCache=new Map,this.entityMap=new d,this.on("removed",s=>{this.entityInstancesCache.delete(s)})}hasComponents(e){const t=this.world.componentManager;return this.config.include?.every(s=>t.getComponent(e,s))&&this.config.exclude?.every(s=>!t.getComponent(e,s))}size(){return this.ids.size()}get hash(){return c.getHash(this.config)}get ids(){return this.entityMap}getCachedEntity(e){const t=this.entityInstancesCache.get(e);if(t)return t;{const s=this.world.getEntity(e);return s?(this.entityInstancesCache.set(e,s),s):void 0}}get entities(){const e=[],t=this.entityMap.size()>100;return this.entityMap.forEach(s=>{if(t){const n=this.getCachedEntity(s);n&&e.push(n)}else{const n=this.world.getEntity(s);n&&e.push(n)}}),e}include(...e){return this.world.include(...e)}exclude(...e){return this.world.exclude(...e)}_checkExistingEntities(){for(let e of this.ids)this.world.exist(e)||(this.emit("removed",e),this.entityMap.remove(e))}checkEntities(){this.entityInstancesCache.clear();for(let e of this.world.entityIds)this.hasComponents(e)&&(this.entityMap.add(e),this.emit("added",e));this._checkExistingEntities()}static getHash(e){const t=e.include?.map(i=>i.trim()).filter(i=>i).join("_"),s=e.exclude?.map(i=>i.trim()).filter(i=>i).join("_"),n="in_"+t+"_out_"+s;let h=0;for(const i of n)h=(h<<5)-h+i.charCodeAt(0),h|=0;return h}}class p extends o{_startTime=0;_oldTime=0;_requestId=0;running=!1;delta=0;elapsed=0;constructor(){super()}_loop(){let e=0;if(this.running){const t=performance.now();e=(t-this._oldTime)/1e3,this._oldTime=t,this.elapsed+=e}this.delta=e,this.emit("update"),this._requestId=requestAnimationFrame(this._loop.bind(this))}start(){this._startTime=performance.now(),this._oldTime=this._startTime,this.elapsed=0,this.delta=0,this.running=!0,this._loop()}stop(){this.running=!1,cancelAnimationFrame(this._requestId),this._requestId=0}}let g=new p;class f extends o{entityManager;componentManager;systemManager;queries;constructor(){super(),this.entityManager=new l(this),this.componentManager=new m(this),this.systemManager=new u,this.entityManager.on("create",e=>{this.emit("entityCreated",{entity:new a(this,e)}),this._updateQueries()}),this.entityManager.on("destroy",e=>{this.emit("entityDestroyed",{entity:new a(this,e)}),this._updateQueries(),this.componentManager.clearComponentSchema(e)}),this.componentManager.on("add",({entityId:e,component:t})=>{this.emit("componentAdded",{entity:new a(this,e),component:t}),this._updateQueries()}),this.componentManager.on("remove",({entityId:e,component:t})=>{this.getEntity(e)&&this.emit("componentRemoved",{entity:new a(this,e),component:t}),this._updateQueries()}),this.queries=new Map}getEntity(e){return this.exist(e)?new a(this,e):void 0}get entityIds(){return this.entityManager.entities}query(e){const t=c.getHash(e);let n=this.queries.get(t);return n||(n=new c(e,this),this.queries.set(t,n),this._updateQueries()),n}_updateQueries(){this.queries.forEach(e=>e.checkEntities())}exist(e){return this.entityManager.exist(e)}include(...e){return this.query({include:e,exclude:[]})}exclude(...e){return this.query({include:[],exclude:e})}create(){return this.entityManager.create()}destroy(e){this.entityManager.destroy(e)}addSystem(e){this.systemManager.addSystem(e)}removeSystem(e){this.systemManager.removeSystem(e)}addComponent(e,t,s){this.componentManager.addComponent(e,t,s)}getComponent(e,t){return this.componentManager.getComponent(e,t)}removeComponent(e,t){this.componentManager.removeComponent(e,t)}update(){this.systemManager.systemList.forEach(e=>{e.update()}),this.emit("updated")}}exports.ComponentManager=m;exports.EntityManager=l;exports.EventRegistry=o;exports.Query=c;exports.SparseSet=d;exports.SystemManager=u;exports.Time=g;exports.World=f;
|
package/dist/jael-build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class a {
|
|
2
2
|
_listeners = /* @__PURE__ */ new Map();
|
|
3
3
|
on(e, t) {
|
|
4
4
|
if (this.contains(e, t))
|
|
@@ -13,8 +13,8 @@ class h {
|
|
|
13
13
|
s && s.delete(t);
|
|
14
14
|
}
|
|
15
15
|
once(e, t) {
|
|
16
|
-
const s = ((
|
|
17
|
-
t(
|
|
16
|
+
const s = ((n) => {
|
|
17
|
+
t(n), this.off(e, s);
|
|
18
18
|
});
|
|
19
19
|
this.on(e, s);
|
|
20
20
|
}
|
|
@@ -33,7 +33,7 @@ class h {
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
class
|
|
36
|
+
class u {
|
|
37
37
|
systemList = [];
|
|
38
38
|
addSystem(e) {
|
|
39
39
|
this.systemList.push(e), e.init?.(), this.reorder();
|
|
@@ -73,7 +73,8 @@ class d {
|
|
|
73
73
|
this.has(e) || (this.denseValues.push(e), this.sparse.set(e, this.denseValues.length - 1));
|
|
74
74
|
}
|
|
75
75
|
indexOf(e) {
|
|
76
|
-
|
|
76
|
+
const t = this.sparse.get(e);
|
|
77
|
+
return t !== void 0 ? t : -1;
|
|
77
78
|
}
|
|
78
79
|
remove(e) {
|
|
79
80
|
if (!this.has(e)) return;
|
|
@@ -97,7 +98,7 @@ class d {
|
|
|
97
98
|
return this.sparse.has(e);
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
class
|
|
101
|
+
class h {
|
|
101
102
|
id;
|
|
102
103
|
_world;
|
|
103
104
|
constructor(e, t) {
|
|
@@ -109,14 +110,14 @@ class u {
|
|
|
109
110
|
* @param compValue Component value
|
|
110
111
|
*/
|
|
111
112
|
add(e, t) {
|
|
112
|
-
this._world.addComponent(this, e, t);
|
|
113
|
+
this._world.addComponent(this.id, e, t);
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
116
|
* Remove component of current entity.
|
|
116
117
|
* @param compType Component name
|
|
117
118
|
*/
|
|
118
119
|
remove(e) {
|
|
119
|
-
this._world.removeComponent(this, e);
|
|
120
|
+
this._world.removeComponent(this.id, e);
|
|
120
121
|
}
|
|
121
122
|
/**
|
|
122
123
|
* Check if current entity has a component.
|
|
@@ -124,7 +125,7 @@ class u {
|
|
|
124
125
|
* @returns boolean
|
|
125
126
|
*/
|
|
126
127
|
has(e) {
|
|
127
|
-
return this._world.componentManager.hasComponent(this, e);
|
|
128
|
+
return this._world.componentManager.hasComponent(this.id, e);
|
|
128
129
|
}
|
|
129
130
|
/**
|
|
130
131
|
* Get passed component schema of current entity.
|
|
@@ -132,10 +133,10 @@ class u {
|
|
|
132
133
|
* @returns Return component schema with T(any as default) as type
|
|
133
134
|
*/
|
|
134
135
|
get(e) {
|
|
135
|
-
return this._world.componentManager.getComponent(this, e);
|
|
136
|
+
return this._world.componentManager.getComponent(this.id, e);
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
|
-
class l extends
|
|
139
|
+
class l extends a {
|
|
139
140
|
entityMap = new d();
|
|
140
141
|
nextId = 0;
|
|
141
142
|
_world;
|
|
@@ -146,8 +147,8 @@ class l extends h {
|
|
|
146
147
|
return this.entityMap;
|
|
147
148
|
}
|
|
148
149
|
create() {
|
|
149
|
-
const e = this.nextId
|
|
150
|
-
return this.entities.add(
|
|
150
|
+
const e = this.nextId++;
|
|
151
|
+
return this.entities.add(e), this.emit("create", e), e;
|
|
151
152
|
}
|
|
152
153
|
exist(e) {
|
|
153
154
|
return this.entities.has(e);
|
|
@@ -159,47 +160,82 @@ class l extends h {
|
|
|
159
160
|
return this.entities.remove(e), this.emit("destroy", e), e;
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
|
-
class m extends
|
|
163
|
-
componentSet =
|
|
163
|
+
class m extends a {
|
|
164
|
+
componentSet = {};
|
|
164
165
|
world;
|
|
165
166
|
constructor(e) {
|
|
166
167
|
super(), this.world = e;
|
|
167
168
|
}
|
|
168
169
|
clearComponentSchema(e) {
|
|
169
|
-
this.componentSet
|
|
170
|
+
this.componentSet[e] && delete this.componentSet[e];
|
|
170
171
|
}
|
|
171
172
|
addComponent(e, t, s) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
175
|
-
i ? i[t] = s : this.componentSet.set(e.id, { [t]: s }), this.emit("add", { entity: e, component: t });
|
|
173
|
+
if (!this.world.exist(e)) return;
|
|
174
|
+
const n = this.componentSet[e];
|
|
175
|
+
n ? n[t] = s : this.componentSet[e] = { [t]: s }, this.emit("add", { entityId: e, component: t });
|
|
176
176
|
}
|
|
177
177
|
getComponent(e, t) {
|
|
178
|
-
|
|
178
|
+
if (this.hasComponent(e, t))
|
|
179
|
+
return this.componentSet[e][t];
|
|
179
180
|
}
|
|
180
181
|
hasComponent(e, t) {
|
|
181
|
-
const s = this.componentSet
|
|
182
|
+
const s = this.componentSet[e];
|
|
182
183
|
return s ? t in s : !1;
|
|
183
184
|
}
|
|
184
185
|
removeComponent(e, t) {
|
|
185
|
-
if (!this.componentSet
|
|
186
|
-
const s = this.componentSet
|
|
187
|
-
s && s[t] !== void 0 && (delete s[t], Object.keys(s).length === 0 && this.componentSet
|
|
186
|
+
if (!this.componentSet[e]) return;
|
|
187
|
+
const s = this.componentSet[e];
|
|
188
|
+
s && s[t] !== void 0 && (delete s[t], Object.keys(s).length === 0 && delete this.componentSet[e], this.emit("remove", { entityId: e, component: t }));
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
|
-
class
|
|
191
|
+
class c extends a {
|
|
191
192
|
config;
|
|
192
193
|
entityMap;
|
|
194
|
+
entityInstancesCache;
|
|
193
195
|
world;
|
|
194
196
|
constructor(e, t) {
|
|
195
|
-
super(), this.config = e, this.world = t, this.entityMap = new d()
|
|
197
|
+
super(), this.config = e, this.world = t, this.entityInstancesCache = /* @__PURE__ */ new Map(), this.entityMap = new d(), this.on("removed", (s) => {
|
|
198
|
+
this.entityInstancesCache.delete(s);
|
|
199
|
+
});
|
|
196
200
|
}
|
|
197
201
|
hasComponents(e) {
|
|
198
|
-
|
|
202
|
+
const t = this.world.componentManager;
|
|
203
|
+
return this.config.include?.every(
|
|
204
|
+
(s) => t.getComponent(e, s)
|
|
205
|
+
) && this.config.exclude?.every(
|
|
206
|
+
(s) => !t.getComponent(e, s)
|
|
207
|
+
);
|
|
199
208
|
}
|
|
200
|
-
|
|
209
|
+
size() {
|
|
210
|
+
return this.ids.size();
|
|
211
|
+
}
|
|
212
|
+
get hash() {
|
|
213
|
+
return c.getHash(this.config);
|
|
214
|
+
}
|
|
215
|
+
get ids() {
|
|
201
216
|
return this.entityMap;
|
|
202
217
|
}
|
|
218
|
+
getCachedEntity(e) {
|
|
219
|
+
const t = this.entityInstancesCache.get(e);
|
|
220
|
+
if (t)
|
|
221
|
+
return t;
|
|
222
|
+
{
|
|
223
|
+
const s = this.world.getEntity(e);
|
|
224
|
+
return s ? (this.entityInstancesCache.set(e, s), s) : void 0;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
get entities() {
|
|
228
|
+
const e = [], t = this.entityMap.size() > 100;
|
|
229
|
+
return this.entityMap.forEach((s) => {
|
|
230
|
+
if (t) {
|
|
231
|
+
const n = this.getCachedEntity(s);
|
|
232
|
+
n && e.push(n);
|
|
233
|
+
} else {
|
|
234
|
+
const n = this.world.getEntity(s);
|
|
235
|
+
n && e.push(n);
|
|
236
|
+
}
|
|
237
|
+
}), e;
|
|
238
|
+
}
|
|
203
239
|
include(...e) {
|
|
204
240
|
return this.world.include(...e);
|
|
205
241
|
}
|
|
@@ -207,23 +243,24 @@ class a extends h {
|
|
|
207
243
|
return this.world.exclude(...e);
|
|
208
244
|
}
|
|
209
245
|
_checkExistingEntities() {
|
|
210
|
-
for (let e of this.
|
|
246
|
+
for (let e of this.ids)
|
|
211
247
|
this.world.exist(e) || (this.emit("removed", e), this.entityMap.remove(e));
|
|
212
248
|
}
|
|
213
249
|
checkEntities() {
|
|
214
|
-
|
|
215
|
-
|
|
250
|
+
this.entityInstancesCache.clear();
|
|
251
|
+
for (let e of this.world.entityIds)
|
|
252
|
+
this.hasComponents(e) && (this.entityMap.add(e), this.emit("added", e));
|
|
216
253
|
this._checkExistingEntities();
|
|
217
254
|
}
|
|
218
255
|
static getHash(e) {
|
|
219
|
-
const t = e.include?.map((
|
|
256
|
+
const t = e.include?.map((i) => i.trim()).filter((i) => i).join("_"), s = e.exclude?.map((i) => i.trim()).filter((i) => i).join("_"), n = "in_" + t + "_out_" + s;
|
|
220
257
|
let o = 0;
|
|
221
|
-
for (const
|
|
222
|
-
o = (o << 5) - o +
|
|
258
|
+
for (const i of n)
|
|
259
|
+
o = (o << 5) - o + i.charCodeAt(0), o |= 0;
|
|
223
260
|
return o;
|
|
224
261
|
}
|
|
225
262
|
}
|
|
226
|
-
class p extends
|
|
263
|
+
class p extends a {
|
|
227
264
|
_startTime = 0;
|
|
228
265
|
_oldTime = 0;
|
|
229
266
|
_requestId = 0;
|
|
@@ -249,41 +286,42 @@ class p extends h {
|
|
|
249
286
|
}
|
|
250
287
|
}
|
|
251
288
|
let g = new p();
|
|
252
|
-
class f extends
|
|
289
|
+
class f extends a {
|
|
253
290
|
entityManager;
|
|
254
291
|
componentManager;
|
|
255
292
|
systemManager;
|
|
256
293
|
queries;
|
|
257
294
|
constructor() {
|
|
258
|
-
super(), this.entityManager = new l(this), this.componentManager = new m(this), this.systemManager = new
|
|
259
|
-
|
|
295
|
+
super(), this.entityManager = new l(this), this.componentManager = new m(this), this.systemManager = new u(), this.entityManager.on("create", (e) => {
|
|
296
|
+
this.emit("entityCreated", {
|
|
297
|
+
entity: new h(this, e)
|
|
298
|
+
}), this._updateQueries();
|
|
260
299
|
}), this.entityManager.on("destroy", (e) => {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
get entities() {
|
|
300
|
+
this.emit("entityDestroyed", {
|
|
301
|
+
entity: new h(this, e)
|
|
302
|
+
}), this._updateQueries(), this.componentManager.clearComponentSchema(e);
|
|
303
|
+
}), this.componentManager.on("add", ({ entityId: e, component: t }) => {
|
|
304
|
+
this.emit("componentAdded", {
|
|
305
|
+
entity: new h(this, e),
|
|
306
|
+
component: t
|
|
307
|
+
}), this._updateQueries();
|
|
308
|
+
}), this.componentManager.on("remove", ({ entityId: e, component: t }) => {
|
|
309
|
+
this.getEntity(e) && this.emit("componentRemoved", {
|
|
310
|
+
entity: new h(this, e),
|
|
311
|
+
component: t
|
|
312
|
+
}), this._updateQueries();
|
|
313
|
+
}), this.queries = /* @__PURE__ */ new Map();
|
|
314
|
+
}
|
|
315
|
+
getEntity(e) {
|
|
316
|
+
return this.exist(e) ? new h(this, e) : void 0;
|
|
317
|
+
}
|
|
318
|
+
get entityIds() {
|
|
281
319
|
return this.entityManager.entities;
|
|
282
320
|
}
|
|
283
321
|
query(e) {
|
|
284
|
-
const t =
|
|
285
|
-
let
|
|
286
|
-
return
|
|
322
|
+
const t = c.getHash(e);
|
|
323
|
+
let n = this.queries.get(t);
|
|
324
|
+
return n || (n = new c(e, this), this.queries.set(t, n), this._updateQueries()), n;
|
|
287
325
|
}
|
|
288
326
|
_updateQueries() {
|
|
289
327
|
this.queries.forEach((e) => e.checkEntities());
|
|
@@ -312,6 +350,9 @@ class f extends h {
|
|
|
312
350
|
addComponent(e, t, s) {
|
|
313
351
|
this.componentManager.addComponent(e, t, s);
|
|
314
352
|
}
|
|
353
|
+
getComponent(e, t) {
|
|
354
|
+
return this.componentManager.getComponent(e, t);
|
|
355
|
+
}
|
|
315
356
|
removeComponent(e, t) {
|
|
316
357
|
this.componentManager.removeComponent(e, t);
|
|
317
358
|
}
|
|
@@ -324,10 +365,10 @@ class f extends h {
|
|
|
324
365
|
export {
|
|
325
366
|
m as ComponentManager,
|
|
326
367
|
l as EntityManager,
|
|
327
|
-
|
|
328
|
-
|
|
368
|
+
a as EventRegistry,
|
|
369
|
+
c as Query,
|
|
329
370
|
d as SparseSet,
|
|
330
|
-
|
|
371
|
+
u as SystemManager,
|
|
331
372
|
g as Time,
|
|
332
373
|
f as World
|
|
333
374
|
};
|