@codehz/ecs 0.1.5 → 0.1.7
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 +3 -3
- package/index.js +18 -15
- package/package.json +1 -1
- package/system-scheduler.d.ts +3 -1
- package/world.d.ts +1 -1
package/README.md
CHANGED
|
@@ -176,7 +176,7 @@ bun run examples/simple/demo.ts
|
|
|
176
176
|
- `delete(entity, componentId)`: 从实体移除组件
|
|
177
177
|
- `setExclusive(componentId)`: 将组件标记为独占关系
|
|
178
178
|
- `createQuery(componentIds)`: 创建查询
|
|
179
|
-
- `registerSystem(system)`: 注册系统
|
|
179
|
+
- `registerSystem(system, dependencies?)`: 注册系统
|
|
180
180
|
- `registerLifecycleHook(componentId, hook)`: 注册组件或通配符关系生命周期钩子
|
|
181
181
|
- `unregisterLifecycleHook(componentId, hook)`: 注销组件或通配符关系生命周期钩子
|
|
182
182
|
- `update(...params)`: 更新世界(参数取决于泛型配置)
|
|
@@ -289,7 +289,7 @@ class MovementSystem implements System<[deltaTime: number]> {
|
|
|
289
289
|
}
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
|
|
292
|
+
系统支持依赖关系排序,确保正确的执行顺序。依赖关系可以通过系统的 `dependencies` 属性指定:
|
|
293
293
|
|
|
294
294
|
```typescript
|
|
295
295
|
class InputSystem implements System<[deltaTime: number]> {
|
|
@@ -314,7 +314,7 @@ class MovementSystem implements System<[deltaTime: number]> {
|
|
|
314
314
|
// 注册系统
|
|
315
315
|
const inputSystem = new InputSystem();
|
|
316
316
|
world.registerSystem(inputSystem);
|
|
317
|
-
world.registerSystem(new MovementSystem(inputSystem));
|
|
317
|
+
world.registerSystem(new MovementSystem(inputSystem), [inputSystem]); // 也可以在注册时指定额外依赖
|
|
318
318
|
```
|
|
319
319
|
|
|
320
320
|
系统将按照拓扑排序执行,依赖系统始终在被依赖系统之前运行。
|
package/index.js
CHANGED
|
@@ -280,8 +280,9 @@ class Archetype {
|
|
|
280
280
|
const removedData = new Map;
|
|
281
281
|
for (const componentType of this.componentTypes) {
|
|
282
282
|
const dataArray = this.getComponentData(componentType);
|
|
283
|
-
removedData.set(componentType, dataArray[index]
|
|
283
|
+
removedData.set(componentType, dataArray[index]);
|
|
284
284
|
}
|
|
285
|
+
this.entityToIndex.delete(entityId);
|
|
285
286
|
const lastIndex = this.entities.length - 1;
|
|
286
287
|
if (index !== lastIndex) {
|
|
287
288
|
const lastEntity = this.entities[lastIndex];
|
|
@@ -289,11 +290,13 @@ class Archetype {
|
|
|
289
290
|
this.entityToIndex.set(lastEntity, index);
|
|
290
291
|
for (const componentType of this.componentTypes) {
|
|
291
292
|
const dataArray = this.getComponentData(componentType);
|
|
292
|
-
|
|
293
|
+
dataArray[index] = dataArray[lastIndex];
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
296
|
this.entities.pop();
|
|
296
|
-
this.
|
|
297
|
+
for (const componentType of this.componentTypes) {
|
|
298
|
+
this.getComponentData(componentType).pop();
|
|
299
|
+
}
|
|
297
300
|
return removedData;
|
|
298
301
|
}
|
|
299
302
|
exists(entityId) {
|
|
@@ -436,14 +439,13 @@ class ComponentChangeset {
|
|
|
436
439
|
}
|
|
437
440
|
}
|
|
438
441
|
applyTo(existingComponents) {
|
|
439
|
-
const finalComponents = new Map(existingComponents);
|
|
440
442
|
for (const componentType of this.removes) {
|
|
441
|
-
|
|
443
|
+
existingComponents.delete(componentType);
|
|
442
444
|
}
|
|
443
445
|
for (const [componentType, component2] of this.adds) {
|
|
444
|
-
|
|
446
|
+
existingComponents.set(componentType, component2);
|
|
445
447
|
}
|
|
446
|
-
return
|
|
448
|
+
return existingComponents;
|
|
447
449
|
}
|
|
448
450
|
}
|
|
449
451
|
|
|
@@ -615,12 +617,14 @@ class Query {
|
|
|
615
617
|
// src/system-scheduler.ts
|
|
616
618
|
class SystemScheduler {
|
|
617
619
|
systems = new Set;
|
|
620
|
+
systemDependencies = new Map;
|
|
618
621
|
cachedExecutionOrder = null;
|
|
619
|
-
addSystem(system) {
|
|
622
|
+
addSystem(system, additionalDeps = []) {
|
|
620
623
|
this.systems.add(system);
|
|
621
624
|
for (const dep of system.dependencies || []) {
|
|
622
625
|
this.systems.add(dep);
|
|
623
626
|
}
|
|
627
|
+
this.systemDependencies.set(system, new Set([...additionalDeps, ...system.dependencies || []]));
|
|
624
628
|
this.cachedExecutionOrder = null;
|
|
625
629
|
}
|
|
626
630
|
getExecutionOrder() {
|
|
@@ -637,7 +641,7 @@ class SystemScheduler {
|
|
|
637
641
|
throw new Error("Circular dependency detected in system scheduling");
|
|
638
642
|
}
|
|
639
643
|
visiting.add(system);
|
|
640
|
-
for (const dep of system
|
|
644
|
+
for (const dep of this.systemDependencies.get(system) || []) {
|
|
641
645
|
visit(dep);
|
|
642
646
|
}
|
|
643
647
|
visiting.delete(system);
|
|
@@ -734,8 +738,7 @@ class World {
|
|
|
734
738
|
currentComponents.set(archetypeComponentType, componentData);
|
|
735
739
|
}
|
|
736
740
|
}
|
|
737
|
-
const
|
|
738
|
-
const newArchetype = this.ensureArchetype(newComponentTypes);
|
|
741
|
+
const newArchetype = this.ensureArchetype(currentComponents.keys());
|
|
739
742
|
sourceArchetype.removeEntity(sourceEntityId);
|
|
740
743
|
if (sourceArchetype.getEntities().length === 0) {
|
|
741
744
|
this.cleanupEmptyArchetype(sourceArchetype);
|
|
@@ -800,8 +803,8 @@ class World {
|
|
|
800
803
|
}
|
|
801
804
|
return archetype.get(entityId, componentType);
|
|
802
805
|
}
|
|
803
|
-
registerSystem(system) {
|
|
804
|
-
this.systemScheduler.addSystem(system);
|
|
806
|
+
registerSystem(system, additionalDeps = []) {
|
|
807
|
+
this.systemScheduler.addSystem(system, additionalDeps);
|
|
805
808
|
}
|
|
806
809
|
registerLifecycleHook(componentType, hook) {
|
|
807
810
|
if (!this.lifecycleHooks.has(componentType)) {
|
|
@@ -1000,7 +1003,7 @@ class World {
|
|
|
1000
1003
|
const currentComponentTypes = currentArchetype.componentTypes;
|
|
1001
1004
|
const needsArchetypeChange = finalComponents.size !== currentComponentTypes.length || !currentComponentTypes.every((type) => finalComponents.has(type));
|
|
1002
1005
|
if (needsArchetypeChange) {
|
|
1003
|
-
const newArchetype = this.ensureArchetype(finalComponents.keys()
|
|
1006
|
+
const newArchetype = this.ensureArchetype(finalComponents.keys());
|
|
1004
1007
|
currentArchetype.removeEntity(entityId);
|
|
1005
1008
|
newArchetype.addEntity(entityId, finalComponents);
|
|
1006
1009
|
this.entityToArchetype.set(entityId, newArchetype);
|
|
@@ -1031,7 +1034,7 @@ class World {
|
|
|
1031
1034
|
return changeset;
|
|
1032
1035
|
}
|
|
1033
1036
|
ensureArchetype(componentTypes) {
|
|
1034
|
-
const sortedTypes = componentTypes.
|
|
1037
|
+
const sortedTypes = Array.from(componentTypes).sort((a, b) => a - b);
|
|
1035
1038
|
const hashKey = this.createArchetypeSignature(sortedTypes);
|
|
1036
1039
|
return getOrCreateWithSideEffect(this.archetypeBySignature, hashKey, () => {
|
|
1037
1040
|
const newArchetype = new Archetype(sortedTypes);
|
package/package.json
CHANGED
package/system-scheduler.d.ts
CHANGED
|
@@ -4,12 +4,14 @@ import type { System } from "./system";
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class SystemScheduler<UpdateParams extends any[] = [deltaTime: number]> {
|
|
6
6
|
private systems;
|
|
7
|
+
private systemDependencies;
|
|
7
8
|
private cachedExecutionOrder;
|
|
8
9
|
/**
|
|
9
10
|
* Add a system with optional dependencies
|
|
10
11
|
* @param system The system to add
|
|
12
|
+
* @param additionalDeps Additional dependencies for the system
|
|
11
13
|
*/
|
|
12
|
-
addSystem(system: System<UpdateParams>): void;
|
|
14
|
+
addSystem(system: System<UpdateParams>, additionalDeps?: System<UpdateParams>[]): void;
|
|
13
15
|
/**
|
|
14
16
|
* Get the execution order of systems based on dependencies
|
|
15
17
|
* Uses topological sort
|
package/world.d.ts
CHANGED
|
@@ -94,7 +94,7 @@ export declare class World<UpdateParams extends any[] = []> {
|
|
|
94
94
|
/**
|
|
95
95
|
* Register a system with optional dependencies
|
|
96
96
|
*/
|
|
97
|
-
registerSystem(system: System<UpdateParams>): void;
|
|
97
|
+
registerSystem(system: System<UpdateParams>, additionalDeps?: System<UpdateParams>[]): void;
|
|
98
98
|
/**
|
|
99
99
|
* Register a lifecycle hook for component or wildcard relation events
|
|
100
100
|
*/
|