依赖注入引入DI容器

This commit is contained in:
YHH
2025-10-10 21:52:43 +08:00
parent a1a6970ea4
commit b13132b259
19 changed files with 1529 additions and 231 deletions

View File

@@ -1,4 +1,3 @@
import { GlobalManager } from './Utils/GlobalManager';
import { TimerManager } from './Utils/Timers/TimerManager';
import { ITimer } from './Utils/Timers/ITimer';
import { Timer } from './Utils/Timers/Timer';
@@ -6,7 +5,7 @@ import { Time } from './Utils/Time';
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool/PoolManager';
import { DebugManager } from './Utils/Debug';
import { ICoreConfig, IECSDebugConfig } from './Types';
import { ICoreConfig, IECSDebugConfig, IUpdatable, isUpdatable } from './Types';
import { createLogger } from './Utils/Logger';
import { SceneManager } from './ECS/SceneManager';
import { IScene } from './ECS/IScene';
@@ -55,8 +54,10 @@ export class Core {
/**
* 全局核心实例
*
* 可能为null表示Core尚未初始化或已被销毁
*/
private static _instance: Core;
private static _instance: Core | null = null;
/**
* Core专用日志器
@@ -84,13 +85,6 @@ export class Core {
*/
private _serviceContainer: ServiceContainer;
/**
* 全局管理器集合
*
* 存储所有注册的全局管理器实例。
*/
public _globalManagers: GlobalManager[] = [];
/**
* 定时器管理器
*
@@ -151,7 +145,6 @@ export class Core {
// 初始化定时器管理器
this._timerManager = new TimerManager();
Core.registerGlobalManager(this._timerManager);
this._serviceContainer.registerInstance(TimerManager, this._timerManager);
// 初始化性能监控器
@@ -175,7 +168,13 @@ export class Core {
// 初始化调试管理器
if (this._config.debugConfig?.enabled) {
this._debugManager = new DebugManager(this, this._config.debugConfig);
// 使用DI容器创建DebugManager前两个参数从容器解析config手动传入
const config = this._config.debugConfig;
this._debugManager = new DebugManager(
this._serviceContainer.resolve(SceneManager),
this._serviceContainer.resolve(PerformanceMonitor),
config
);
this._serviceContainer.registerInstance(DebugManager, this._debugManager);
}
@@ -197,6 +196,7 @@ export class Core {
* 用于注册和解析自定义服务。
*
* @returns 服务容器实例
* @throws 如果Core实例未创建
*
* @example
* ```typescript
@@ -368,43 +368,6 @@ export class Core {
this._instance.updateInternal(deltaTime);
}
/**
* 注册全局管理器
*
* 将管理器添加到全局管理器列表中,并启用它。
*
* @param manager - 要注册的全局管理器
*/
public static registerGlobalManager(manager: GlobalManager) {
this._instance._globalManagers.push(manager);
manager.enabled = true;
}
/**
* 注销全局管理器
*
* 从全局管理器列表中移除管理器,并禁用它。
*
* @param manager - 要注销的全局管理器
*/
public static unregisterGlobalManager(manager: GlobalManager) {
this._instance._globalManagers.splice(this._instance._globalManagers.indexOf(manager), 1);
manager.enabled = false;
}
/**
* 获取指定类型的全局管理器
*
* @param type - 管理器类型构造函数
* @returns 管理器实例如果未找到则返回null
*/
public static getGlobalManager<T extends GlobalManager>(type: new (...args: unknown[]) => T): T | null {
for (const manager of this._instance._globalManagers) {
if (manager instanceof type)
return manager as T;
}
return null;
}
/**
* 调度定时器
@@ -416,6 +379,7 @@ export class Core {
* @param context - 回调函数的上下文默认为null
* @param onTime - 定时器触发时的回调函数
* @returns 创建的定时器实例
* @throws 如果Core实例未创建或onTime回调未提供
*
* @example
* ```typescript
@@ -431,6 +395,9 @@ export class Core {
* ```
*/
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context?: TContext, onTime?: (timer: ITimer<TContext>) => void): Timer<TContext> {
if (!this._instance) {
throw new Error('Core实例未创建请先调用Core.create()');
}
if (!onTime) {
throw new Error('onTime callback is required');
}
@@ -451,7 +418,13 @@ export class Core {
if (this._instance._debugManager) {
this._instance._debugManager.updateConfig(config);
} else {
this._instance._debugManager = new DebugManager(this._instance, config);
// 使用DI容器创建DebugManager
this._instance._debugManager = new DebugManager(
this._instance._serviceContainer.resolve(SceneManager),
this._instance._serviceContainer.resolve(PerformanceMonitor),
config
);
this._instance._serviceContainer.registerInstance(DebugManager, this._instance._debugManager);
}
// 更新Core配置
@@ -530,13 +503,10 @@ export class Core {
this._performanceMonitor.updateFPS(Time.deltaTime);
}
// 更新全局管理器
const managersStartTime = this._performanceMonitor.startMonitoring('GlobalManagers.update');
for (const globalManager of this._globalManagers) {
if (globalManager.enabled)
globalManager.update();
}
this._performanceMonitor.endMonitoring('GlobalManagers.update', managersStartTime, this._globalManagers.length);
// 更新所有可更新的服务
const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
this._serviceContainer.updateAll(deltaTime);
this._performanceMonitor.endMonitoring('Services.update', servicesStartTime, this._serviceContainer.getUpdatableCount());
// 更新对象池管理器
this._poolManager.update();
@@ -566,15 +536,12 @@ export class Core {
this._instance._debugManager.stop();
}
// 清理全局管理器
for (const manager of this._instance._globalManagers) {
manager.enabled = false;
}
this._instance._globalManagers = [];
// 清理所有服务
this._instance._serviceContainer.clear();
Core._logger.info('Core destroyed');
// @ts-ignore - 清空实例引用
// 清空实例引用允许重新创建Core实例
this._instance = null;
}
}

