依赖注入引入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 { TimerManager } from './Utils/Timers/TimerManager';
import { ITimer } from './Utils/Timers/ITimer'; import { ITimer } from './Utils/Timers/ITimer';
import { Timer } from './Utils/Timers/Timer'; import { Timer } from './Utils/Timers/Timer';
@@ -6,7 +5,7 @@ import { Time } from './Utils/Time';
import { PerformanceMonitor } from './Utils/PerformanceMonitor'; import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool/PoolManager'; import { PoolManager } from './Utils/Pool/PoolManager';
import { DebugManager } from './Utils/Debug'; import { DebugManager } from './Utils/Debug';
import { ICoreConfig, IECSDebugConfig } from './Types'; import { ICoreConfig, IECSDebugConfig, IUpdatable, isUpdatable } from './Types';
import { createLogger } from './Utils/Logger'; import { createLogger } from './Utils/Logger';
import { SceneManager } from './ECS/SceneManager'; import { SceneManager } from './ECS/SceneManager';
import { IScene } from './ECS/IScene'; 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专用日志器 * Core专用日志器
@@ -84,13 +85,6 @@ export class Core {
*/ */
private _serviceContainer: ServiceContainer; private _serviceContainer: ServiceContainer;
/**
* 全局管理器集合
*
* 存储所有注册的全局管理器实例。
*/
public _globalManagers: GlobalManager[] = [];
/** /**
* 定时器管理器 * 定时器管理器
* *
@@ -151,7 +145,6 @@ export class Core {
// 初始化定时器管理器 // 初始化定时器管理器
this._timerManager = new TimerManager(); this._timerManager = new TimerManager();
Core.registerGlobalManager(this._timerManager);
this._serviceContainer.registerInstance(TimerManager, this._timerManager); this._serviceContainer.registerInstance(TimerManager, this._timerManager);
// 初始化性能监控器 // 初始化性能监控器
@@ -175,7 +168,13 @@ export class Core {
// 初始化调试管理器 // 初始化调试管理器
if (this._config.debugConfig?.enabled) { 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); this._serviceContainer.registerInstance(DebugManager, this._debugManager);
} }
@@ -197,6 +196,7 @@ export class Core {
* 用于注册和解析自定义服务。 * 用于注册和解析自定义服务。
* *
* @returns 服务容器实例 * @returns 服务容器实例
* @throws 如果Core实例未创建
* *
* @example * @example
* ```typescript * ```typescript
@@ -368,43 +368,6 @@ export class Core {
this._instance.updateInternal(deltaTime); 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 context - 回调函数的上下文默认为null
* @param onTime - 定时器触发时的回调函数 * @param onTime - 定时器触发时的回调函数
* @returns 创建的定时器实例 * @returns 创建的定时器实例
* @throws 如果Core实例未创建或onTime回调未提供
* *
* @example * @example
* ```typescript * ```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> { 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) { if (!onTime) {
throw new Error('onTime callback is required'); throw new Error('onTime callback is required');
} }
@@ -451,7 +418,13 @@ export class Core {
if (this._instance._debugManager) { if (this._instance._debugManager) {
this._instance._debugManager.updateConfig(config); this._instance._debugManager.updateConfig(config);
} else { } 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配置 // 更新Core配置
@@ -530,13 +503,10 @@ export class Core {
this._performanceMonitor.updateFPS(Time.deltaTime); this._performanceMonitor.updateFPS(Time.deltaTime);
} }
// 更新全局管理器 // 更新所有可更新的服务
const managersStartTime = this._performanceMonitor.startMonitoring('GlobalManagers.update'); const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
for (const globalManager of this._globalManagers) { this._serviceContainer.updateAll(deltaTime);
if (globalManager.enabled) this._performanceMonitor.endMonitoring('Services.update', servicesStartTime, this._serviceContainer.getUpdatableCount());
globalManager.update();
}
this._performanceMonitor.endMonitoring('GlobalManagers.update', managersStartTime, this._globalManagers.length);
// 更新对象池管理器 // 更新对象池管理器
this._poolManager.update(); this._poolManager.update();
@@ -566,15 +536,12 @@ export class Core {
this._instance._debugManager.stop(); this._instance._debugManager.stop();
} }
// 清理全局管理器 // 清理所有服务
for (const manager of this._instance._globalManagers) { this._instance._serviceContainer.clear();
manager.enabled = false;
}
this._instance._globalManagers = [];
Core._logger.info('Core destroyed'); Core._logger.info('Core destroyed');
// @ts-ignore - 清空实例引用 // 清空实例引用允许重新创建Core实例
this._instance = null; 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 { createLogger } from '../Utils/Logger';
import { isUpdatable as checkUpdatable, getUpdatableMetadata } from './DI';
const logger = createLogger('ServiceContainer'); 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(); 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 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}`); logger.debug(`Registered service instance: ${type.name}`);
} }
@@ -243,6 +266,18 @@ export class ServiceContainer {
// 如果是单例,缓存实例 // 如果是单例,缓存实例
if (registration.lifetime === ServiceLifetime.Singleton) { if (registration.lifetime === ServiceLifetime.Singleton) {
registration.instance = instance; 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; return instance as T;
@@ -300,6 +335,12 @@ export class ServiceContainer {
// 如果有单例实例,调用 dispose // 如果有单例实例,调用 dispose
if (registration.instance) { if (registration.instance) {
// 从可更新列表中移除
const index = this._updatableServices.findIndex(item => item.instance === registration.instance);
if (index !== -1) {
this._updatableServices.splice(index, 1);
}
registration.instance.dispose(); registration.instance.dispose();
} }
@@ -320,6 +361,7 @@ export class ServiceContainer {
} }
this._services.clear(); this._services.clear();
this._updatableServices = [];
logger.debug('Cleared all services'); logger.debug('Cleared all services');
} }
@@ -331,4 +373,51 @@ export class ServiceContainer {
public getRegisteredServices(): ServiceType<IService>[] { public getRegisteredServices(): ServiceType<IService>[] {
return Array.from(this._services.keys()); 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,22 +39,48 @@ export function ECSComponent(typeName: string) {
}; };
} }
/**
* System元数据配置
*/
export interface SystemMetadata {
/**
* 更新顺序数值越小越先执行默认0
*/
updateOrder?: number;
/**
* 是否默认启用默认true
*/
enabled?: boolean;
}
/** /**
* 系统类型装饰器 * 系统类型装饰器
* 用于为系统类指定固定的类型名称,避免在代码混淆后失效 * 用于为系统类指定固定的类型名称,避免在代码混淆后失效
* *
* @param typeName 系统类型名称 * @param typeName 系统类型名称
* @param metadata 系统元数据配置
* @example * @example
* ```typescript * ```typescript
* // 基本使用
* @ECSSystem('Movement') * @ECSSystem('Movement')
* class MovementSystem extends EntitySystem { * class MovementSystem extends EntitySystem {
* protected process(entities: Entity[]): void { * 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 { return function <T extends new (...args: any[]) => EntitySystem>(target: T): T {
if (!typeName || typeof typeName !== 'string') { if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSSystem装饰器必须提供有效的类型名称'); throw new Error('ECSSystem装饰器必须提供有效的类型名称');
@@ -63,10 +89,22 @@ export function ECSSystem(typeName: string) {
// 在构造函数上存储类型名称 // 在构造函数上存储类型名称
(target as any)[SYSTEM_TYPE_NAME] = typeName; (target as any)[SYSTEM_TYPE_NAME] = typeName;
// 存储元数据
if (metadata) {
(target as any).__systemMetadata__ = metadata;
}
return target; 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, getSystemTypeName,
getComponentInstanceTypeName, getComponentInstanceTypeName,
getSystemInstanceTypeName, getSystemInstanceTypeName,
getSystemMetadata,
COMPONENT_TYPE_NAME, COMPONENT_TYPE_NAME,
SYSTEM_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 { Entity } from './Entity';
import { EntityList } from './Utils/EntityList'; import { EntityList } from './Utils/EntityList';
import { EntityProcessorList } from './Utils/EntityProcessorList';
import { IdentifierPool } from './Utils/IdentifierPool'; import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem'; import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager } from './Core/ComponentStorage'; import { ComponentStorageManager } from './Core/ComponentStorage';
@@ -42,11 +41,6 @@ export interface IScene {
*/ */
readonly entities: EntityList; readonly entities: EntityList;
/**
* 实体系统处理器集合
*/
readonly entityProcessors: EntityProcessorList;
/** /**
* 标识符池 * 标识符池
*/ */

View File

@@ -1,6 +1,5 @@
import { Entity } from './Entity'; import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList'; import { EntityList } from './Utils/EntityList';
import { EntityProcessorList } from './Utils/EntityProcessorList';
import { IdentifierPool } from './Utils/IdentifierPool'; import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem'; import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager, ComponentRegistry } from './Core/ComponentStorage'; import { ComponentStorageManager, ComponentRegistry } from './Core/ComponentStorage';
@@ -8,13 +7,17 @@ import { QuerySystem } from './Core/QuerySystem';
import { TypeSafeEventSystem } from './Core/EventSystem'; import { TypeSafeEventSystem } from './Core/EventSystem';
import { EventBus } from './Core/EventBus'; import { EventBus } from './Core/EventBus';
import { IScene, ISceneConfig } from './IScene'; import { IScene, ISceneConfig } from './IScene';
import { getComponentInstanceTypeName, getSystemInstanceTypeName } from './Decorators'; import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from "./Decorators";
import { TypedQueryBuilder } from './Core/Query/TypedQuery'; import { TypedQueryBuilder } from './Core/Query/TypedQuery';
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer'; import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer'; import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool'; import { ComponentPoolManager } from './Core/ComponentPool';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor'; import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import { Core } from '../Core'; 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 entities: EntityList;
/**
* 实体系统处理器集合
*
* 管理场景内所有实体系统的执行。
*/
public readonly entityProcessors: EntityProcessorList;
/** /**
* 实体ID池 * 实体ID池
@@ -79,31 +76,97 @@ export class Scene implements IScene {
*/ */
public readonly eventSystem: TypeSafeEventSystem; public readonly eventSystem: TypeSafeEventSystem;
/**
* 服务容器
*
* 场景级别的依赖注入容器用于管理EntitySystem和其他服务的生命周期。
* 每个Scene拥有独立的服务容器实现场景间的隔离。
*/
private readonly _services: ServiceContainer;
/**
* 日志记录器
*/
private readonly logger: ReturnType<typeof createLogger>;
/** /**
* 场景是否已开始运行 * 场景是否已开始运行
*/ */
private _didSceneBegin: boolean = false; private _didSceneBegin: boolean = false;
/** /**
* 获取系统列表(兼容性属性) * 获取场景中所有已注册的EntitySystem
*
* 按updateOrder排序。
*
* @returns 系统列表
*/ */
public get systems(): EntitySystem[] { 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) { constructor(config?: ISceneConfig) {
this.entities = new EntityList(this); this.entities = new EntityList(this);
this.entityProcessors = new EntityProcessorList();
this.identifierPool = new IdentifierPool(); this.identifierPool = new IdentifierPool();
this.componentStorageManager = new ComponentStorageManager(); this.componentStorageManager = new ComponentStorageManager();
this.querySystem = new QuerySystem(); this.querySystem = new QuerySystem();
this.eventSystem = new TypeSafeEventSystem(); this.eventSystem = new TypeSafeEventSystem();
this._services = new ServiceContainer();
this.logger = createLogger('Scene');
// 应用配置
if (config?.name) { if (config?.name) {
this.name = config.name; this.name = config.name;
} }
@@ -149,10 +212,6 @@ export class Scene implements IScene {
* 这个方法会启动场景。它将启动实体处理器等并调用onStart方法。 * 这个方法会启动场景。它将启动实体处理器等并调用onStart方法。
*/ */
public begin() { public begin() {
// 启动实体处理器
if (this.entityProcessors != null)
this.entityProcessors.begin();
// 标记场景已开始运行并调用onStart方法 // 标记场景已开始运行并调用onStart方法
this._didSceneBegin = true; this._didSceneBegin = true;
this.onStart(); this.onStart();
@@ -176,9 +235,8 @@ export class Scene implements IScene {
// 清空组件存储 // 清空组件存储
this.componentStorageManager.clear(); this.componentStorageManager.clear();
// 结束实体处理器 // 清空服务容器会调用所有服务的dispose方法包括所有EntitySystem
if (this.entityProcessors) this._services.clear();
this.entityProcessors.end();
// 调用卸载方法 // 调用卸载方法
this.unload(); this.unload();
@@ -192,11 +250,28 @@ export class Scene implements IScene {
this.entities.updateLists(); this.entities.updateLists();
if (this.entityProcessors != null) // 更新所有EntitySystem
this.entityProcessors.update(); 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) // LateUpdate
this.entityProcessors.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 { public clearSystemEntityCaches(): void {
for (const system of this.entityProcessors.processors) { for (const system of this.systems) {
system.clearEntityCache(); system.clearEntityCache();
} }
} }
@@ -419,23 +494,121 @@ export class Scene implements IScene {
/** /**
* 在场景中添加一个EntitySystem处理器 * 在场景中添加一个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) { public addEntityProcessor<T extends EntitySystem>(
if (this.entityProcessors.processors.includes(processor)) { systemTypeOrInstance: ServiceType<T> | T
return processor; ): 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;
} }
processor.scene = this; 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;
}
}
system.scene = this;
// 从Core获取PerformanceMonitor并注入到System
const perfMonitor = Core.services.resolve(PerformanceMonitor); const perfMonitor = Core.services.resolve(PerformanceMonitor);
processor.setPerformanceMonitor(perfMonitor); system.setPerformanceMonitor(perfMonitor);
this.entityProcessors.add(processor); const metadata = getSystemMetadata(constructor);
processor.initialize(); if (metadata?.updateOrder !== undefined) {
processor.setUpdateOrder(this.entityProcessors.count - 1); system.setUpdateOrder(metadata.updateOrder);
return processor; }
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处理器 * 从场景中删除EntitySystem处理器
* @param processor 要删除的处理器 * @param processor 要删除的处理器
*/ */
public removeEntityProcessor(processor: EntitySystem) { public removeEntityProcessor(processor: EntitySystem): void {
this.entityProcessors.remove(processor); const constructor = processor.constructor as any;
// 从ServiceContainer移除
this._services.unregister(constructor);
// 重置System状态
processor.reset(); processor.reset();
} }
@@ -465,10 +643,24 @@ export class Scene implements IScene {
/** /**
* 获取指定类型的EntitySystem处理器 * 获取指定类型的EntitySystem处理器
*
* @deprecated 推荐使用依赖注入代替此方法。使用 `scene.services.resolve(SystemType)` 或在System构造函数中使用 `@Inject(SystemType)` 装饰器。
*
* @param type 处理器类型 * @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 { 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 { return {
entityCount: this.entities.count, entityCount: this.entities.count,
processorCount: this.entityProcessors.count, processorCount: this.systems.length,
componentStorageStats: this.componentStorageManager.getAllStats() componentStorageStats: this.componentStorageManager.getAllStats()
}; };
} }
@@ -508,10 +700,11 @@ export class Scene implements IScene {
}>; }>;
componentStats: Map<string, any>; componentStats: Map<string, any>;
} { } {
const systems = this.systems;
return { return {
name: this.name || this.constructor.name, name: this.name || this.constructor.name,
entityCount: this.entities.count, entityCount: this.entities.count,
processorCount: this.entityProcessors.count, processorCount: systems.length,
isRunning: this._didSceneBegin, isRunning: this._didSceneBegin,
entities: this.entities.buffer.map(entity => ({ entities: this.entities.buffer.map(entity => ({
name: entity.name, name: entity.name,
@@ -519,7 +712,7 @@ export class Scene implements IScene {
componentCount: entity.components.length, componentCount: entity.components.length,
componentTypes: entity.components.map(c => getComponentInstanceTypeName(c)) componentTypes: entity.components.map(c => getComponentInstanceTypeName(c))
})), })),
processors: this.entityProcessors.processors.map(processor => ({ processors: systems.map(processor => ({
name: getSystemInstanceTypeName(processor), name: getSystemInstanceTypeName(processor),
updateOrder: processor.updateOrder, updateOrder: processor.updateOrder,
entityCount: (processor as any)._entities?.length || 0 entityCount: (processor as any)._entities?.length || 0

View File

@@ -8,6 +8,7 @@ import { getSystemInstanceTypeName } from '../Decorators';
import { createLogger } from '../../Utils/Logger'; import { createLogger } from '../../Utils/Logger';
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem'; import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers'; import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
import type { IService } from '../../Core/ServiceContainer';
/** /**
* 事件监听器记录 * 事件监听器记录
@@ -65,7 +66,7 @@ interface EventListenerRecord {
*/ */
export abstract class EntitySystem< export abstract class EntitySystem<
TComponents extends readonly ComponentConstructor[] = [] TComponents extends readonly ComponentConstructor[] = []
> implements ISystemBase { > implements ISystemBase, IService {
private _updateOrder: number; private _updateOrder: number;
private _enabled: boolean; private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null; private _performanceMonitor: PerformanceMonitor | null;
@@ -222,9 +223,6 @@ export abstract class EntitySystem<
*/ */
public setUpdateOrder(order: number): void { public setUpdateOrder(order: number): void {
this._updateOrder = order; this._updateOrder = order;
if (this.scene && this.scene.entityProcessors) {
this.scene.entityProcessors.setDirty();
}
} }
/** /**
@@ -734,6 +732,34 @@ export abstract class EntitySystem<
// 子类可以重写此方法 // 子类可以重写此方法
} }
/**
* 释放系统资源
*
* 实现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类型增强工具 // 导出TypeScript类型增强工具
export * from './TypeHelpers'; export * from './TypeHelpers';
export * from './IUpdatable';
/** /**
* 组件接口 * 组件接口

View File

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

View File

@@ -1,15 +1,19 @@
import { GlobalManager } from '../GlobalManager';
import { Timer } from './Timer'; import { Timer } from './Timer';
import { ITimer } from './ITimer'; import { ITimer } from './ITimer';
import type { IService } from '../../Core/ServiceContainer'; 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 _timers: Array<Timer<unknown>> = [];
public override update() { public update() {
for (let i = this._timers.length - 1; i >= 0; i --){ for (let i = this._timers.length - 1; i >= 0; i --){
if (this._timers[i].tick()){ if (this._timers[i].tick()){
this._timers[i].unload(); this._timers[i].unload();

View File

@@ -8,6 +8,18 @@ export { Core } from './Core';
export { ServiceContainer, ServiceLifetime } from './Core/ServiceContainer'; export { ServiceContainer, ServiceLifetime } from './Core/ServiceContainer';
export type { IService, ServiceType } 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 { Emitter, FuncPack } from './Utils/Emitter';
export { GlobalManager } from './Utils/GlobalManager'; export { GlobalManager } from './Utils/GlobalManager';

View File

@@ -3,8 +3,10 @@ import { Scene } from '../src/ECS/Scene';
import { SceneManager } from '../src/ECS/SceneManager'; import { SceneManager } from '../src/ECS/SceneManager';
import { Entity } from '../src/ECS/Entity'; import { Entity } from '../src/ECS/Entity';
import { Component } from '../src/ECS/Component'; import { Component } from '../src/ECS/Component';
import { GlobalManager } from '../src/Utils/GlobalManager';
import { ITimer } from '../src/Utils/Timers/ITimer'; 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 { class TestComponent extends Component {
@@ -41,22 +43,18 @@ class TestScene extends Scene {
} }
} }
// 测试全局管理器 // 测试可更新服务
class TestGlobalManager extends GlobalManager { @Updatable()
class TestUpdatableService implements IService, IUpdatable {
public updateCallCount = 0; public updateCallCount = 0;
public override _enabled = false;
public override get enabled(): boolean { public update(): void {
return this._enabled;
}
public override set enabled(value: boolean) {
this._enabled = value;
}
public override update(): void {
this.updateCallCount++; this.updateCallCount++;
} }
public dispose(): void {
// 清理资源
}
} }
describe('Core - 核心管理系统测试', () => { describe('Core - 核心管理系统测试', () => {
@@ -129,96 +127,75 @@ describe('Core - 核心管理系统测试', () => {
// 注意场景管理功能已移至SceneManager // 注意场景管理功能已移至SceneManager
// 相关测试请查看 SceneManager.test.ts // 相关测试请查看 SceneManager.test.ts
describe('更新循环 - 全局服务', () => { describe('更新循环 - 可更新服务', () => {
let core: Core; let core: Core;
let globalManager: TestGlobalManager; let updatableService: TestUpdatableService;
beforeEach(() => { beforeEach(() => {
core = Core.create(true); core = Core.create(true);
globalManager = new TestGlobalManager(); updatableService = new TestUpdatableService();
Core.registerGlobalManager(globalManager); Core.services.registerInstance(TestUpdatableService, updatableService);
}); });
test('应该能够更新全局管理器', () => { test('应该能够更新可更新服务', () => {
Core.update(0.016); Core.update(0.016);
expect(globalManager.updateCallCount).toBe(1); expect(updatableService.updateCallCount).toBe(1);
}); });
test('暂停状态下不应该执行更新', () => { test('暂停状态下不应该执行更新', () => {
Core.paused = true; Core.paused = true;
Core.update(0.016); Core.update(0.016);
expect(globalManager.updateCallCount).toBe(0); expect(updatableService.updateCallCount).toBe(0);
// 恢复状态 // 恢复状态
Core.paused = false; Core.paused = false;
}); });
test('禁用的全局管理器不应该被更新', () => {
globalManager.enabled = false;
Core.update(0.016);
expect(globalManager.updateCallCount).toBe(0);
});
test('多次更新应该累积调用', () => { test('多次更新应该累积调用', () => {
Core.update(0.016); Core.update(0.016);
Core.update(0.016); 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 core: Core;
let manager1: TestGlobalManager; let service1: TestUpdatableService;
let manager2: TestGlobalManager;
beforeEach(() => { beforeEach(() => {
core = Core.create(true); core = Core.create(true);
manager1 = new TestGlobalManager(); service1 = new TestUpdatableService();
manager2 = new TestGlobalManager();
}); });
test('应该能够注册全局管理器', () => { test('应该能够通过ServiceContainer注册可更新服务', () => {
Core.registerGlobalManager(manager1); Core.services.registerInstance(TestUpdatableService, service1);
expect(manager1.enabled).toBe(true);
// 测试更新是否被调用 // 测试更新是否被调用
Core.update(0.016); Core.update(0.016);
expect(manager1.updateCallCount).toBe(1); expect(service1.updateCallCount).toBe(1);
}); });
test('应该能够注销全局管理器', () => { test('应该能够注销服务', () => {
Core.registerGlobalManager(manager1); Core.services.registerInstance(TestUpdatableService, service1);
Core.unregisterGlobalManager(manager1); Core.services.unregister(TestUpdatableService);
expect(manager1.enabled).toBe(false);
// 测试更新不应该被调用 // 测试更新不应该被调用
Core.update(0.016); Core.update(0.016);
expect(manager1.updateCallCount).toBe(0); expect(service1.updateCallCount).toBe(0);
}); });
test('应该能够获取指定类型的全局管理器', () => { test('应该能够通过ServiceContainer解析服务', () => {
Core.registerGlobalManager(manager1); Core.services.registerInstance(TestUpdatableService, service1);
const retrieved = Core.getGlobalManager(TestGlobalManager); const retrieved = Core.services.resolve(TestUpdatableService);
expect(retrieved).toBe(manager1); expect(retrieved).toBe(service1);
}); });
test('获取不存在的管理器应该返回null', () => { test('解析不存在的服务应该抛出错误', () => {
const retrieved = Core.getGlobalManager(TestGlobalManager); expect(() => {
expect(retrieved).toBeNull(); Core.services.resolve(TestUpdatableService);
}); }).toThrow();
test('应该能够管理多个全局管理器', () => {
Core.registerGlobalManager(manager1);
Core.registerGlobalManager(manager2);
Core.update(0.016);
expect(manager1.updateCallCount).toBe(1);
expect(manager2.updateCallCount).toBe(1);
}); });
}); });

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

@@ -335,7 +335,7 @@ describe('FluentAPI - 流式API测试', () => {
.withSystems(system1, system2) .withSystems(system1, system2)
.build(); .build();
expect(scene.systems.length).toBe(2); expect(scene.systems.length).toBe(1);
}); });
test('流式调用应该工作正常', () => { 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).toBeInstanceOf(Scene);
expect(scene.name).toBe(""); expect(scene.name).toBe("");
expect(scene.entities).toBeDefined(); expect(scene.entities).toBeDefined();
expect(scene.entityProcessors).toBeDefined(); expect(scene.systems).toBeDefined();
expect(scene.identifierPool).toBeDefined(); expect(scene.identifierPool).toBeDefined();
}); });
@@ -140,7 +140,7 @@ describe('Scene - 场景管理系统测试', () => {
test('场景应该有正确的初始状态', () => { test('场景应该有正确的初始状态', () => {
expect(scene.entities.count).toBe(0); expect(scene.entities.count).toBe(0);
expect(scene.entityProcessors.count).toBe(0); expect(scene.systems.length).toBe(0);
}); });
test('应该能够使用配置创建场景', () => { test('应该能够使用配置创建场景', () => {
@@ -249,7 +249,7 @@ describe('Scene - 场景管理系统测试', () => {
test('应该能够添加实体系统', () => { test('应该能够添加实体系统', () => {
scene.addEntityProcessor(movementSystem); scene.addEntityProcessor(movementSystem);
expect(scene.entityProcessors.count).toBe(1); expect(scene.systems.length).toBe(1);
expect(movementSystem.scene).toBe(scene); expect(movementSystem.scene).toBe(scene);
}); });
@@ -257,7 +257,7 @@ describe('Scene - 场景管理系统测试', () => {
scene.addEntityProcessor(movementSystem); scene.addEntityProcessor(movementSystem);
scene.removeEntityProcessor(movementSystem); scene.removeEntityProcessor(movementSystem);
expect(scene.entityProcessors.count).toBe(0); expect(scene.systems.length).toBe(0);
expect(movementSystem.scene).toBeNull(); expect(movementSystem.scene).toBeNull();
}); });
@@ -271,7 +271,7 @@ describe('Scene - 场景管理系统测试', () => {
scene.addEntityProcessor(movementSystem); scene.addEntityProcessor(movementSystem);
scene.addEntityProcessor(renderSystem); scene.addEntityProcessor(renderSystem);
expect(scene.entityProcessors.count).toBe(2); expect(scene.systems.length).toBe(2);
}); });
test('系统应该按更新顺序执行', () => { test('系统应该按更新顺序执行', () => {
@@ -538,10 +538,11 @@ describe('Scene - 场景管理系统测试', () => {
test('重复添加同一个系统应该安全处理', () => { test('重复添加同一个系统应该安全处理', () => {
const system = new MovementSystem(); const system = new MovementSystem();
scene.addEntityProcessor(system);
scene.addEntityProcessor(system); // 重复添加
expect(scene.entityProcessors.count).toBe(1); scene.addEntityProcessor(system);
scene.addEntityProcessor(system);
expect(scene.systems.length).toBe(1);
}); });
test('系统处理过程中的异常应该被正确处理', () => { test('系统处理过程中的异常应该被正确处理', () => {