diff --git a/packages/core/src/ECS/Core/FluentAPI/EntityBuilder.ts b/packages/core/src/ECS/Core/FluentAPI/EntityBuilder.ts index d3ec236e..f266b4c0 100644 --- a/packages/core/src/ECS/Core/FluentAPI/EntityBuilder.ts +++ b/packages/core/src/ECS/Core/FluentAPI/EntityBuilder.ts @@ -14,7 +14,9 @@ export class EntityBuilder { constructor(scene: IScene, storageManager: ComponentStorageManager) { this.scene = scene; this.storageManager = storageManager; - this.entity = new Entity("", scene.identifierPool.checkOut()); + const id = scene.identifierPool.checkOut(); + this.entity = new Entity("", id); + this.entity.scene = this.scene as any; } /** diff --git a/packages/core/src/ECS/Entity.ts b/packages/core/src/ECS/Entity.ts index 0360b2d9..41c5a69c 100644 --- a/packages/core/src/ECS/Entity.ts +++ b/packages/core/src/ECS/Entity.ts @@ -145,12 +145,6 @@ export class Entity { */ private _componentCache: Component[] | null = null; - /** - * 本地组件存储(用于没有 Scene 的 Entity) - * 当 Entity 添加到 Scene 时,组件会迁移到 Scene 的 componentStorageManager - */ - private _localComponents: Map = new Map(); - /** * 构造函数 * @@ -186,28 +180,23 @@ export class Entity { */ private _rebuildComponentCache(): void { const components: Component[] = []; - const mask = this._componentMask; + if (!this.scene?.componentStorageManager) { + this._componentCache = components; + return; + } + + const mask = this._componentMask; const maxBitIndex = ComponentRegistry.getRegisteredCount(); for (let bitIndex = 0; bitIndex < maxBitIndex; bitIndex++) { if (BitMask64Utils.getBit(mask, bitIndex)) { const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex); if (componentType) { - let component: Component | null = null; - - // 优先从 Scene 存储获取 - if (this.scene?.componentStorageManager) { - component = this.scene.componentStorageManager.getComponent( - this.id, - componentType - ); - } - - // Fallback 到本地存储 - if (!component) { - component = this._localComponents.get(componentType) || null; - } + const component = this.scene.componentStorageManager.getComponent( + this.id, + componentType + ); if (component) { components.push(component); @@ -378,9 +367,6 @@ export class Entity { ComponentRegistry.register(componentType); } - // 存储到本地 Map - this._localComponents.set(componentType, component); - // 更新位掩码 const componentMask = ComponentRegistry.getBitMask(componentType); BitMask64Utils.orInPlace(this._componentMask, componentMask); @@ -406,19 +392,25 @@ export class Entity { */ public addComponent(component: T): T { const componentType = component.constructor as ComponentType; - + + if (!this.scene) { + throw new Error(`Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()`); + } + + if (!this.scene.componentStorageManager) { + throw new Error(`Scene does not have componentStorageManager`); + } + if (this.hasComponent(componentType)) { throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`); } this.addComponentInternal(component); - - if (this.scene && this.scene.componentStorageManager) { - this.scene.componentStorageManager.addComponent(this.id, component); - } + + this.scene.componentStorageManager.addComponent(this.id, component); component.onAddedToEntity(); - + if (Entity.eventBus) { Entity.eventBus.emitComponentAdded({ timestamp: Date.now(), @@ -430,7 +422,7 @@ export class Entity { component: component }); } - + // 通知所有相关的QuerySystem组件已变动 Entity.notifyQuerySystems(this); @@ -459,16 +451,13 @@ export class Entity { return null; } - // 优先从 Scene 存储获取 - if (this.scene?.componentStorageManager) { - const component = this.scene.componentStorageManager.getComponent(this.id, type); - if (component) { - return component as T; - } + // 从Scene存储获取 + if (!this.scene?.componentStorageManager) { + return null; } - // Fallback 到本地存储 - return (this._localComponents.get(type) as T) || null; + const component = this.scene.componentStorageManager.getComponent(this.id, type); + return component as T | null; } @@ -538,17 +527,14 @@ export class Entity { const bitIndex = ComponentRegistry.getBitIndex(componentType); - // 从本地存储移除 - this._localComponents.delete(componentType); - // 更新位掩码 BitMask64Utils.clearBit(this._componentMask, bitIndex); // 使缓存失效 this._componentCache = null; - // 从 Scene 存储移除 - if (this.scene && this.scene.componentStorageManager) { + // 从Scene存储移除 + if (this.scene?.componentStorageManager) { this.scene.componentStorageManager.removeComponent(this.id, componentType); } @@ -593,9 +579,6 @@ export class Entity { public removeAllComponents(): void { const componentsToRemove = [...this.components]; - // 清除本地存储 - this._localComponents.clear(); - // 清除位掩码 BitMask64Utils.clear(this._componentMask); @@ -605,7 +588,7 @@ export class Entity { for (const component of componentsToRemove) { const componentType = component.constructor as ComponentType; - if (this.scene && this.scene.componentStorageManager) { + if (this.scene?.componentStorageManager) { this.scene.componentStorageManager.removeComponent(this.id, componentType); } diff --git a/packages/core/src/ECS/Serialization/EntitySerializer.ts b/packages/core/src/ECS/Serialization/EntitySerializer.ts index c502448f..d8705b12 100644 --- a/packages/core/src/ECS/Serialization/EntitySerializer.ts +++ b/packages/core/src/ECS/Serialization/EntitySerializer.ts @@ -8,6 +8,7 @@ import { Entity } from '../Entity'; import { Component } from '../Component'; import { ComponentType } from '../Core/ComponentStorage'; import { ComponentSerializer, SerializedComponent } from './ComponentSerializer'; +import { IScene } from '../IScene'; /** * 序列化后的实体数据 @@ -108,18 +109,25 @@ export class EntitySerializer { * @param componentRegistry 组件类型注册表 * @param idGenerator 实体ID生成器(用于生成新ID或保持原ID) * @param preserveIds 是否保持原始ID(默认false) + * @param scene 目标场景(可选,用于设置entity.scene以支持添加组件) * @returns 反序列化后的实体 */ public static deserialize( serializedEntity: SerializedEntity, componentRegistry: Map, idGenerator: () => number, - preserveIds: boolean = false + preserveIds: boolean = false, + scene?: IScene ): Entity { // 创建实体(使用原始ID或新生成的ID) const entityId = preserveIds ? serializedEntity.id : idGenerator(); const entity = new Entity(serializedEntity.name, entityId); + // 如果提供了scene,先设置entity.scene以支持添加组件 + if (scene) { + entity.scene = scene; + } + // 恢复实体属性 entity.tag = serializedEntity.tag; entity.active = serializedEntity.active; @@ -142,7 +150,8 @@ export class EntitySerializer { childData, componentRegistry, idGenerator, - preserveIds + preserveIds, + scene ); entity.addChild(childEntity); } @@ -181,13 +190,15 @@ export class EntitySerializer { * @param componentRegistry 组件类型注册表 * @param idGenerator 实体ID生成器 * @param preserveIds 是否保持原始ID + * @param scene 目标场景(可选,用于设置entity.scene以支持添加组件) * @returns 反序列化后的实体数组 */ public static deserializeEntities( serializedEntities: SerializedEntity[], componentRegistry: Map, idGenerator: () => number, - preserveIds: boolean = false + preserveIds: boolean = false, + scene?: IScene ): Entity[] { const result: Entity[] = []; @@ -196,7 +207,8 @@ export class EntitySerializer { serialized, componentRegistry, idGenerator, - preserveIds + preserveIds, + scene ); result.push(entity); } diff --git a/packages/core/src/ECS/Serialization/SceneSerializer.ts b/packages/core/src/ECS/Serialization/SceneSerializer.ts index 22d13f9f..985be925 100644 --- a/packages/core/src/ECS/Serialization/SceneSerializer.ts +++ b/packages/core/src/ECS/Serialization/SceneSerializer.ts @@ -269,7 +269,8 @@ export class SceneSerializer { serializedScene.entities, componentRegistry, idGenerator, - opts.preserveIds || false + opts.preserveIds || false, + scene ); // 将实体添加到场景 diff --git a/packages/core/tests/ECS/Component.test.ts b/packages/core/tests/ECS/Component.test.ts index 4531d15d..99529fe0 100644 --- a/packages/core/tests/ECS/Component.test.ts +++ b/packages/core/tests/ECS/Component.test.ts @@ -1,5 +1,6 @@ import { Component } from '../../src/ECS/Component'; import { Entity } from '../../src/ECS/Entity'; +import { Scene } from '../../src/ECS/Scene'; // 测试组件 class TestComponent extends Component { @@ -23,12 +24,13 @@ class AnotherTestComponent extends Component { describe('Component - 组件基类测试', () => { let component: TestComponent; let entity: Entity; + let scene: Scene; beforeEach(() => { - // Reset component ID generator to avoid BigInt issues Component._idGenerator = 0; component = new TestComponent(); - entity = new Entity('TestEntity', 1); + scene = new Scene(); + entity = scene.createEntity('TestEntity'); }); describe('基本功能', () => { diff --git a/packages/core/tests/ECS/Core/FluentAPI.test.ts b/packages/core/tests/ECS/Core/FluentAPI.test.ts index 4a98d2a5..b362a59d 100644 --- a/packages/core/tests/ECS/Core/FluentAPI.test.ts +++ b/packages/core/tests/ECS/Core/FluentAPI.test.ts @@ -568,9 +568,9 @@ describe('FluentAPI - 流式API测试', () => { let batchOp: EntityBatchOperator; beforeEach(() => { - entity1 = new Entity('Entity1', 1); - entity2 = new Entity('Entity2', 2); - entity3 = new Entity('Entity3', 3); + entity1 = scene.createEntity('Entity1'); + entity2 = scene.createEntity('Entity2'); + entity3 = scene.createEntity('Entity3'); batchOp = new EntityBatchOperator([entity1, entity2, entity3]); }); diff --git a/packages/core/tests/ECS/Core/QuerySystem.test.ts b/packages/core/tests/ECS/Core/QuerySystem.test.ts index 6e94b2fd..163859a0 100644 --- a/packages/core/tests/ECS/Core/QuerySystem.test.ts +++ b/packages/core/tests/ECS/Core/QuerySystem.test.ts @@ -2,6 +2,7 @@ import { QuerySystem, QueryBuilder, QueryConditionType } from '../../../src/ECS/ import { Entity } from '../../../src/ECS/Entity'; import { Component } from '../../../src/ECS/Component'; import { ComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage'; +import { Scene } from '../../../src/ECS/Scene'; // 测试组件 class PositionComponent extends Component { @@ -75,6 +76,7 @@ class PhysicsComponent extends Component { describe('QuerySystem - 查询系统测试', () => { let querySystem: QuerySystem; let entities: Entity[]; + let scene: Scene; let originalAddComponent: any; let originalRemoveComponent: any; let originalRemoveAllComponents: any; @@ -82,13 +84,14 @@ describe('QuerySystem - 查询系统测试', () => { beforeEach(() => { querySystem = new QuerySystem(); entities = []; + scene = new Scene(); // 创建测试实体 for (let i = 0; i < 10; i++) { - const entity = new Entity(`Entity_${i}`, i + 1); + const entity = scene.createEntity(`Entity_${i}`); entities.push(entity); } - + // 将实体添加到查询系统 querySystem.setEntities(entities); @@ -288,16 +291,12 @@ describe('QuerySystem - 查询系统测试', () => { // 创建大量具有相同组件组合的实体 for (let i = 0; i < entityCount; i++) { - const entity = new Entity(`PerfEntity_${i}`, i + 100); - testEntities.push(entity); - } - - // 先添加组件 - for (const entity of testEntities) { + const entity = scene.createEntity(`PerfEntity_${i}`); entity.addComponent(new PositionComponent(0, 0)); entity.addComponent(new VelocityComponent(1, 1)); + testEntities.push(entity); } - + // 将实体添加到查询系统 querySystem.setEntities([...entities, ...testEntities]); @@ -343,31 +342,27 @@ describe('QuerySystem - 查询系统测试', () => { const entityCount = 5000; const testEntities: Entity[] = []; - // 创建大量实体 + // 创建大量实体并分配组件 for (let i = 0; i < entityCount; i++) { - const entity = new Entity(`MaskEntity_${i}`, i + 200); - testEntities.push(entity); - } - - // 先随机分配组件 - for (let i = 0; i < entityCount; i++) { - const entity = testEntities[i]; - + const entity = scene.createEntity(`MaskEntity_${i}`); + entity.addComponent(new PositionComponent(i, i)); - + if (i % 2 === 0) { entity.addComponent(new VelocityComponent(1, 1)); } - + if (i % 3 === 0) { entity.addComponent(new HealthComponent(100)); } - + if (i % 5 === 0) { entity.addComponent(new RenderComponent(true)); } + + testEntities.push(entity); } - + // 将实体添加到查询系统 querySystem.setEntities([...entities, ...testEntities]); @@ -499,13 +494,13 @@ describe('QuerySystem - 查询系统测试', () => { // 创建大量实体 for (let i = 0; i < entityCount; i++) { - const entity = new Entity(`MemEntity_${i}`, i + 300); + const entity = scene.createEntity(`MemEntity_${i}`); entity.addComponent(new PositionComponent(i, i)); - + if (i % 2 === 0) { entity.addComponent(new VelocityComponent(1, 1)); } - + testEntities.push(entity); } @@ -785,7 +780,7 @@ describe('QuerySystem - 查询系统测试', () => { describe('实体管理功能', () => { test('应该能够添加和移除单个实体', () => { - const newEntity = new Entity('NewEntity', 999); + const newEntity = scene.createEntity('NewEntity'); querySystem.addEntity(newEntity); let stats = querySystem.getStats(); @@ -798,9 +793,9 @@ describe('QuerySystem - 查询系统测试', () => { test('应该能够批量添加实体', () => { const newEntities = [ - new Entity('Batch1', 997), - new Entity('Batch2', 998), - new Entity('Batch3', 999) + scene.createEntity('Batch1'), + scene.createEntity('Batch2'), + scene.createEntity('Batch3') ]; querySystem.addEntities(newEntities); @@ -810,8 +805,8 @@ describe('QuerySystem - 查询系统测试', () => { test('应该能够批量添加实体(无重复检查)', () => { const newEntities = [ - new Entity('Unchecked1', 995), - new Entity('Unchecked2', 996) + scene.createEntity('Unchecked1'), + scene.createEntity('Unchecked2') ]; querySystem.addEntitiesUnchecked(newEntities); @@ -846,43 +841,34 @@ describe('QuerySystem - 查询系统测试', () => { }); describe('组件变动同步问题测试', () => { - test('没有Scene时组件变动不会自动同步(符合ECS架构)', () => { + test('Entity必须有Scene才能添加组件', () => { // 创建一个独立的QuerySystem和实体 const independentQuerySystem = new QuerySystem(); - const testEntity = new Entity('TestEntity', 9999); + const testEntity = scene.createEntity('TestEntity'); - // 确保实体没有scene - expect(testEntity.scene).toBe(null); + // Entity现在必须有scene + expect(testEntity.scene).toBeTruthy(); // 添加实体到查询系统 independentQuerySystem.addEntity(testEntity); - // 初始查询:应该没有PositionComponent的实体 - const result1 = independentQuerySystem.queryAll(PositionComponent); - expect(result1.entities.length).toBe(0); - - // 添加组件,但没有Scene,不会自动同步 + // 添加组件 testEntity.addComponent(new PositionComponent(100, 200)); - // 查询系统不知道组件变化(这是预期行为) - const result2 = independentQuerySystem.queryAll(PositionComponent); - expect(result2.entities.length).toBe(0); // 查询系统没有自动更新 - expect(testEntity.hasComponent(PositionComponent)).toBe(true); // 但实体确实有这个组件 - // 手动同步后应该能找到 independentQuerySystem.updateEntity(testEntity); - const result3 = independentQuerySystem.queryAll(PositionComponent); - expect(result3.entities.length).toBe(1); - expect(result3.entities[0]).toBe(testEntity); + const result = independentQuerySystem.queryAll(PositionComponent); + expect(result.entities.length).toBe(1); + expect(result.entities[0]).toBe(testEntity); }); test('有Scene但没有querySystem时组件变动应该安全', () => { - const testEntity = new Entity('TestEntity2', 9998); + const testEntity = scene.createEntity('TestEntity2'); - // 模拟一个没有querySystem的scene + // 模拟一个没有querySystem的scene(但保留componentStorageManager) const mockScene = { querySystem: null, - componentStorageManager: null, + componentStorageManager: scene.componentStorageManager, clearSystemEntityCaches: jest.fn() }; testEntity.scene = mockScene as any; @@ -897,12 +883,12 @@ describe('QuerySystem - 查询系统测试', () => { test('有Scene时ArchetypeSystem组件变动能正确同步', () => { const independentQuerySystem = new QuerySystem(); - const testEntity = new Entity('ArchetypeTestEntity', 9997); + const testEntity = scene.createEntity('ArchetypeTestEntity'); - // 模拟Scene环境 + // 模拟Scene环境(保留componentStorageManager) const mockScene = { querySystem: independentQuerySystem, - componentStorageManager: null, + componentStorageManager: scene.componentStorageManager, clearSystemEntityCaches: jest.fn() }; testEntity.scene = mockScene as any; @@ -941,12 +927,12 @@ describe('QuerySystem - 查询系统测试', () => { test('有Scene时removeAllComponents应该正确同步QuerySystem', () => { const independentQuerySystem = new QuerySystem(); - const testEntity = new Entity('RemoveAllTestEntity', 9996); + const testEntity = scene.createEntity('RemoveAllTestEntity'); - // 模拟Scene环境 + // 模拟Scene环境(保留componentStorageManager) const mockScene = { querySystem: independentQuerySystem, - componentStorageManager: null, + componentStorageManager: scene.componentStorageManager, clearSystemEntityCaches: jest.fn() }; testEntity.scene = mockScene as any; @@ -978,7 +964,7 @@ describe('QuerySystem - 查询系统测试', () => { test('手动同步updateEntity应该工作正常', () => { const independentQuerySystem = new QuerySystem(); - const testEntity = new Entity('ManualSyncTestEntity', 9995); + const testEntity = scene.createEntity('ManualSyncTestEntity'); independentQuerySystem.addEntity(testEntity); @@ -1002,9 +988,9 @@ describe('QuerySystem - 查询系统测试', () => { const querySystem = new QuerySystem(); // 创建带组件的实体 - const entity1 = new Entity('BatchEntity1', 8001); - const entity2 = new Entity('BatchEntity2', 8002); - const entity3 = new Entity('BatchEntity3', 8003); + const entity1 = scene.createEntity('BatchEntity1'); + const entity2 = scene.createEntity('BatchEntity2'); + const entity3 = scene.createEntity('BatchEntity3'); entity1.addComponent(new PositionComponent(10, 20)); entity2.addComponent(new PositionComponent(30, 40)); @@ -1053,9 +1039,9 @@ describe('QuerySystem - 查询系统测试', () => { describe('组件掩码字符串索引', () => { test('应该为不同的组件组合生成不同的掩码字符串', () => { // 创建具有不同组件组合的实体 - const entity1 = new Entity('Entity1', 101); - const entity2 = new Entity('Entity2', 102); - const entity3 = new Entity('Entity3', 103); + const entity1 = scene.createEntity('Entity1'); + const entity2 = scene.createEntity('Entity2'); + const entity3 = scene.createEntity('Entity3'); entity1.addComponent(new PositionComponent(1, 1)); entity2.addComponent(new VelocityComponent(2, 2)); @@ -1071,22 +1057,22 @@ describe('QuerySystem - 查询系统测试', () => { const withBoth = querySystem.queryAll(PositionComponent, VelocityComponent); // entity1 应该在 withPosition 中 - expect(withPosition.entities.some(e => e.id === 101)).toBe(true); + expect(withPosition.entities).toContain(entity1); // entity2 应该在 withVelocity 中 - expect(withVelocity.entities.some(e => e.id === 102)).toBe(true); + expect(withVelocity.entities).toContain(entity2); // entity3 应该在所有查询中(因为它包含 Position 和 Velocity) - expect(withPosition.entities.some(e => e.id === 103)).toBe(true); - expect(withVelocity.entities.some(e => e.id === 103)).toBe(true); - expect(withBoth.entities.some(e => e.id === 103)).toBe(true); + expect(withPosition.entities).toContain(entity3); + expect(withVelocity.entities).toContain(entity3); + expect(withBoth.entities).toContain(entity3); // withBoth 只应该包含同时有两个组件的实体 - expect(withBoth.entities.some(e => e.id === 101)).toBe(false); // 只有 Position - expect(withBoth.entities.some(e => e.id === 102)).toBe(false); // 只有 Velocity + expect(withBoth.entities).not.toContain(entity1); // 只有 Position + expect(withBoth.entities).not.toContain(entity2); // 只有 Velocity }); test('相同组件组合的实体应该使用相同的掩码索引', () => { - const entity1 = new Entity('Entity1', 201); - const entity2 = new Entity('Entity2', 202); + const entity1 = scene.createEntity('Entity1'); + const entity2 = scene.createEntity('Entity2'); // 两个实体都有相同的组件组合 entity1.addComponent(new PositionComponent(1, 1)); @@ -1101,8 +1087,8 @@ describe('QuerySystem - 查询系统测试', () => { // 查询应该同时返回这两个实体 const result = querySystem.queryAll(PositionComponent, VelocityComponent); - expect(result.entities.some(e => e.id === 201)).toBe(true); - expect(result.entities.some(e => e.id === 202)).toBe(true); + expect(result.entities).toContain(entity1); + expect(result.entities).toContain(entity2); }); }); }); \ No newline at end of file diff --git a/packages/core/tests/ECS/Entity.test.ts b/packages/core/tests/ECS/Entity.test.ts index ab4833c7..8993c306 100644 --- a/packages/core/tests/ECS/Entity.test.ts +++ b/packages/core/tests/ECS/Entity.test.ts @@ -1,5 +1,6 @@ import { Entity } from '../../src/ECS/Entity'; import { Component } from '../../src/ECS/Component'; +import { Scene } from '../../src/ECS/Scene'; // 测试组件类 class TestPositionComponent extends Component { @@ -48,17 +49,19 @@ class TestRenderComponent extends Component { describe('Entity - 组件缓存优化测试', () => { let entity: Entity; + let scene: Scene; beforeEach(() => { - // 创建新的实体 - entity = new Entity('TestEntity', 1); + scene = new Scene(); + entity = scene.createEntity('TestEntity'); }); describe('基本功能测试', () => { test('应该能够创建实体', () => { expect(entity.name).toBe('TestEntity'); - expect(entity.id).toBe(1); + expect(entity.id).toBeGreaterThanOrEqual(0); expect(entity.components.length).toBe(0); + expect(entity.scene).toBe(scene); }); test('应该能够添加组件', () => { @@ -262,7 +265,7 @@ describe('Entity - 组件缓存优化测试', () => { const debugInfo = entity.getDebugInfo(); expect(debugInfo.name).toBe('TestEntity'); - expect(debugInfo.id).toBe(1); + expect(debugInfo.id).toBeGreaterThanOrEqual(0); expect(debugInfo.componentCount).toBe(2); expect(debugInfo.componentTypes).toContain('TestPositionComponent'); expect(debugInfo.componentTypes).toContain('TestHealthComponent'); diff --git a/packages/core/tests/ECS/Serialization/Serialization.test.ts b/packages/core/tests/ECS/Serialization/Serialization.test.ts index 5f2272e9..d9f7652b 100644 --- a/packages/core/tests/ECS/Serialization/Serialization.test.ts +++ b/packages/core/tests/ECS/Serialization/Serialization.test.ts @@ -82,6 +82,8 @@ class NonSerializableComponent extends Component { } describe('ECS Serialization System', () => { + let scene: Scene; + beforeEach(() => { // 清空测试环境 ComponentRegistry.reset(); @@ -91,6 +93,9 @@ describe('ECS Serialization System', () => { ComponentRegistry.register(VelocityComponent); ComponentRegistry.register(PlayerComponent); ComponentRegistry.register(HealthComponent); + + // 创建测试场景 + scene = new Scene(); }); describe('Component Serialization', () => { @@ -185,22 +190,22 @@ describe('ECS Serialization System', () => { describe('Entity Serialization', () => { it('should serialize an entity with components', () => { - const entity = new Entity('Player', 1); + const entity = scene.createEntity('Player'); entity.addComponent(new PositionComponent(50, 100)); entity.addComponent(new VelocityComponent()); entity.tag = 10; const serialized = EntitySerializer.serialize(entity); - expect(serialized.id).toBe(1); + expect(serialized.id).toBe(entity.id); expect(serialized.name).toBe('Player'); expect(serialized.tag).toBe(10); expect(serialized.components.length).toBe(2); }); it('should serialize entity hierarchy', () => { - const parent = new Entity('Parent', 1); - const child = new Entity('Child', 2); + const parent = scene.createEntity('Parent'); + const child = scene.createEntity('Child'); parent.addComponent(new PositionComponent(0, 0)); child.addComponent(new PositionComponent(10, 10)); @@ -209,7 +214,7 @@ describe('ECS Serialization System', () => { const serialized = EntitySerializer.serialize(parent); expect(serialized.children.length).toBe(1); - expect(serialized.children[0].id).toBe(2); + expect(serialized.children[0].id).toBe(child.id); expect(serialized.children[0].name).toBe('Child'); }); @@ -237,7 +242,8 @@ describe('ECS Serialization System', () => { serializedEntity, registry, () => idCounter++, - false + false, + scene ); expect(entity.name).toBe('TestEntity'); diff --git a/packages/core/tests/ECS/Systems/EntitySystem.test.ts b/packages/core/tests/ECS/Systems/EntitySystem.test.ts index 0c47cbce..073bfe3f 100644 --- a/packages/core/tests/ECS/Systems/EntitySystem.test.ts +++ b/packages/core/tests/ECS/Systems/EntitySystem.test.ts @@ -90,7 +90,7 @@ describe('EntitySystem', () => { beforeEach(() => { scene = new Scene(); system = new ConcreteEntitySystem(); - entity = new Entity('test_entity', 1); + entity = scene.createEntity('test_entity'); entity.addComponent(new TestComponent(10)); scene.addEntity(entity); diff --git a/packages/core/tests/ECS/Systems/SystemTypes.test.ts b/packages/core/tests/ECS/Systems/SystemTypes.test.ts index 18ac9c69..94c815ce 100644 --- a/packages/core/tests/ECS/Systems/SystemTypes.test.ts +++ b/packages/core/tests/ECS/Systems/SystemTypes.test.ts @@ -1,3 +1,4 @@ +import { Scene } from '../../../src/ECS/Scene'; import { PassiveSystem } from '../../../src/ECS/Systems/PassiveSystem'; import { IntervalSystem } from '../../../src/ECS/Systems/IntervalSystem'; import { ProcessingSystem } from '../../../src/ECS/Systems/ProcessingSystem'; @@ -78,10 +79,12 @@ class ConcreteProcessingSystem extends ProcessingSystem { } describe('System Types - 系统类型测试', () => { + let scene: Scene; let entity: Entity; beforeEach(() => { - entity = new Entity('TestEntity', 1); + scene = new Scene(); + entity = scene.createEntity('TestEntity'); // 重置时间系统 Time.update(0.016); // 注册测试组件类型 @@ -282,10 +285,10 @@ describe('System Types - 系统类型测试', () => { const interval = new ConcreteIntervalSystem(0.1); const processing = new ConcreteProcessingSystem(); - const matchingEntity = new Entity('Matching', 1); + const matchingEntity = scene.createEntity('Matching'); matchingEntity.addComponent(new TestComponent(100)); - const nonMatchingEntity = new Entity('NonMatching', 2); + const nonMatchingEntity = scene.createEntity('NonMatching'); nonMatchingEntity.addComponent(new AnotherComponent('test')); // 所有系统都应该匹配TestComponent diff --git a/packages/core/tests/ECS/Utils/ComponentSparseSet.test.ts b/packages/core/tests/ECS/Utils/ComponentSparseSet.test.ts index 2e9ea30c..4ce5b11e 100644 --- a/packages/core/tests/ECS/Utils/ComponentSparseSet.test.ts +++ b/packages/core/tests/ECS/Utils/ComponentSparseSet.test.ts @@ -1,6 +1,7 @@ import { ComponentSparseSet } from '../../../src/ECS/Utils/ComponentSparseSet'; import { Entity } from '../../../src/ECS/Entity'; import { Component } from '../../../src/ECS/Component'; +import { Scene } from '../../../src/ECS/Scene'; // 测试组件类 class PositionComponent extends Component { @@ -32,20 +33,21 @@ describe('ComponentSparseSet', () => { let entity1: Entity; let entity2: Entity; let entity3: Entity; + let scene: Scene; beforeEach(() => { componentSparseSet = new ComponentSparseSet(); - - // 创建测试实体 - entity1 = new Entity('entity1', 1); + scene = new Scene(); + + entity1 = scene.createEntity('entity1'); entity1.addComponent(new PositionComponent(10, 20)); entity1.addComponent(new VelocityComponent(1, 2)); - - entity2 = new Entity('entity2', 2); + + entity2 = scene.createEntity('entity2'); entity2.addComponent(new PositionComponent(30, 40)); entity2.addComponent(new HealthComponent(80, 100)); - - entity3 = new Entity('entity3', 3); + + entity3 = scene.createEntity('entity3'); entity3.addComponent(new VelocityComponent(3, 4)); entity3.addComponent(new HealthComponent(50, 100)); entity3.addComponent(new RenderComponent(true)); @@ -358,16 +360,16 @@ describe('ComponentSparseSet', () => { // 创建大量实体 for (let i = 0; i < 1000; i++) { - const entity = new Entity(`entity${i}`, i); + const entity = scene.createEntity(`entity${i}`); entity.addComponent(new PositionComponent(i, i)); - + if (i % 2 === 0) { entity.addComponent(new VelocityComponent(1, 1)); } if (i % 3 === 0) { entity.addComponent(new HealthComponent(100, 100)); } - + entities.push(entity); componentSparseSet.addEntity(entity); }