View File

@@ -0,0 +1,317 @@
/**
* 依赖注入装饰器
*
* 提供 @Injectable、@Inject 和 @Updatable 装饰器,用于标记可注入的类和依赖注入点
*/
import type { ServiceContainer } from '../ServiceContainer';
import type { IService, ServiceType } from '../ServiceContainer';
/**
* 依赖注入元数据键
*/
const INJECTABLE_METADATA_KEY = Symbol('injectable');
const INJECT_METADATA_KEY = Symbol('inject');
const INJECT_PARAMS_METADATA_KEY = Symbol('inject:params');
const UPDATABLE_METADATA_KEY = Symbol('updatable');
/**
* 依赖注入元数据存储
*/
const injectableMetadata = new WeakMap<any, InjectableMetadata>();
const injectMetadata = new WeakMap<any, Map<number, ServiceType<any> | string | symbol>>();
const updatableMetadata = new WeakMap<any, UpdatableMetadata>();
/**
* 可注入元数据接口
*/
export interface InjectableMetadata {
/**
* 是否可注入
*/
injectable: boolean;
/**
* 依赖列表
*/
dependencies: Array<ServiceType<any> | string | symbol>;
}
/**
* 可更新元数据接口
*/
export interface UpdatableMetadata {
/**
* 是否可更新
*/
updatable: boolean;
/**
* 更新优先级数值越小越先执行默认0
*/
priority: number;
}
/**
* @Injectable() 装饰器
*
* 标记类为可注入的服务使其可以通过ServiceContainer进行依赖注入
*
* @example
* ```typescript
* @Injectable()
* class TimeService implements IService {
* constructor() {}
* dispose() {}
* }
*
* @Injectable()
* class PhysicsSystem extends EntitySystem {
* constructor(
* @Inject(TimeService) private timeService: TimeService
* ) {
* super();
* }
* }
* ```
*/
export function Injectable(): ClassDecorator {
return function <T extends Function>(target: T): T {
// 标记为可注入
injectableMetadata.set(target, {
injectable: true,
dependencies: []
});
return target;
};
}
/**
* @Updatable() 装饰器
*
* 标记服务类为可更新的使其在每帧自动被ServiceContainer调用update方法。
* 使用此装饰器的类必须实现IUpdatable接口包含update方法
*
* @param priority - 更新优先级数值越小越先执行默认0
* @throws 如果类没有实现update方法将在运行时抛出错误
*
* @example
* ```typescript
* @Injectable()
* @Updatable()
* class TimerManager implements IService, IUpdatable {
* update(deltaTime?: number) {
* // 每帧更新逻辑
* }
* dispose() {}
* }
*
* // 指定优先级
* @Injectable()
* @Updatable(10)
* class PhysicsManager implements IService, IUpdatable {
* update() { }
* dispose() {}
* }
* ```
*/
export function Updatable(priority: number = 0): ClassDecorator {
return function <T extends Function>(target: T): T {
// 验证类原型上是否有update方法
const prototype = (target as any).prototype;
if (!prototype || typeof prototype.update !== 'function') {
throw new Error(
`@Updatable() decorator requires class ${target.name} to implement IUpdatable interface with update() method. ` +
`Please add 'implements IUpdatable' and define update(deltaTime?: number): void method.`
);
}
// 标记为可更新
updatableMetadata.set(target, {
updatable: true,
priority
});
return target;
};
}
/**
* @Inject() 装饰器
*
* 标记构造函数参数需要注入的服务类型
*
* @param serviceType 服务类型标识符类、字符串或Symbol
*
* @example
* ```typescript
* @Injectable()
* class MySystem extends EntitySystem {
* constructor(
* @Inject(TimeService) private timeService: TimeService,
* @Inject(PhysicsService) private physics: PhysicsService
* ) {
* super();
* }
* }
* ```
*/
export function Inject(serviceType: ServiceType<any> | string | symbol): ParameterDecorator {
return function (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) {
// 获取或创建注入元数据
let params = injectMetadata.get(target);
if (!params) {
params = new Map();
injectMetadata.set(target, params);
}
// 记录参数索引和服务类型的映射
params.set(parameterIndex, serviceType);
};
}
/**
* 检查类是否标记为可注入
*
* @param target 目标类
* @returns 是否可注入
*/
export function isInjectable(target: any): boolean {
const metadata = injectableMetadata.get(target);
return metadata?.injectable ?? false;
}
/**
* 获取类的依赖注入元数据
*
* @param target 目标类
* @returns 依赖注入元数据
*/
export function getInjectableMetadata(target: any): InjectableMetadata | undefined {
return injectableMetadata.get(target);
}
/**
* 获取构造函数参数的注入元数据
*
* @param target 目标类
* @returns 参数索引到服务类型的映射
*/
export function getInjectMetadata(target: any): Map<number, ServiceType<any> | string | symbol> {
return injectMetadata.get(target) || new Map();
}
/**
* 创建实例并自动注入依赖
*
* @param constructor 构造函数
* @param container 服务容器
* @returns 创建的实例
*
* @example
* ```typescript
* const instance = createInstance(MySystem, container);
* ```
*/
export function createInstance<T>(
constructor: new (...args: any[]) => T,
container: ServiceContainer
): T {
// 获取参数注入元数据
const injectParams = getInjectMetadata(constructor);
// 解析依赖
const dependencies: any[] = [];
// 获取构造函数参数数量
const paramCount = constructor.length;
for (let i = 0; i < paramCount; i++) {
const serviceType = injectParams.get(i);
if (serviceType) {
// 如果有显式的@Inject标记使用标记的类型
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
// 字符串或Symbol类型的服务标识
throw new Error(
`String and Symbol service identifiers are not yet supported in constructor injection. ` +
`Please use class types for ${constructor.name} parameter ${i}`
);
} else {
// 类类型
dependencies.push(container.resolve(serviceType as ServiceType<any>));
}
} else {
// 没有@Inject标记传入undefined
dependencies.push(undefined);
}
}
// 创建实例
return new constructor(...dependencies);
}
/**
* 检查类是否标记为可更新
*
* @param target 目标类
* @returns 是否可更新
*/
export function isUpdatable(target: any): boolean {
const metadata = updatableMetadata.get(target);
return metadata?.updatable ?? false;
}
/**
* 获取类的可更新元数据
*
* @param target 目标类
* @returns 可更新元数据
*/
export function getUpdatableMetadata(target: any): UpdatableMetadata | undefined {
return updatableMetadata.get(target);
}
/**
* 注册可注入的服务到容器
*
* 自动检测@Injectable装饰器并注册服务
*
* @param container 服务容器
* @param serviceType 服务类型
* @param singleton 是否注册为单例默认true
*
* @example
* ```typescript
* @Injectable()
* class MyService implements IService {
* dispose() {}
* }
*
* // 自动注册
* registerInjectable(Core.services, MyService);
* ```
*/
export function registerInjectable<T extends IService>(
container: ServiceContainer,
serviceType: ServiceType<T>,
singleton: boolean = true
): void {
if (!isInjectable(serviceType)) {
throw new Error(
`${serviceType.name} is not marked as @Injectable(). ` +
`Please add @Injectable() decorator to the class.`
);
}
// 创建工厂函数使用createInstance自动解析依赖
const factory = (c: ServiceContainer) => createInstance(serviceType, c);
// 注册到容器
if (singleton) {
container.registerSingleton(serviceType, factory);
} else {
container.registerTransient(serviceType, factory);
}
}

