@codehz/ecs 0.1.3 → 0.1.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 +3 -0
- package/changeset.d.ts +0 -4
- package/index.js +22 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -171,6 +171,8 @@ bun run examples/simple/demo.ts
|
|
|
171
171
|
|
|
172
172
|
- `new()`: 创建新实体
|
|
173
173
|
- `set(entity, componentId, data)`: 向实体添加组件
|
|
174
|
+
- `get(entity, componentId)`: 获取实体的组件数据(注意:只能获取已设置的组件,使用前请先用 `has()` 检查组件是否存在)
|
|
175
|
+
- `has(entity, componentId)`: 检查实体是否拥有指定组件
|
|
174
176
|
- `delete(entity, componentId)`: 从实体移除组件
|
|
175
177
|
- `setExclusive(componentId)`: 将组件标记为独占关系
|
|
176
178
|
- `createQuery(componentIds)`: 创建查询
|
|
@@ -251,6 +253,7 @@ const restored = World.deserialize(readySnapshot);
|
|
|
251
253
|
|
|
252
254
|
注意事项
|
|
253
255
|
|
|
256
|
+
- **重要警告**:`get()` 方法只能获取实体已设置的组件。如果尝试获取不存在的组件,会抛出错误。由于 `undefined` 是组件的有效值,不能使用 `get()` 的返回值是否为 `undefined` 来判断组件是否存在。请在使用 `get()` 之前先用 `has()` 方法检查组件是否存在。
|
|
254
257
|
- 快照只包含实体、组件、以及 `EntityIdManager` 的分配器状态(用于保留下一次分配的 ID);并不会自动恢复已注册的系统、查询缓存或生命周期钩子。恢复后应由应用负责重新注册系统与钩子。
|
|
255
258
|
- 若需要跨版本兼容,建议在持久化格式中包含 `version` 字段,并在恢复时进行格式兼容性检查与迁移。
|
|
256
259
|
|
package/changeset.d.ts
CHANGED
|
@@ -29,8 +29,4 @@ export declare class ComponentChangeset {
|
|
|
29
29
|
* Apply the changeset to existing components and return the final state
|
|
30
30
|
*/
|
|
31
31
|
applyTo(existingComponents: Map<EntityId<any>, any>): Map<EntityId<any>, any>;
|
|
32
|
-
/**
|
|
33
|
-
* Get the final component types after applying changes
|
|
34
|
-
*/
|
|
35
|
-
getFinalComponentTypes(existingComponents: Map<EntityId<any>, any>): EntityId<any>[];
|
|
36
32
|
}
|
package/index.js
CHANGED
|
@@ -277,17 +277,23 @@ class Archetype {
|
|
|
277
277
|
if (index === undefined) {
|
|
278
278
|
return;
|
|
279
279
|
}
|
|
280
|
-
this.entities.splice(index, 1);
|
|
281
|
-
this.entityToIndex.delete(entityId);
|
|
282
280
|
const removedData = new Map;
|
|
283
281
|
for (const componentType of this.componentTypes) {
|
|
284
282
|
const dataArray = this.getComponentData(componentType);
|
|
285
|
-
removedData.set(componentType, dataArray[index]);
|
|
286
|
-
dataArray.splice(index, 1);
|
|
283
|
+
removedData.set(componentType, dataArray[index] === MISSING_COMPONENT ? undefined : dataArray[index]);
|
|
287
284
|
}
|
|
288
|
-
|
|
289
|
-
|
|
285
|
+
const lastIndex = this.entities.length - 1;
|
|
286
|
+
if (index !== lastIndex) {
|
|
287
|
+
const lastEntity = this.entities[lastIndex];
|
|
288
|
+
this.entities[index] = lastEntity;
|
|
289
|
+
this.entityToIndex.set(lastEntity, index);
|
|
290
|
+
for (const componentType of this.componentTypes) {
|
|
291
|
+
const dataArray = this.getComponentData(componentType);
|
|
292
|
+
[dataArray[index], dataArray[lastIndex]] = [dataArray[lastIndex], dataArray[index]];
|
|
293
|
+
}
|
|
290
294
|
}
|
|
295
|
+
this.entities.pop();
|
|
296
|
+
this.entityToIndex.delete(entityId);
|
|
291
297
|
return removedData;
|
|
292
298
|
}
|
|
293
299
|
exists(entityId) {
|
|
@@ -439,10 +445,6 @@ class ComponentChangeset {
|
|
|
439
445
|
}
|
|
440
446
|
return finalComponents;
|
|
441
447
|
}
|
|
442
|
-
getFinalComponentTypes(existingComponents) {
|
|
443
|
-
const finalComponents = this.applyTo(existingComponents);
|
|
444
|
-
return Array.from(finalComponents.keys()).sort((a, b) => a - b);
|
|
445
|
-
}
|
|
446
448
|
}
|
|
447
449
|
|
|
448
450
|
// src/command-buffer.ts
|
|
@@ -790,6 +792,12 @@ class World {
|
|
|
790
792
|
if (!archetype) {
|
|
791
793
|
throw new Error(`Entity ${entityId} does not exist`);
|
|
792
794
|
}
|
|
795
|
+
const detailedType = getDetailedIdType(componentType);
|
|
796
|
+
if (detailedType.type !== "wildcard-relation") {
|
|
797
|
+
if (!archetype.componentTypes.includes(componentType)) {
|
|
798
|
+
throw new Error(`Entity ${entityId} does not have component ${componentType}. Use has() to check component existence before calling get().`);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
793
801
|
return archetype.get(entityId, componentType);
|
|
794
802
|
}
|
|
795
803
|
registerSystem(system) {
|
|
@@ -989,11 +997,10 @@ class World {
|
|
|
989
997
|
}
|
|
990
998
|
}
|
|
991
999
|
const finalComponents = changeset.applyTo(currentComponents);
|
|
992
|
-
const
|
|
993
|
-
const
|
|
994
|
-
const needsArchetypeChange = finalComponentTypes.length !== currentComponentTypes.length || !finalComponentTypes.every((type, index) => type === currentComponentTypes[index]);
|
|
1000
|
+
const currentComponentTypes = currentArchetype.componentTypes;
|
|
1001
|
+
const needsArchetypeChange = finalComponents.size !== currentComponentTypes.length || !currentComponentTypes.every((type) => finalComponents.has(type));
|
|
995
1002
|
if (needsArchetypeChange) {
|
|
996
|
-
const newArchetype = this.ensureArchetype(
|
|
1003
|
+
const newArchetype = this.ensureArchetype(finalComponents.keys().toArray());
|
|
997
1004
|
currentArchetype.removeEntity(entityId);
|
|
998
1005
|
newArchetype.addEntity(entityId, finalComponents);
|
|
999
1006
|
this.entityToArchetype.set(entityId, newArchetype);
|
|
@@ -1024,7 +1031,7 @@ class World {
|
|
|
1024
1031
|
return changeset;
|
|
1025
1032
|
}
|
|
1026
1033
|
ensureArchetype(componentTypes) {
|
|
1027
|
-
const sortedTypes =
|
|
1034
|
+
const sortedTypes = componentTypes.toSorted((a, b) => a - b);
|
|
1028
1035
|
const hashKey = this.createArchetypeSignature(sortedTypes);
|
|
1029
1036
|
return getOrCreateWithSideEffect(this.archetypeBySignature, hashKey, () => {
|
|
1030
1037
|
const newArchetype = new Archetype(sortedTypes);
|