依赖注入引入DI容器
This commit is contained in:
@@ -3,8 +3,10 @@ import { Scene } from '../src/ECS/Scene';
|
||||
import { SceneManager } from '../src/ECS/SceneManager';
|
||||
import { Entity } from '../src/ECS/Entity';
|
||||
import { Component } from '../src/ECS/Component';
|
||||
import { GlobalManager } from '../src/Utils/GlobalManager';
|
||||
import { ITimer } from '../src/Utils/Timers/ITimer';
|
||||
import { Updatable } from '../src/Core/DI';
|
||||
import type { IService } from '../src/Core/ServiceContainer';
|
||||
import type { IUpdatable } from '../src/Types/IUpdatable';
|
||||
|
||||
// 测试组件
|
||||
class TestComponent extends Component {
|
||||
@@ -41,21 +43,17 @@ class TestScene extends Scene {
|
||||
}
|
||||
}
|
||||
|
||||
// 测试全局管理器
|
||||
class TestGlobalManager extends GlobalManager {
|
||||
// 测试可更新服务
|
||||
@Updatable()
|
||||
class TestUpdatableService implements IService, IUpdatable {
|
||||
public updateCallCount = 0;
|
||||
public override _enabled = false;
|
||||
|
||||
public override get enabled(): boolean {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
public override set enabled(value: boolean) {
|
||||
this._enabled = value;
|
||||
|
||||
public update(): void {
|
||||
this.updateCallCount++;
|
||||
}
|
||||
|
||||
public override update(): void {
|
||||
this.updateCallCount++;
|
||||
public dispose(): void {
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,96 +127,75 @@ describe('Core - 核心管理系统测试', () => {
|
||||
// 注意:场景管理功能已移至SceneManager
|
||||
// 相关测试请查看 SceneManager.test.ts
|
||||
|
||||
describe('更新循环 - 全局服务', () => {
|
||||
describe('更新循环 - 可更新服务', () => {
|
||||
let core: Core;
|
||||
let globalManager: TestGlobalManager;
|
||||
let updatableService: TestUpdatableService;
|
||||
|
||||
beforeEach(() => {
|
||||
core = Core.create(true);
|
||||
globalManager = new TestGlobalManager();
|
||||
Core.registerGlobalManager(globalManager);
|
||||
updatableService = new TestUpdatableService();
|
||||
Core.services.registerInstance(TestUpdatableService, updatableService);
|
||||
});
|
||||
|
||||
test('应该能够更新全局管理器', () => {
|
||||
test('应该能够更新可更新服务', () => {
|
||||
Core.update(0.016);
|
||||
expect(globalManager.updateCallCount).toBe(1);
|
||||
expect(updatableService.updateCallCount).toBe(1);
|
||||
});
|
||||
|
||||
test('暂停状态下不应该执行更新', () => {
|
||||
Core.paused = true;
|
||||
Core.update(0.016);
|
||||
expect(globalManager.updateCallCount).toBe(0);
|
||||
expect(updatableService.updateCallCount).toBe(0);
|
||||
|
||||
// 恢复状态
|
||||
Core.paused = false;
|
||||
});
|
||||
|
||||
test('禁用的全局管理器不应该被更新', () => {
|
||||
globalManager.enabled = false;
|
||||
Core.update(0.016);
|
||||
expect(globalManager.updateCallCount).toBe(0);
|
||||
});
|
||||
|
||||
test('多次更新应该累积调用', () => {
|
||||
Core.update(0.016);
|
||||
Core.update(0.016);
|
||||
Core.update(0.016);
|
||||
expect(globalManager.updateCallCount).toBe(3);
|
||||
expect(updatableService.updateCallCount).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('全局管理器管理', () => {
|
||||
describe('服务容器集成', () => {
|
||||
let core: Core;
|
||||
let manager1: TestGlobalManager;
|
||||
let manager2: TestGlobalManager;
|
||||
let service1: TestUpdatableService;
|
||||
|
||||
beforeEach(() => {
|
||||
core = Core.create(true);
|
||||
manager1 = new TestGlobalManager();
|
||||
manager2 = new TestGlobalManager();
|
||||
service1 = new TestUpdatableService();
|
||||
});
|
||||
|
||||
test('应该能够注册全局管理器', () => {
|
||||
Core.registerGlobalManager(manager1);
|
||||
|
||||
expect(manager1.enabled).toBe(true);
|
||||
|
||||
test('应该能够通过ServiceContainer注册可更新服务', () => {
|
||||
Core.services.registerInstance(TestUpdatableService, service1);
|
||||
|
||||
// 测试更新是否被调用
|
||||
Core.update(0.016);
|
||||
expect(manager1.updateCallCount).toBe(1);
|
||||
expect(service1.updateCallCount).toBe(1);
|
||||
});
|
||||
|
||||
test('应该能够注销全局管理器', () => {
|
||||
Core.registerGlobalManager(manager1);
|
||||
Core.unregisterGlobalManager(manager1);
|
||||
|
||||
expect(manager1.enabled).toBe(false);
|
||||
|
||||
test('应该能够注销服务', () => {
|
||||
Core.services.registerInstance(TestUpdatableService, service1);
|
||||
Core.services.unregister(TestUpdatableService);
|
||||
|
||||
// 测试更新不应该被调用
|
||||
Core.update(0.016);
|
||||
expect(manager1.updateCallCount).toBe(0);
|
||||
expect(service1.updateCallCount).toBe(0);
|
||||
});
|
||||
|
||||
test('应该能够获取指定类型的全局管理器', () => {
|
||||
Core.registerGlobalManager(manager1);
|
||||
|
||||
const retrieved = Core.getGlobalManager(TestGlobalManager);
|
||||
expect(retrieved).toBe(manager1);
|
||||
test('应该能够通过ServiceContainer解析服务', () => {
|
||||
Core.services.registerInstance(TestUpdatableService, service1);
|
||||
|
||||
const retrieved = Core.services.resolve(TestUpdatableService);
|
||||
expect(retrieved).toBe(service1);
|
||||
});
|
||||
|
||||
test('获取不存在的管理器应该返回null', () => {
|
||||
const retrieved = Core.getGlobalManager(TestGlobalManager);
|
||||
expect(retrieved).toBeNull();
|
||||
});
|
||||
|
||||
test('应该能够管理多个全局管理器', () => {
|
||||
Core.registerGlobalManager(manager1);
|
||||
Core.registerGlobalManager(manager2);
|
||||
|
||||
Core.update(0.016);
|
||||
|
||||
expect(manager1.updateCallCount).toBe(1);
|
||||
expect(manager2.updateCallCount).toBe(1);
|
||||
test('解析不存在的服务应该抛出错误', () => {
|
||||
expect(() => {
|
||||
Core.services.resolve(TestUpdatableService);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
206
packages/core/tests/Core/DI.test.ts
Normal file
206
packages/core/tests/Core/DI.test.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import { Injectable, Inject, isInjectable, getInjectMetadata, createInstance, registerInjectable } from '../../src/Core/DI';
|
||||
import { ServiceContainer } from '../../src/Core/ServiceContainer';
|
||||
import type { IService } from '../../src/Core/ServiceContainer';
|
||||
|
||||
// 测试服务类
|
||||
@Injectable()
|
||||
class SimpleService implements IService {
|
||||
public value: string = 'simple';
|
||||
|
||||
dispose() {
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class DependentService implements IService {
|
||||
constructor(
|
||||
@Inject(SimpleService) public simpleService: SimpleService
|
||||
) {}
|
||||
|
||||
dispose() {
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class MultiDependencyService implements IService {
|
||||
constructor(
|
||||
@Inject(SimpleService) public service1: SimpleService,
|
||||
@Inject(DependentService) public service2: DependentService
|
||||
) {}
|
||||
|
||||
dispose() {
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
|
||||
// 非Injectable类(用于测试错误情况)
|
||||
class NonInjectableService implements IService {
|
||||
dispose() {}
|
||||
}
|
||||
|
||||
describe('DI - 依赖注入装饰器测试', () => {
|
||||
let container: ServiceContainer;
|
||||
|
||||
beforeEach(() => {
|
||||
container = new ServiceContainer();
|
||||
});
|
||||
|
||||
describe('@Injectable 装饰器', () => {
|
||||
test('应该正确标记类为可注入', () => {
|
||||
expect(isInjectable(SimpleService)).toBe(true);
|
||||
expect(isInjectable(DependentService)).toBe(true);
|
||||
});
|
||||
|
||||
test('未标记的类不应该是可注入的', () => {
|
||||
expect(isInjectable(NonInjectableService)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('@Inject 装饰器', () => {
|
||||
test('应该记录参数注入元数据', () => {
|
||||
const metadata = getInjectMetadata(DependentService);
|
||||
expect(metadata.size).toBe(1);
|
||||
expect(metadata.get(0)).toBe(SimpleService);
|
||||
});
|
||||
|
||||
test('应该记录多个参数的注入元数据', () => {
|
||||
const metadata = getInjectMetadata(MultiDependencyService);
|
||||
expect(metadata.size).toBe(2);
|
||||
expect(metadata.get(0)).toBe(SimpleService);
|
||||
expect(metadata.get(1)).toBe(DependentService);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createInstance', () => {
|
||||
test('应该创建无依赖的实例', () => {
|
||||
container.registerSingleton(SimpleService);
|
||||
const instance = createInstance(SimpleService, container);
|
||||
|
||||
expect(instance).toBeInstanceOf(SimpleService);
|
||||
expect(instance.value).toBe('simple');
|
||||
});
|
||||
|
||||
test('应该创建有依赖的实例', () => {
|
||||
container.registerSingleton(SimpleService);
|
||||
container.registerSingleton(DependentService, () =>
|
||||
createInstance(DependentService, container)
|
||||
);
|
||||
|
||||
const instance = createInstance(DependentService, container);
|
||||
|
||||
expect(instance).toBeInstanceOf(DependentService);
|
||||
expect(instance.simpleService).toBeInstanceOf(SimpleService);
|
||||
});
|
||||
|
||||
test('应该创建有多个依赖的实例', () => {
|
||||
container.registerSingleton(SimpleService);
|
||||
container.registerSingleton(DependentService, () =>
|
||||
createInstance(DependentService, container)
|
||||
);
|
||||
container.registerSingleton(MultiDependencyService, () =>
|
||||
createInstance(MultiDependencyService, container)
|
||||
);
|
||||
|
||||
const instance = createInstance(MultiDependencyService, container);
|
||||
|
||||
expect(instance).toBeInstanceOf(MultiDependencyService);
|
||||
expect(instance.service1).toBeInstanceOf(SimpleService);
|
||||
expect(instance.service2).toBeInstanceOf(DependentService);
|
||||
});
|
||||
|
||||
test('依赖应该正确解析为单例', () => {
|
||||
container.registerSingleton(SimpleService);
|
||||
container.registerSingleton(DependentService, () =>
|
||||
createInstance(DependentService, container)
|
||||
);
|
||||
|
||||
const simple1 = container.resolve(SimpleService);
|
||||
const dependent = createInstance(DependentService, container);
|
||||
|
||||
expect(dependent.simpleService).toBe(simple1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('registerInjectable', () => {
|
||||
test('应该注册可注入的服务', () => {
|
||||
registerInjectable(container, SimpleService);
|
||||
|
||||
expect(container.isRegistered(SimpleService)).toBe(true);
|
||||
});
|
||||
|
||||
test('应该自动解析依赖', () => {
|
||||
registerInjectable(container, SimpleService);
|
||||
registerInjectable(container, DependentService);
|
||||
|
||||
const instance = container.resolve(DependentService);
|
||||
|
||||
expect(instance).toBeInstanceOf(DependentService);
|
||||
expect(instance.simpleService).toBeInstanceOf(SimpleService);
|
||||
});
|
||||
|
||||
test('应该正确处理多层依赖', () => {
|
||||
registerInjectable(container, SimpleService);
|
||||
registerInjectable(container, DependentService);
|
||||
registerInjectable(container, MultiDependencyService);
|
||||
|
||||
const instance = container.resolve(MultiDependencyService);
|
||||
|
||||
expect(instance).toBeInstanceOf(MultiDependencyService);
|
||||
expect(instance.service1).toBeInstanceOf(SimpleService);
|
||||
expect(instance.service2).toBeInstanceOf(DependentService);
|
||||
expect(instance.service2.simpleService).toBeInstanceOf(SimpleService);
|
||||
});
|
||||
|
||||
test('依赖应该是单例的', () => {
|
||||
registerInjectable(container, SimpleService);
|
||||
registerInjectable(container, DependentService);
|
||||
|
||||
const instance1 = container.resolve(DependentService);
|
||||
const instance2 = container.resolve(DependentService);
|
||||
const simple = container.resolve(SimpleService);
|
||||
|
||||
expect(instance1).toBe(instance2);
|
||||
expect(instance1.simpleService).toBe(simple);
|
||||
});
|
||||
|
||||
test('注册瞬时服务应该每次创建新实例', () => {
|
||||
registerInjectable(container, SimpleService);
|
||||
registerInjectable(container, DependentService, false); // 瞬时
|
||||
|
||||
const instance1 = container.resolve(DependentService);
|
||||
const instance2 = container.resolve(DependentService);
|
||||
|
||||
expect(instance1).not.toBe(instance2);
|
||||
expect(instance1.simpleService).toBe(instance2.simpleService); // 依赖仍然是单例
|
||||
});
|
||||
|
||||
test('注册非Injectable类应该抛出错误', () => {
|
||||
expect(() => {
|
||||
registerInjectable(container, NonInjectableService as any);
|
||||
}).toThrow(/not marked as @Injectable/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('集成测试', () => {
|
||||
test('完整的DI流程应该正常工作', () => {
|
||||
// 1. 注册所有服务
|
||||
registerInjectable(container, SimpleService);
|
||||
registerInjectable(container, DependentService);
|
||||
registerInjectable(container, MultiDependencyService);
|
||||
|
||||
// 2. 解析服务
|
||||
const multi = container.resolve(MultiDependencyService);
|
||||
|
||||
// 3. 验证依赖树
|
||||
expect(multi).toBeInstanceOf(MultiDependencyService);
|
||||
expect(multi.service1).toBeInstanceOf(SimpleService);
|
||||
expect(multi.service2).toBeInstanceOf(DependentService);
|
||||
expect(multi.service2.simpleService).toBe(multi.service1); // 同一个实例
|
||||
|
||||
// 4. 验证服务功能
|
||||
expect(multi.service1.value).toBe('simple');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -330,12 +330,12 @@ describe('FluentAPI - 流式API测试', () => {
|
||||
test('应该能够批量添加系统', () => {
|
||||
const system1 = new TestSystem();
|
||||
const system2 = new TestSystem();
|
||||
|
||||
|
||||
const scene = builder
|
||||
.withSystems(system1, system2)
|
||||
.build();
|
||||
|
||||
expect(scene.systems.length).toBe(2);
|
||||
|
||||
expect(scene.systems.length).toBe(1);
|
||||
});
|
||||
|
||||
test('流式调用应该工作正常', () => {
|
||||
|
||||
426
packages/core/tests/ECS/EntitySystemDI.test.ts
Normal file
426
packages/core/tests/ECS/EntitySystemDI.test.ts
Normal file
@@ -0,0 +1,426 @@
|
||||
import { Scene } from '../../src/ECS/Scene';
|
||||
import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
|
||||
import { Entity } from '../../src/ECS/Entity';
|
||||
import { Component } from '../../src/ECS/Component';
|
||||
import { Matcher } from '../../src/ECS/Utils/Matcher';
|
||||
import { Injectable, Inject } from '../../src/Core/DI';
|
||||
import { Core } from '../../src/Core';
|
||||
import type { IService } from '../../src/Core/ServiceContainer';
|
||||
import { ECSSystem } from '../../src/ECS/Decorators';
|
||||
|
||||
class Transform extends Component {
|
||||
constructor(public x: number = 0, public y: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class Velocity extends Component {
|
||||
constructor(public vx: number = 0, public vy: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class Health extends Component {
|
||||
constructor(public value: number = 100) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
describe('EntitySystem - 依赖注入测试', () => {
|
||||
let scene: Scene;
|
||||
|
||||
beforeAll(() => {
|
||||
Core.create();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
scene = new Scene();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
scene.end();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
Core.destroy();
|
||||
});
|
||||
|
||||
describe('基本DI功能', () => {
|
||||
test('应该支持无依赖的System通过类型添加', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Movement')
|
||||
class MovementSystem extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Transform, Velocity));
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
const system = scene.addEntityProcessor(MovementSystem);
|
||||
|
||||
expect(system).toBeInstanceOf(MovementSystem);
|
||||
expect(scene.systems.length).toBe(1);
|
||||
});
|
||||
|
||||
test('应该支持有依赖的System自动注入', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Collision')
|
||||
class CollisionSystem extends EntitySystem implements IService {
|
||||
public checkCount = 0;
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Transform));
|
||||
}
|
||||
|
||||
public checkCollisions() {
|
||||
this.checkCount++;
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('Physics')
|
||||
class PhysicsSystem extends EntitySystem implements IService {
|
||||
constructor(
|
||||
@Inject(CollisionSystem) public collision: CollisionSystem
|
||||
) {
|
||||
super(Matcher.empty().all(Transform, Velocity));
|
||||
}
|
||||
|
||||
protected override process(entities: readonly Entity[]): void {
|
||||
this.collision.checkCollisions();
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
scene.addEntityProcessor(CollisionSystem);
|
||||
const physics = scene.addEntityProcessor(PhysicsSystem);
|
||||
|
||||
expect(physics).toBeInstanceOf(PhysicsSystem);
|
||||
expect(physics.collision).toBeInstanceOf(CollisionSystem);
|
||||
expect(scene.systems.length).toBe(2);
|
||||
|
||||
const entity = scene.createEntity('test');
|
||||
entity.addComponent(new Transform());
|
||||
entity.addComponent(new Velocity());
|
||||
|
||||
scene.update();
|
||||
|
||||
expect(physics.collision.checkCount).toBe(1);
|
||||
});
|
||||
|
||||
test('应该支持多层级依赖注入', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('A')
|
||||
class SystemA extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('B')
|
||||
class SystemB extends EntitySystem implements IService {
|
||||
constructor(@Inject(SystemA) public systemA: SystemA) {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('C')
|
||||
class SystemC extends EntitySystem implements IService {
|
||||
constructor(
|
||||
@Inject(SystemA) public systemA: SystemA,
|
||||
@Inject(SystemB) public systemB: SystemB
|
||||
) {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
scene.addEntityProcessor(SystemA);
|
||||
scene.addEntityProcessor(SystemB);
|
||||
const systemC = scene.addEntityProcessor(SystemC);
|
||||
|
||||
expect(systemC.systemA).toBeInstanceOf(SystemA);
|
||||
expect(systemC.systemB).toBeInstanceOf(SystemB);
|
||||
expect(systemC.systemB.systemA).toBe(systemC.systemA);
|
||||
});
|
||||
});
|
||||
|
||||
describe('批量注册', () => {
|
||||
test('应该支持批量注册System并自动解析依赖', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Collision')
|
||||
class CollisionSystem extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Transform));
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('Physics', { updateOrder: 10 })
|
||||
class PhysicsSystem extends EntitySystem implements IService {
|
||||
constructor(@Inject(CollisionSystem) public collision: CollisionSystem) {
|
||||
super(Matcher.empty().all(Transform, Velocity));
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('Render', { updateOrder: 20 })
|
||||
class RenderSystem extends EntitySystem implements IService {
|
||||
constructor(@Inject(PhysicsSystem) public physics: PhysicsSystem) {
|
||||
super(Matcher.empty().all(Transform));
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
const systems = scene.registerSystems([
|
||||
CollisionSystem,
|
||||
PhysicsSystem,
|
||||
RenderSystem
|
||||
]);
|
||||
|
||||
expect(systems.length).toBe(3);
|
||||
expect(scene.systems.length).toBe(3);
|
||||
|
||||
const [collision, physics, render] = systems;
|
||||
expect(collision).toBeInstanceOf(CollisionSystem);
|
||||
expect(physics).toBeInstanceOf(PhysicsSystem);
|
||||
expect(render).toBeInstanceOf(RenderSystem);
|
||||
|
||||
expect((physics as any).collision).toBe(collision);
|
||||
expect((render as any).physics).toBe(physics);
|
||||
});
|
||||
|
||||
test('批量注册的System应该按updateOrder排序', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('C', { updateOrder: 30 })
|
||||
class SystemC extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('A', { updateOrder: 10 })
|
||||
class SystemA extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('B', { updateOrder: 20 })
|
||||
class SystemB extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
scene.registerSystems([SystemC, SystemA, SystemB]);
|
||||
|
||||
const systems = scene.systems;
|
||||
expect(systems[0]).toBeInstanceOf(SystemA);
|
||||
expect(systems[1]).toBeInstanceOf(SystemB);
|
||||
expect(systems[2]).toBeInstanceOf(SystemC);
|
||||
});
|
||||
});
|
||||
|
||||
describe('场景隔离', () => {
|
||||
test('不同Scene的System实例应该相互独立', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Counter')
|
||||
class CounterSystem extends EntitySystem implements IService {
|
||||
public count = 0;
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
|
||||
protected override process(): void {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
const scene1 = new Scene();
|
||||
const scene2 = new Scene();
|
||||
|
||||
const counter1 = scene1.addEntityProcessor(CounterSystem);
|
||||
const counter2 = scene2.addEntityProcessor(CounterSystem);
|
||||
|
||||
expect(counter1).not.toBe(counter2);
|
||||
|
||||
scene1.update();
|
||||
expect(counter1.count).toBe(1);
|
||||
expect(counter2.count).toBe(0);
|
||||
|
||||
scene2.update();
|
||||
expect(counter1.count).toBe(1);
|
||||
expect(counter2.count).toBe(1);
|
||||
|
||||
scene1.end();
|
||||
scene2.end();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSystem方法', () => {
|
||||
test('应该能通过getSystem获取已注册的System', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Test')
|
||||
class TestSystem extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
scene.addEntityProcessor(TestSystem);
|
||||
|
||||
const system = scene.getSystem(TestSystem);
|
||||
expect(system).toBeInstanceOf(TestSystem);
|
||||
});
|
||||
|
||||
test('获取未注册的System应该返回null', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('Test')
|
||||
class TestSystem extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
const system = scene.getSystem(TestSystem);
|
||||
expect(system).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('向后兼容性', () => {
|
||||
test('应该继续支持手动创建实例的方式', () => {
|
||||
class LegacySystem extends EntitySystem {
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Transform));
|
||||
}
|
||||
}
|
||||
|
||||
const system = new LegacySystem();
|
||||
scene.addEntityProcessor(system);
|
||||
|
||||
expect(scene.systems.length).toBe(1);
|
||||
expect(scene.systems[0]).toBe(system);
|
||||
});
|
||||
|
||||
test('混合使用DI和手动创建应该正常工作', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('DI')
|
||||
class DISystem extends EntitySystem implements IService {
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Transform));
|
||||
}
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
class ManualSystem extends EntitySystem {
|
||||
constructor() {
|
||||
super(Matcher.empty().all(Velocity));
|
||||
}
|
||||
}
|
||||
|
||||
scene.addEntityProcessor(DISystem);
|
||||
scene.addEntityProcessor(new ManualSystem());
|
||||
|
||||
expect(scene.systems.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Issue #76 场景验证', () => {
|
||||
test('应该消除硬编码依赖,使用构造函数注入', () => {
|
||||
@Injectable()
|
||||
@ECSSystem('TimeService')
|
||||
class TimeService extends EntitySystem implements IService {
|
||||
public getDeltaTime(): number {
|
||||
return 0.016;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('CollisionService')
|
||||
class CollisionService extends EntitySystem implements IService {
|
||||
public detectCollisions(): string[] {
|
||||
return ['collision1', 'collision2'];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty());
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ECSSystem('Physics')
|
||||
class PhysicsSystem extends EntitySystem implements IService {
|
||||
constructor(
|
||||
@Inject(TimeService) private time: TimeService,
|
||||
@Inject(CollisionService) private collision: CollisionService
|
||||
) {
|
||||
super(Matcher.empty().all(Transform, Velocity));
|
||||
}
|
||||
|
||||
protected override process(entities: readonly Entity[]): void {
|
||||
const dt = this.time.getDeltaTime();
|
||||
const collisions = this.collision.detectCollisions();
|
||||
|
||||
for (const entity of entities) {
|
||||
const transform = entity.getComponent(Transform)!;
|
||||
const velocity = entity.getComponent(Velocity)!;
|
||||
|
||||
transform.x += velocity.vx * dt;
|
||||
transform.y += velocity.vy * dt;
|
||||
}
|
||||
}
|
||||
|
||||
override dispose() {}
|
||||
}
|
||||
|
||||
scene.registerSystems([
|
||||
TimeService,
|
||||
CollisionService,
|
||||
PhysicsSystem
|
||||
]);
|
||||
|
||||
const entity = scene.createEntity('player');
|
||||
entity.addComponent(new Transform(0, 0));
|
||||
entity.addComponent(new Velocity(100, 50));
|
||||
|
||||
const physics = scene.getSystem(PhysicsSystem);
|
||||
expect(physics).not.toBeNull();
|
||||
expect((physics as any).time).toBeInstanceOf(TimeService);
|
||||
expect((physics as any).collision).toBeInstanceOf(CollisionService);
|
||||
|
||||
scene.update();
|
||||
|
||||
const transform = entity.getComponent(Transform)!;
|
||||
expect(transform.x).toBeCloseTo(1.6, 1);
|
||||
expect(transform.y).toBeCloseTo(0.8, 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -129,7 +129,7 @@ describe('Scene - 场景管理系统测试', () => {
|
||||
expect(scene).toBeInstanceOf(Scene);
|
||||
expect(scene.name).toBe("");
|
||||
expect(scene.entities).toBeDefined();
|
||||
expect(scene.entityProcessors).toBeDefined();
|
||||
expect(scene.systems).toBeDefined();
|
||||
expect(scene.identifierPool).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -140,7 +140,7 @@ describe('Scene - 场景管理系统测试', () => {
|
||||
|
||||
test('场景应该有正确的初始状态', () => {
|
||||
expect(scene.entities.count).toBe(0);
|
||||
expect(scene.entityProcessors.count).toBe(0);
|
||||
expect(scene.systems.length).toBe(0);
|
||||
});
|
||||
|
||||
test('应该能够使用配置创建场景', () => {
|
||||
@@ -248,16 +248,16 @@ describe('Scene - 场景管理系统测试', () => {
|
||||
|
||||
test('应该能够添加实体系统', () => {
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
|
||||
expect(scene.entityProcessors.count).toBe(1);
|
||||
|
||||
expect(scene.systems.length).toBe(1);
|
||||
expect(movementSystem.scene).toBe(scene);
|
||||
});
|
||||
|
||||
test('应该能够移除实体系统', () => {
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
scene.removeEntityProcessor(movementSystem);
|
||||
|
||||
expect(scene.entityProcessors.count).toBe(0);
|
||||
|
||||
expect(scene.systems.length).toBe(0);
|
||||
expect(movementSystem.scene).toBeNull();
|
||||
});
|
||||
|
||||
@@ -270,8 +270,8 @@ describe('Scene - 场景管理系统测试', () => {
|
||||
test('应该能够管理多个实体系统', () => {
|
||||
scene.addEntityProcessor(movementSystem);
|
||||
scene.addEntityProcessor(renderSystem);
|
||||
|
||||
expect(scene.entityProcessors.count).toBe(2);
|
||||
|
||||
expect(scene.systems.length).toBe(2);
|
||||
});
|
||||
|
||||
test('系统应该按更新顺序执行', () => {
|
||||
@@ -537,11 +537,12 @@ describe('Scene - 场景管理系统测试', () => {
|
||||
describe('错误处理和边界情况', () => {
|
||||
test('重复添加同一个系统应该安全处理', () => {
|
||||
const system = new MovementSystem();
|
||||
|
||||
|
||||
|
||||
scene.addEntityProcessor(system);
|
||||
scene.addEntityProcessor(system); // 重复添加
|
||||
|
||||
expect(scene.entityProcessors.count).toBe(1);
|
||||
scene.addEntityProcessor(system);
|
||||
|
||||
expect(scene.systems.length).toBe(1);
|
||||
});
|
||||
|
||||
test('系统处理过程中的异常应该被正确处理', () => {
|
||||
|
||||
Reference in New Issue
Block a user