View File

@@ -0,0 +1,20 @@
/**
* 依赖注入模块
*
* 提供装饰器和工具函数,用于实现依赖注入模式
*/
export {
Injectable,
Inject,
Updatable,
isInjectable,
getInjectableMetadata,
getInjectMetadata,
isUpdatable,
getUpdatableMetadata,
createInstance,
registerInjectable
} from './Decorators';
export type { InjectableMetadata, UpdatableMetadata } from './Decorators';

View File

@@ -1,4 +1,5 @@
import { createLogger } from '../Utils/Logger';
import { isUpdatable as checkUpdatable, getUpdatableMetadata } from './DI';
const logger = createLogger('ServiceContainer');
@@ -16,8 +17,10 @@ export interface IService {
/**
* 服务类型
*
* 支持任意构造函数签名,以便与依赖注入装饰器配合使用
*/
export type ServiceType<T extends IService> = new (...args: unknown[]) => T;
export type ServiceType<T extends IService> = new (...args: any[]) => T;
/**
* 服务生命周期
@@ -99,6 +102,14 @@ export class ServiceContainer {
*/
private _resolving: Set<ServiceType<IService>> = new Set();
/**
* 可更新的服务列表
*
* 自动收集所有使用@Updatable装饰器标记的服务供Core统一更新
* 按优先级排序(数值越小越先执行)
*/
private _updatableServices: Array<{ instance: any; priority: number }> = [];
/**
* 注册单例服务
*
@@ -192,6 +203,18 @@ export class ServiceContainer {
lifetime: ServiceLifetime.Singleton
});
// 如果使用了@Updatable装饰器添加到可更新列表
if (checkUpdatable(type)) {
const metadata = getUpdatableMetadata(type);
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
logger.debug(`Service ${type.name} is updatable (priority: ${priority}), added to update list`);
}
logger.debug(`Registered service instance: ${type.name}`);
}
@@ -243,6 +266,18 @@ export class ServiceContainer {
// 如果是单例,缓存实例
if (registration.lifetime === ServiceLifetime.Singleton) {
registration.instance = instance;
// 如果使用了@Updatable装饰器添加到可更新列表
if (checkUpdatable(registration.type)) {
const metadata = getUpdatableMetadata(registration.type);
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
logger.debug(`Service ${type.name} is updatable (priority: ${priority}), added to update list`);
}
}
return instance as T;
@@ -300,6 +335,12 @@ export class ServiceContainer {
// 如果有单例实例,调用 dispose
if (registration.instance) {
// 从可更新列表中移除
const index = this._updatableServices.findIndex(item => item.instance === registration.instance);
if (index !== -1) {
this._updatableServices.splice(index, 1);
}
registration.instance.dispose();
}
@@ -320,6 +361,7 @@ export class ServiceContainer {
}
this._services.clear();
this._updatableServices = [];
logger.debug('Cleared all services');
}
@@ -331,4 +373,51 @@ export class ServiceContainer {
public getRegisteredServices(): ServiceType<IService>[] {
return Array.from(this._services.keys());
}
/**
* 更新所有使用@Updatable装饰器标记的服务
*
* 此方法会按优先级顺序遍历所有可更新的服务并调用它们的update方法。
* 所有服务在注册时已经由@Updatable装饰器验证过必须实现IUpdatable接口。
* 通常在Core的主更新循环中调用。
*
* @param deltaTime - 可选的帧时间间隔(秒)
*
* @example
* ```typescript
* // 在Core的update方法中
* this._serviceContainer.updateAll(deltaTime);
* ```
*/
public updateAll(deltaTime?: number): void {
for (const { instance } of this._updatableServices) {
instance.update(deltaTime);
}
}
/**
* 获取所有可更新的服务数量
*
* @returns 可更新服务的数量
*/
public getUpdatableCount(): number {
return this._updatableServices.length;
}
/**
* 获取所有已实例化的服务实例
*
* @returns 所有服务实例的数组
*/
public getAll(): IService[] {
const instances: IService[] = [];
for (const descriptor of this._services.values()) {
if (descriptor.instance) {
instances.push(descriptor.instance);
}
}
return instances;
}
}

View File

@@ -39,34 +39,72 @@ export function ECSComponent(typeName: string) {
};
}
/**
* System元数据配置
*/
export interface SystemMetadata {
/**
* 更新顺序数值越小越先执行默认0
*/
updateOrder?: number;
/**
* 是否默认启用默认true
*/
enabled?: boolean;
}
/**
* 系统类型装饰器
* 用于为系统类指定固定的类型名称,避免在代码混淆后失效
*
*
* @param typeName 系统类型名称
* @param metadata 系统元数据配置
* @example
* ```typescript
* // 基本使用
* @ECSSystem('Movement')
* class MovementSystem extends EntitySystem {
* protected process(entities: Entity[]): void {
* // 系统逻辑
* }
* }
*
* // 配置更新顺序
* @Injectable()
* @ECSSystem('Physics', { updateOrder: 10 })
* class PhysicsSystem extends EntitySystem {
* constructor(@Inject(CollisionSystem) private collision: CollisionSystem) {
* super(Matcher.of(Transform, RigidBody));
* }
* }
* ```
*/
export function ECSSystem(typeName: string) {
export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
return function <T extends new (...args: any[]) => EntitySystem>(target: T): T {
if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSSystem装饰器必须提供有效的类型名称');
}
// 在构造函数上存储类型名称
(target as any)[SYSTEM_TYPE_NAME] = typeName;
// 存储元数据
if (metadata) {
(target as any).__systemMetadata__ = metadata;
}
return target;
};
}
/**
* 获取System的元数据
*/
export function getSystemMetadata(systemType: new (...args: any[]) => EntitySystem): SystemMetadata | undefined {
return (systemType as any).__systemMetadata__;
}
/**
* 获取组件类型的名称,优先使用装饰器指定的名称
*

View File

@@ -5,6 +5,9 @@ export {
getSystemTypeName,
getComponentInstanceTypeName,
getSystemInstanceTypeName,
getSystemMetadata,
COMPONENT_TYPE_NAME,
SYSTEM_TYPE_NAME
} from './TypeDecorators';
} from './TypeDecorators';
export type { SystemMetadata } from './TypeDecorators';

View File

@@ -1,6 +1,5 @@
import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList';
import { EntityProcessorList } from './Utils/EntityProcessorList';
import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager } from './Core/ComponentStorage';
@@ -41,12 +40,7 @@ export interface IScene {
* 场景中的实体集合
*/
readonly entities: EntityList;
/**
* 实体系统处理器集合
*/
readonly entityProcessors: EntityProcessorList;
/**
* 标识符池
*/

View File

@@ -1,6 +1,5 @@
import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList';
import { EntityProcessorList } from './Utils/EntityProcessorList';
import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager, ComponentRegistry } from './Core/ComponentStorage';
@@ -8,13 +7,17 @@ import { QuerySystem } from './Core/QuerySystem';
import { TypeSafeEventSystem } from './Core/EventSystem';
import { EventBus } from './Core/EventBus';
import { IScene, ISceneConfig } from './IScene';
import { getComponentInstanceTypeName, getSystemInstanceTypeName } from './Decorators';
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from "./Decorators";
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import { Core } from '../Core';
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
import { createInstance, isInjectable } from '../Core/DI';
import { isUpdatable, getUpdatableMetadata } from '../Core/DI/Decorators';
import { createLogger } from '../Utils/Logger';
/**
* 游戏场景默认实现类
@@ -44,12 +47,6 @@ export class Scene implements IScene {
*/
public readonly entities: EntityList;
/**
* 实体系统处理器集合
*
* 管理场景内所有实体系统的执行。
*/
public readonly entityProcessors: EntityProcessorList;
/**
* 实体ID池
@@ -74,36 +71,102 @@ export class Scene implements IScene {
/**
* 事件系统
*
*
* 类型安全的事件系统。
*/
public readonly eventSystem: TypeSafeEventSystem;
/**
* 服务容器
*
* 场景级别的依赖注入容器用于管理EntitySystem和其他服务的生命周期。
* 每个Scene拥有独立的服务容器实现场景间的隔离。
*/
private readonly _services: ServiceContainer;
/**
* 日志记录器
*/
private readonly logger: ReturnType<typeof createLogger>;
/**
* 场景是否已开始运行
*/
private _didSceneBegin: boolean = false;
/**
* 获取系统列表(兼容性属性)
* 获取场景中所有已注册的EntitySystem
*
* 按updateOrder排序。
*
* @returns 系统列表
*/
public get systems(): EntitySystem[] {
return this.entityProcessors.processors;
// 从ServiceContainer获取所有EntitySystem实例
const services = this._services.getAll();
const systems: EntitySystem[] = [];
for (const service of services) {
if (service instanceof EntitySystem) {
systems.push(service);
}
}
// 按updateOrder排序
systems.sort((a, b) => a.updateOrder - b.updateOrder);
return systems;
}
/**
* 通过类型获取System实例
*
* @param systemType System类型
* @returns System实例如果未找到则返回null
*
* @example
* ```typescript
* const physics = scene.getSystem(PhysicsSystem);
* if (physics) {
* physics.doSomething();
* }
* ```
*/
public getSystem<T extends EntitySystem>(systemType: ServiceType<T>): T | null {
return this._services.tryResolve(systemType) as T | null;
}
/**
* 获取场景的服务容器
*
* 用于注册和解析场景级别的服务如EntitySystem
*
* @example
* ```typescript
* // 注册服务
* scene.services.registerSingleton(PhysicsSystem);
*
* // 解析服务
* const physics = scene.services.resolve(PhysicsSystem);
* ```
*/
public get services(): ServiceContainer {
return this._services;
}
/**
* 创建场景实例
*/
constructor(config?: ISceneConfig) {
this.entities = new EntityList(this);
this.entityProcessors = new EntityProcessorList();
this.identifierPool = new IdentifierPool();
this.componentStorageManager = new ComponentStorageManager();
this.querySystem = new QuerySystem();
this.eventSystem = new TypeSafeEventSystem();
this._services = new ServiceContainer();
this.logger = createLogger('Scene');
// 应用配置
if (config?.name) {
this.name = config.name;
}
@@ -111,7 +174,7 @@ export class Scene implements IScene {
if (!Entity.eventBus) {
Entity.eventBus = new EventBus(false);
}
if (Entity.eventBus) {
Entity.eventBus.onComponentAdded((data: unknown) => {
this.eventSystem.emitSync('component:added', data);
@@ -149,10 +212,6 @@ export class Scene implements IScene {
* 这个方法会启动场景。它将启动实体处理器等并调用onStart方法。
*/
public begin() {
// 启动实体处理器
if (this.entityProcessors != null)
this.entityProcessors.begin();
// 标记场景已开始运行并调用onStart方法
this._didSceneBegin = true;
this.onStart();
@@ -176,9 +235,8 @@ export class Scene implements IScene {
// 清空组件存储
this.componentStorageManager.clear();
// 结束实体处理器
if (this.entityProcessors)
this.entityProcessors.end();
// 清空服务容器会调用所有服务的dispose方法包括所有EntitySystem
this._services.clear();
// 调用卸载方法
this.unload();
@@ -192,11 +250,28 @@ export class Scene implements IScene {
this.entities.updateLists();
if (this.entityProcessors != null)
this.entityProcessors.update();
// 更新所有EntitySystem
const systems = this.systems;
for (const system of systems) {
if (system.enabled) {
try {
system.update();
} catch (error) {
this.logger.error(`Error in system ${system.constructor.name}.update():`, error);
}
}
}
if (this.entityProcessors != null)
this.entityProcessors.lateUpdate();
// LateUpdate
for (const system of systems) {
if (system.enabled) {
try {
system.lateUpdate();
} catch (error) {
this.logger.error(`Error in system ${system.constructor.name}.lateUpdate():`, error);
}
}
}
}
/**
@@ -216,7 +291,7 @@ export class Scene implements IScene {
* 当实体或组件发生变化时调用
*/
public clearSystemEntityCaches(): void {
for (const system of this.entityProcessors.processors) {
for (const system of this.systems) {
system.clearEntityCache();
}
}
@@ -419,23 +494,121 @@ export class Scene implements IScene {
/**
* 在场景中添加一个EntitySystem处理器
* @param processor 处理器
*
* 支持两种使用方式:
* 1. 传入类型推荐自动使用DI创建实例支持@Injectable和@Inject装饰器
* 2. 传入实例:直接使用提供的实例
*
* @param systemTypeOrInstance 系统类型或系统实例
* @returns 添加的处理器实例
*
* @example
* ```typescript
* // 方式1传入类型自动DI推荐
* @Injectable()
* class PhysicsSystem extends EntitySystem {
* constructor(@Inject(CollisionSystem) private collision: CollisionSystem) {
* super(Matcher.of(Transform));
* }
* }
* scene.addEntityProcessor(PhysicsSystem);
*
* // 方式2传入实例
* const system = new MySystem();
* scene.addEntityProcessor(system);
* ```
*/
public addEntityProcessor(processor: EntitySystem) {
if (this.entityProcessors.processors.includes(processor)) {
return processor;
public addEntityProcessor<T extends EntitySystem>(
systemTypeOrInstance: ServiceType<T> | T
): T {
let system: T;
let constructor: any;
if (typeof systemTypeOrInstance === 'function') {
constructor = systemTypeOrInstance;
if (this._services.isRegistered(constructor)) {
return this._services.resolve(constructor) as T;
}
if (isInjectable(constructor)) {
system = createInstance(constructor, this._services) as T;
} else {
system = new (constructor as any)() as T;
}
} else {
system = systemTypeOrInstance;
constructor = system.constructor;
if (this._services.isRegistered(constructor)) {
return system;
}
}
processor.scene = this;
system.scene = this;
// 从Core获取PerformanceMonitor并注入到System
const perfMonitor = Core.services.resolve(PerformanceMonitor);
processor.setPerformanceMonitor(perfMonitor);
system.setPerformanceMonitor(perfMonitor);
this.entityProcessors.add(processor);
processor.initialize();
processor.setUpdateOrder(this.entityProcessors.count - 1);
return processor;
const metadata = getSystemMetadata(constructor);
if (metadata?.updateOrder !== undefined) {
system.setUpdateOrder(metadata.updateOrder);
}
if (metadata?.enabled !== undefined) {
system.enabled = metadata.enabled;
}
this._services.registerInstance(constructor, system);
system.initialize();
return system;
}
/**
* 批量注册EntitySystem到场景使用DI
*
* 自动按照依赖顺序注册多个System。
* 所有System必须使用@Injectable装饰器标记。
*
* @param systemTypes System类型数组
* @returns 注册的System实例数组
*
* @example
* ```typescript
* @Injectable()
* @ECSSystem('Collision', { updateOrder: 5 })
* class CollisionSystem extends EntitySystem implements IService {
* constructor() { super(Matcher.of(Collider)); }
* dispose() {}
* }
*
* @Injectable()
* @ECSSystem('Physics', { updateOrder: 10 })
* class PhysicsSystem extends EntitySystem implements IService {
* constructor(@Inject(CollisionSystem) private collision: CollisionSystem) {
* super(Matcher.of(Transform, RigidBody));
* }
* dispose() {}
* }
*
* // 批量注册(自动解析依赖顺序)
* scene.registerSystems([
* CollisionSystem,
* PhysicsSystem, // 自动注入CollisionSystem
* RenderSystem
* ]);
* ```
*/
public registerSystems(systemTypes: Array<ServiceType<EntitySystem>>): EntitySystem[] {
const registeredSystems: EntitySystem[] = [];
for (const systemType of systemTypes) {
const system = this.addEntityProcessor(systemType);
registeredSystems.push(system);
}
return registeredSystems;
}
/**
@@ -450,8 +623,13 @@ export class Scene implements IScene {
* 从场景中删除EntitySystem处理器
* @param processor 要删除的处理器
*/
public removeEntityProcessor(processor: EntitySystem) {
this.entityProcessors.remove(processor);
public removeEntityProcessor(processor: EntitySystem): void {
const constructor = processor.constructor as any;
// 从ServiceContainer移除
this._services.unregister(constructor);
// 重置System状态
processor.reset();
}
@@ -465,10 +643,24 @@ export class Scene implements IScene {
/**
* 获取指定类型的EntitySystem处理器
*
* @deprecated 推荐使用依赖注入代替此方法。使用 `scene.services.resolve(SystemType)` 或在System构造函数中使用 `@Inject(SystemType)` 装饰器。
*
* @param type 处理器类型
* @returns 处理器实例如果未找到则返回null
*
* @example
* ```typescript
* @Injectable()
* class MySystem extends EntitySystem {
* constructor(@Inject(PhysicsSystem) private physics: PhysicsSystem) {
* super();
* }
* }
* ```
*/
public getEntityProcessor<T extends EntitySystem>(type: new (...args: unknown[]) => T): T | null {
return this.entityProcessors.getProcessor(type);
return this._services.tryResolve(type as any) as T | null;
}
/**
@@ -481,7 +673,7 @@ export class Scene implements IScene {
} {
return {
entityCount: this.entities.count,
processorCount: this.entityProcessors.count,
processorCount: this.systems.length,
componentStorageStats: this.componentStorageManager.getAllStats()
};
}
@@ -508,10 +700,11 @@ export class Scene implements IScene {
}>;
componentStats: Map<string, any>;
} {
const systems = this.systems;
return {
name: this.name || this.constructor.name,
entityCount: this.entities.count,
processorCount: this.entityProcessors.count,
processorCount: systems.length,
isRunning: this._didSceneBegin,
entities: this.entities.buffer.map(entity => ({
name: entity.name,
@@ -519,7 +712,7 @@ export class Scene implements IScene {
componentCount: entity.components.length,
componentTypes: entity.components.map(c => getComponentInstanceTypeName(c))
})),
processors: this.entityProcessors.processors.map(processor => ({
processors: systems.map(processor => ({
name: getSystemInstanceTypeName(processor),
updateOrder: processor.updateOrder,
entityCount: (processor as any)._entities?.length || 0

View File

@@ -8,6 +8,7 @@ import { getSystemInstanceTypeName } from '../Decorators';
import { createLogger } from '../../Utils/Logger';
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
import type { IService } from '../../Core/ServiceContainer';
/**
* 事件监听器记录
@@ -65,7 +66,7 @@ interface EventListenerRecord {
*/
export abstract class EntitySystem<
TComponents extends readonly ComponentConstructor[] = []
> implements ISystemBase {
> implements ISystemBase, IService {
private _updateOrder: number;
private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null;
@@ -222,9 +223,6 @@ export abstract class EntitySystem<
*/
public setUpdateOrder(order: number): void {
this._updateOrder = order;
if (this.scene && this.scene.entityProcessors) {
this.scene.entityProcessors.setDirty();
}
}
/**
@@ -725,15 +723,43 @@ export abstract class EntitySystem<
/**
* 当实体从系统中移除时调用
*
*
* 子类可以重写此方法来处理实体移除事件。
*
*
* @param entity 被移除的实体
*/
protected onRemoved(entity: Entity): void {
// 子类可以重写此方法
}
/**
* 释放系统资源
*
* 实现IService接口要求的dispose方法。
* 当系统从Scene中移除或Scene销毁时调用。
*
* 默认行为:
* - 移除所有事件监听器
* - 清空所有缓存
* - 重置初始化状态
*
* 子类可以重写此方法来清理自定义资源但应该调用super.dispose()。
*/
public dispose(): void {
// 移除所有事件监听器
this.cleanupManualEventListeners();
// 清空所有缓存
this._entityCache.clearAll();
this._entityIdMap = null;
// 重置状态
this._initialized = false;
this._scene = null;
this.logger.debug(`System ${this._systemName} disposed`);
}
/**
* 添加事件监听器
*

View File

@@ -0,0 +1,20 @@
/**
* 可更新接口
*
* 实现此接口的服务将在每帧被Core自动调用update方法
*/
export interface IUpdatable {
/**
* 每帧更新方法
*
* @param deltaTime - 帧时间间隔(秒),可选参数
*/
update(deltaTime?: number): void;
}
/**
* 检查对象是否实现了IUpdatable接口
*/
export function isUpdatable(obj: any): obj is IUpdatable {
return obj && typeof obj.update === 'function';
}

View File

@@ -4,6 +4,7 @@
// 导出TypeScript类型增强工具
export * from './TypeHelpers';
export * from './IUpdatable';
/**
* 组件接口

View File

@@ -10,11 +10,15 @@ import { ComponentPoolManager } from '../../ECS/Core/ComponentPool';
import { Pool } from '../../Utils/Pool';
import { getComponentInstanceTypeName, getSystemInstanceTypeName } from '../../ECS/Decorators';
import type { IService } from '../../Core/ServiceContainer';
import { SceneManager } from '../../ECS/SceneManager';
import { PerformanceMonitor } from '../PerformanceMonitor';
/**
* 调试管理器
*
* 整合所有调试数据收集器,负责收集和发送调试数据
*
* 通过构造函数接收SceneManager和PerformanceMonitor避免直接依赖Core实例
*/
export class DebugManager implements IService {
private config: IECSDebugConfig;
@@ -24,8 +28,8 @@ export class DebugManager implements IService {
private performanceCollector: PerformanceDataCollector;
private componentCollector: ComponentDataCollector;
private sceneCollector: SceneDataCollector;
private sceneProvider: () => any;
private performanceMonitorProvider: () => any;
private sceneManager: SceneManager;
private performanceMonitor: PerformanceMonitor;
private frameCounter: number = 0;
private lastSendTime: number = 0;
@@ -34,15 +38,18 @@ export class DebugManager implements IService {
/**
* 构造调试管理器
* @param core Core实例
* @param sceneManager 场景管理器
* @param performanceMonitor 性能监控器
* @param config 调试配置
*/
constructor(core: any, config: IECSDebugConfig) {
constructor(
sceneManager: SceneManager,
performanceMonitor: PerformanceMonitor,
config: IECSDebugConfig
) {
this.config = config;
// 设置提供器函数
this.sceneProvider = () => (core as any).scene || (core.constructor as any).scene;
this.performanceMonitorProvider = () => core._performanceMonitor;
this.sceneManager = sceneManager;
this.performanceMonitor = performanceMonitor;
// 初始化数据收集器
this.entityCollector = new EntityDataCollector();
@@ -339,7 +346,7 @@ export class DebugManager implements IService {
// 收集其他内存统计
const baseMemoryInfo = this.collectBaseMemoryInfo();
const scene = this.sceneProvider();
const scene = this.sceneManager.currentScene;
// 使用专门的内存计算方法收集实体数据
const entityData = this.entityCollector.collectEntityDataWithMemory(scene);
@@ -453,7 +460,7 @@ export class DebugManager implements IService {
/**
* 收集组件内存统计(仅用于内存快照)
*/
private collectComponentMemoryStats(entityList: { buffer: Array<{ id: number; name?: string; destroyed?: boolean; components?: Component[] }> }): {
private collectComponentMemoryStats(entityList: { buffer: Array<{ id: number; name?: string; destroyed?: boolean; components?: readonly Component[] }> }): {
totalMemory: number;
componentTypes: number;
totalInstances: number;
@@ -547,7 +554,7 @@ export class DebugManager implements IService {
updateOrder: number;
}>;
} {
const scene = this.sceneProvider();
const scene = this.sceneManager.currentScene;
let totalSystemMemory = 0;
const systemBreakdown: Array<{
name: string;
@@ -557,11 +564,11 @@ export class DebugManager implements IService {
}> = [];
try {
const entityProcessors = scene?.entityProcessors;
if (entityProcessors && entityProcessors.processors) {
const systems = scene?.systems;
if (systems) {
const systemTypeMemoryCache = new Map<string, number>();
for (const system of entityProcessors.processors) {
for (const system of systems) {
const systemTypeName = getSystemInstanceTypeName(system);
let systemMemory: number;
@@ -721,16 +728,15 @@ export class DebugManager implements IService {
error?: string;
} {
try {
const performanceMonitor = this.performanceMonitorProvider();
if (!performanceMonitor) {
if (!this.performanceMonitor) {
return { enabled: false };
}
const stats = performanceMonitor.getAllSystemStats();
const warnings = performanceMonitor.getPerformanceWarnings();
const stats = this.performanceMonitor.getAllSystemStats();
const warnings = this.performanceMonitor.getPerformanceWarnings();
return {
enabled: (performanceMonitor as { enabled?: boolean }).enabled ?? false,
enabled: (this.performanceMonitor as { enabled?: boolean }).enabled ?? false,
systemCount: stats.size,
warnings: warnings.slice(0, 10), // 最多10个警告
topSystems: Array.from(stats.entries()).map((entry) => {
@@ -754,7 +760,7 @@ export class DebugManager implements IService {
*/
public getDebugData(): IECSDebugData {
const currentTime = Date.now();
const scene = this.sceneProvider();
const scene = this.sceneManager.currentScene;
const debugData: IECSDebugData = {
timestamp: currentTime,
@@ -770,13 +776,11 @@ export class DebugManager implements IService {
}
if (this.config.channels.systems) {
const performanceMonitor = this.performanceMonitorProvider();
debugData.systems = this.systemCollector.collectSystemData(performanceMonitor, scene);
debugData.systems = this.systemCollector.collectSystemData(this.performanceMonitor, scene);
}
if (this.config.channels.performance) {
const performanceMonitor = this.performanceMonitorProvider();
debugData.performance = this.performanceCollector.collectPerformanceData(performanceMonitor);
debugData.performance = this.performanceCollector.collectPerformanceData(this.performanceMonitor);
}
if (this.config.channels.components) {

View File

@@ -1,15 +1,19 @@
import { GlobalManager } from '../GlobalManager';
import { Timer } from './Timer';
import { ITimer } from './ITimer';
import type { IService } from '../../Core/ServiceContainer';
import type { IUpdatable } from '../../Types/IUpdatable';
import { Updatable } from '../../Core/DI';
/**
* 定时器管理器
*
* 允许动作的延迟和重复执行
*/
export class TimerManager extends GlobalManager implements IService {
@Updatable()
export class TimerManager implements IService, IUpdatable {
public _timers: Array<Timer<unknown>> = [];
public override update() {
public update() {
for (let i = this._timers.length - 1; i >= 0; i --){
if (this._timers[i].tick()){
this._timers[i].unload();

View File

@@ -8,6 +8,18 @@ export { Core } from './Core';
export { ServiceContainer, ServiceLifetime } from './Core/ServiceContainer';
export type { IService, ServiceType } from './Core/ServiceContainer';
// 依赖注入
export {
Injectable,
Inject,
Updatable,
registerInjectable,
createInstance,
isUpdatable,
getUpdatableMetadata
} from './Core/DI';
export type { InjectableMetadata, UpdatableMetadata } from './Core/DI';
// 核心管理器
export { Emitter, FuncPack } from './Utils/Emitter';
export { GlobalManager } from './Utils/GlobalManager';

View File

@@ -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();
});
});

View 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');
});
});
});

View File

@@ -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('流式调用应该工作正常', () => {

View 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);
});
});
});

View File

@@ -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('系统处理过程中的异常应该被正确处理', () => {