From 3ad5dc9ca337417e15eb8952b9de9c9aa6384c9f Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Sat, 1 Nov 2025 16:12:18 +0800 Subject: [PATCH] =?UTF-8?q?refactor(core):=20=E6=94=B9=E8=BF=9B=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E7=B3=BB=E7=BB=9F=E7=B1=BB=E5=9E=8B=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E5=B9=B6=E6=B6=88=E9=99=A4=20ESLint=20=E8=AD=A6=E5=91=8A=20(#2?= =?UTF-8?q?08)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/ECS/Core/EventBus.ts | 126 ++++++------- packages/core/src/ECS/Core/EventSystem.ts | 64 ++++--- packages/core/src/ECS/Systems/EntityCache.ts | 166 ++++++++++++++++++ packages/core/src/ECS/Systems/EntitySystem.ts | 85 ++++----- packages/core/src/Types/index.ts | 4 +- .../tests/ECS/Systems/EntitySystem.test.ts | 24 +-- 6 files changed, 310 insertions(+), 159 deletions(-) create mode 100644 packages/core/src/ECS/Systems/EntityCache.ts diff --git a/packages/core/src/ECS/Core/EventBus.ts b/packages/core/src/ECS/Core/EventBus.ts index b51b0e92..37ed4b25 100644 --- a/packages/core/src/ECS/Core/EventBus.ts +++ b/packages/core/src/ECS/Core/EventBus.ts @@ -1,6 +1,6 @@ -import { - IEventBus, - IEventListenerConfig, +import { + IEventBus, + IEventListenerConfig, IEventStats, IEventData, IEntityEventData, @@ -10,10 +10,10 @@ import { IPerformanceEventData } from '../../Types'; import { createLogger } from '../../Utils/Logger'; -import { - TypeSafeEventSystem, - EventListenerConfig, - EventStats +import { + TypeSafeEventSystem, + EventListenerConfig, + EventStats } from './EventSystem'; import { ECSEventType, @@ -30,12 +30,12 @@ export class EventBus implements IEventBus { private eventSystem: TypeSafeEventSystem; private eventIdCounter = 0; private isDebugMode = false; - + constructor(debugMode: boolean = false) { this.eventSystem = new TypeSafeEventSystem(); this.isDebugMode = debugMode; } - + /** * 发射事件 * @param eventType 事件类型 @@ -53,7 +53,7 @@ export class EventBus implements IEventBus { this.eventSystem.emitSync(eventType, finalData); } - + /** * 异步发射事件 * @param eventType 事件类型 @@ -71,7 +71,7 @@ export class EventBus implements IEventBus { await this.eventSystem.emit(eventType, finalData); } - + /** * 监听事件 * @param eventType 事件类型 @@ -80,26 +80,29 @@ export class EventBus implements IEventBus { * @returns 监听器ID */ public on( - eventType: string, - handler: (data: T) => void, + eventType: string, + handler: (data: T) => void, config: IEventListenerConfig = {} ): string { this.validateEventType(eventType); - + const eventConfig: EventListenerConfig = { once: config.once || false, priority: config.priority || EventPriority.NORMAL, - async: config.async || false, - context: config.context + async: config.async || false }; - + + if (config.thisArg) { + eventConfig.thisArg = config.thisArg as object; + } + if (this.isDebugMode) { EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig); } - + return this.eventSystem.on(eventType, handler, eventConfig); } - + /** * 监听事件(一次性) * @param eventType 事件类型 @@ -108,13 +111,13 @@ export class EventBus implements IEventBus { * @returns 监听器ID */ public once( - eventType: string, - handler: (data: T) => void, + eventType: string, + handler: (data: T) => void, config: IEventListenerConfig = {} ): string { return this.on(eventType, handler, { ...config, once: true }); } - + /** * 异步监听事件 * @param eventType 事件类型 @@ -123,13 +126,13 @@ export class EventBus implements IEventBus { * @returns 监听器ID */ public onAsync( - eventType: string, - handler: (data: T) => Promise, + eventType: string, + handler: (data: T) => Promise, config: IEventListenerConfig = {} ): string { - return this.on(eventType, handler as any, { ...config, async: true }); + return this.on(eventType, handler, { ...config, async: true }); } - + /** * 移除事件监听器 * @param eventType 事件类型 @@ -139,10 +142,10 @@ export class EventBus implements IEventBus { if (this.isDebugMode) { EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`); } - + return this.eventSystem.off(eventType, listenerId); } - + /** * 移除指定事件类型的所有监听器 * @param eventType 事件类型 @@ -151,10 +154,10 @@ export class EventBus implements IEventBus { if (this.isDebugMode) { EventBus._logger.info(`移除所有监听器: ${eventType}`); } - + this.eventSystem.offAll(eventType); } - + /** * 检查是否有指定事件的监听器 * @param eventType 事件类型 @@ -162,14 +165,14 @@ export class EventBus implements IEventBus { public hasListeners(eventType: string): boolean { return this.eventSystem.hasListeners(eventType); } - + /** * 获取事件统计信息 * @param eventType 事件类型(可选) */ public getStats(eventType?: string): IEventStats | Map { const stats = this.eventSystem.getStats(eventType); - + if (stats instanceof Map) { // 转换Map中的每个EventStats为IEventStats const result = new Map(); @@ -181,7 +184,7 @@ export class EventBus implements IEventBus { return this.convertEventStats(stats); } } - + /** * 清空所有监听器 */ @@ -189,10 +192,10 @@ export class EventBus implements IEventBus { if (this.isDebugMode) { EventBus._logger.info('清空所有监听器'); } - + this.eventSystem.clear(); } - + /** * 启用或禁用事件系统 * @param enabled 是否启用 @@ -200,7 +203,7 @@ export class EventBus implements IEventBus { public setEnabled(enabled: boolean): void { this.eventSystem.setEnabled(enabled); } - + /** * 设置调试模式 * @param debug 是否启用调试 @@ -208,7 +211,7 @@ export class EventBus implements IEventBus { public setDebugMode(debug: boolean): void { this.isDebugMode = debug; } - + /** * 设置最大监听器数量 * @param max 最大数量 @@ -216,7 +219,7 @@ export class EventBus implements IEventBus { public setMaxListeners(max: number): void { this.eventSystem.setMaxListeners(max); } - + /** * 获取监听器数量 * @param eventType 事件类型 @@ -224,7 +227,7 @@ export class EventBus implements IEventBus { public getListenerCount(eventType: string): number { return this.eventSystem.getListenerCount(eventType); } - + /** * 设置事件批处理配置 * @param eventType 事件类型 @@ -238,7 +241,7 @@ export class EventBus implements IEventBus { enabled: true }); } - + /** * 刷新指定事件的批处理队列 * @param eventType 事件类型 @@ -246,7 +249,7 @@ export class EventBus implements IEventBus { public flushBatch(eventType: string): void { this.eventSystem.flushBatch(eventType); } - + /** * 重置事件统计 * @param eventType 事件类型(可选) @@ -254,9 +257,9 @@ export class EventBus implements IEventBus { public resetStats(eventType?: string): void { this.eventSystem.resetStats(eventType); } - + // 便捷方法:发射预定义的ECS事件 - + /** * 发射实体创建事件 * @param entityData 实体事件数据 @@ -320,59 +323,59 @@ export class EventBus implements IEventBus { public emitPerformanceWarning(performanceData: IPerformanceEventData): void { this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData); } - + // 便捷方法:监听预定义的ECS事件 - + /** * 监听实体创建事件 * @param handler 事件处理器 * @param config 监听器配置 */ public onEntityCreated( - handler: (data: IEntityEventData) => void, + handler: (data: IEntityEventData) => void, config?: IEventListenerConfig ): string { return this.on(ECSEventType.ENTITY_CREATED, handler, config); } - + /** * 监听组件添加事件 * @param handler 事件处理器 * @param config 监听器配置 */ public onComponentAdded( - handler: (data: IComponentEventData) => void, + handler: (data: IComponentEventData) => void, config?: IEventListenerConfig ): string { return this.on(ECSEventType.COMPONENT_ADDED, handler, config); } - + /** * 监听系统错误事件 * @param handler 事件处理器 * @param config 监听器配置 */ public onSystemError( - handler: (data: ISystemEventData) => void, + handler: (data: ISystemEventData) => void, config?: IEventListenerConfig ): string { return this.on(ECSEventType.SYSTEM_ERROR, handler, config); } - + /** * 监听性能警告事件 * @param handler 事件处理器 * @param config 监听器配置 */ public onPerformanceWarning( - handler: (data: IPerformanceEventData) => void, + handler: (data: IPerformanceEventData) => void, config?: IEventListenerConfig ): string { return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config); } - + // 私有方法 - + /** * 验证事件类型(仅在debug模式下执行,提升性能) * @param eventType 事件类型 @@ -387,7 +390,7 @@ export class EventBus implements IEventBus { } } } - + /** * 增强事件数据 * @param eventType 事件类型 @@ -402,9 +405,9 @@ export class EventBus implements IEventBus { source: 'EventBus' } as T & IEventData; } - + const enhanced = data as T & IEventData; - + // 如果数据还没有基础事件属性,添加它们 if (!enhanced.timestamp) { enhanced.timestamp = Date.now(); @@ -415,10 +418,10 @@ export class EventBus implements IEventBus { if (!enhanced.source) { enhanced.source = 'EventBus'; } - + return enhanced; } - + /** * 转换EventStats为IEventStats * @param stats EventStats实例 @@ -441,7 +444,7 @@ export class EventBus implements IEventBus { */ export class GlobalEventBus { private static instance: EventBus; - + /** * 获取全局事件总线实例 * @param debugMode 是否启用调试模式 @@ -452,7 +455,7 @@ export class GlobalEventBus { } return this.instance; } - + /** * 重置全局事件总线实例 * @param debugMode 是否启用调试模式 @@ -466,4 +469,3 @@ export class GlobalEventBus { } } - \ No newline at end of file diff --git a/packages/core/src/ECS/Core/EventSystem.ts b/packages/core/src/ECS/Core/EventSystem.ts index 0786e4fe..8a7809bd 100644 --- a/packages/core/src/ECS/Core/EventSystem.ts +++ b/packages/core/src/ECS/Core/EventSystem.ts @@ -3,12 +3,12 @@ import { createLogger } from '../../Utils/Logger'; /** * 事件处理器函数类型 */ -export type EventHandler = (event: T) => void; +export type EventHandler = (event: T) => void; /** * 异步事件处理器函数类型 */ -export type AsyncEventHandler = (event: T) => Promise; +export type AsyncEventHandler = (event: T) => Promise; /** * 事件监听器配置 @@ -20,15 +20,20 @@ export interface EventListenerConfig { priority?: number; /** 是否异步执行 */ async?: boolean; - /** 执行上下文 */ - context?: any; + /** 事件处理函数的 this 绑定对象 */ + thisArg?: object; } /** * 内部事件监听器 + * + * 注意:handler 使用 any 是必要的类型擦除 + * 原因:需要在同一数组中存储处理不同事件类型(T)的监听器 + * 类型安全保证:公共 API (on/emit) 在编译时保证类型匹配 */ -interface InternalEventListener { - handler: EventHandler | AsyncEventHandler; +interface InternalEventListener { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handler: EventHandler | AsyncEventHandler; config: EventListenerConfig; id: string; } @@ -71,8 +76,9 @@ export class TypeSafeEventSystem { private static readonly _logger = createLogger('EventSystem'); private listeners = new Map(); private stats = new Map(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any private batchQueue = new Map(); - private batchTimers = new Map(); + private batchTimers = new Map>(); private batchConfigs = new Map(); private nextListenerId = 0; private isEnabled = true; @@ -81,13 +87,13 @@ export class TypeSafeEventSystem { /** * 添加事件监听器 * @param eventType 事件类型 - * @param handler 事件处理器 + * @param handler 事件处理器(同步或异步,根据 config.async 决定) * @param config 监听器配置 * @returns 监听器ID(用于移除) */ public on( eventType: string, - handler: EventHandler, + handler: EventHandler | AsyncEventHandler, config: EventListenerConfig = {} ): string { return this.addListener(eventType, handler, config); @@ -100,11 +106,7 @@ export class TypeSafeEventSystem { * @param config 监听器配置 * @returns 监听器ID */ - public once( - eventType: string, - handler: EventHandler, - config: EventListenerConfig = {} - ): string { + public once(eventType: string, handler: EventHandler, config: EventListenerConfig = {}): string { return this.addListener(eventType, handler, { ...config, once: true }); } @@ -115,11 +117,7 @@ export class TypeSafeEventSystem { * @param config 监听器配置 * @returns 监听器ID */ - public onAsync( - eventType: string, - handler: AsyncEventHandler, - config: EventListenerConfig = {} - ): string { + public onAsync(eventType: string, handler: AsyncEventHandler, config: EventListenerConfig = {}): string { return this.addListener(eventType, handler, { ...config, async: true }); } @@ -133,7 +131,7 @@ export class TypeSafeEventSystem { const listeners = this.listeners.get(eventType); if (!listeners) return false; - const index = listeners.findIndex(l => l.id === listenerId); + const index = listeners.findIndex((l) => l.id === listenerId); if (index === -1) return false; listeners.splice(index, 1); @@ -197,8 +195,8 @@ export class TypeSafeEventSystem { if (listener.config.async) continue; // 跳过异步监听器 try { - if (listener.config.context) { - (listener.handler as EventHandler).call(listener.config.context, event); + if (listener.config.thisArg) { + (listener.handler as EventHandler).call(listener.config.thisArg, event); } else { (listener.handler as EventHandler)(event); } @@ -344,7 +342,7 @@ export class TypeSafeEventSystem { } const listenerId = `listener_${this.nextListenerId++}`; - const listener: InternalEventListener = { + const listener: InternalEventListener = { handler, config: { priority: 0, @@ -379,14 +377,14 @@ export class TypeSafeEventSystem { const sortedListeners = this.sortListenersByPriority(listeners); // 分离同步和异步监听器 - const syncListeners = sortedListeners.filter(l => !l.config.async); - const asyncListeners = sortedListeners.filter(l => l.config.async); + const syncListeners = sortedListeners.filter((l) => !l.config.async); + const asyncListeners = sortedListeners.filter((l) => l.config.async); // 执行同步监听器 for (const listener of syncListeners) { try { - if (listener.config.context) { - (listener.handler as EventHandler).call(listener.config.context, event); + if (listener.config.thisArg) { + (listener.handler as EventHandler).call(listener.config.thisArg, event); } else { (listener.handler as EventHandler)(event); } @@ -402,8 +400,8 @@ export class TypeSafeEventSystem { // 执行异步监听器 const asyncPromises = asyncListeners.map(async (listener) => { try { - if (listener.config.context) { - await (listener.handler as AsyncEventHandler).call(listener.config.context, event); + if (listener.config.thisArg) { + await (listener.handler as AsyncEventHandler).call(listener.config.thisArg, event); } else { await (listener.handler as AsyncEventHandler)(event); } @@ -431,7 +429,7 @@ export class TypeSafeEventSystem { * @param listeners 监听器数组 * @returns 排序后的监听器数组 */ - private sortListenersByPriority(listeners: InternalEventListener[]): InternalEventListener[] { + private sortListenersByPriority(listeners: InternalEventListener[]): InternalEventListener[] { return listeners.slice().sort((a, b) => (b.config.priority || 0) - (a.config.priority || 0)); } @@ -447,7 +445,7 @@ export class TypeSafeEventSystem { if (!listeners) return; for (const id of listenerIds) { - const index = listeners.findIndex(l => l.id === id); + const index = listeners.findIndex((l) => l.id === id); if (index !== -1) { listeners.splice(index, 1); } @@ -488,7 +486,7 @@ export class TypeSafeEventSystem { this.flushBatch(eventType); }, config.delay); - this.batchTimers.set(eventType, timer as any); + this.batchTimers.set(eventType, timer); } } @@ -577,5 +575,3 @@ export class TypeSafeEventSystem { * 全局事件系统实例 */ export const GlobalEventSystem = new TypeSafeEventSystem(); - - \ No newline at end of file diff --git a/packages/core/src/ECS/Systems/EntityCache.ts b/packages/core/src/ECS/Systems/EntityCache.ts new file mode 100644 index 00000000..7b299dc5 --- /dev/null +++ b/packages/core/src/ECS/Systems/EntityCache.ts @@ -0,0 +1,166 @@ +import { Entity } from '../Entity'; + +/** + * 实体缓存管理器 + * + * 负责管理 EntitySystem 中的实体缓存,提供帧缓存和持久缓存两级缓存机制。 + * 使用面向对象设计,将数据和行为封装在类中。 + * + * @example + * ```typescript + * const cache = new EntityCache(); + * cache.setPersistent(entities); + * const cached = cache.getPersistent(); + * cache.invalidate(); + * ``` + */ +export class EntityCache { + /** + * 帧缓存 + * + * 在update周期内使用,每帧结束后清理 + */ + private _frameCache: readonly Entity[] | null = null; + + /** + * 持久缓存 + * + * 跨帧使用,直到被显式失效 + */ + private _persistentCache: readonly Entity[] | null = null; + + /** + * 被跟踪的实体集合 + * + * 用于跟踪哪些实体正在被此系统处理 + */ + private _trackedEntities: Set = new Set(); + + /** + * 获取帧缓存 + */ + public getFrame(): readonly Entity[] | null { + return this._frameCache; + } + + /** + * 设置帧缓存 + * + * @param entities 要缓存的实体列表 + */ + public setFrame(entities: readonly Entity[]): void { + this._frameCache = entities; + } + + /** + * 获取持久缓存 + */ + public getPersistent(): readonly Entity[] | null { + return this._persistentCache; + } + + /** + * 设置持久缓存 + * + * @param entities 要缓存的实体列表 + */ + public setPersistent(entities: readonly Entity[]): void { + this._persistentCache = entities; + } + + /** + * 获取被跟踪的实体集合 + */ + public getTracked(): ReadonlySet { + return this._trackedEntities; + } + + /** + * 添加被跟踪的实体 + * + * @param entity 要跟踪的实体 + */ + public addTracked(entity: Entity): void { + this._trackedEntities.add(entity); + } + + /** + * 移除被跟踪的实体 + * + * @param entity 要移除的实体 + */ + public removeTracked(entity: Entity): void { + this._trackedEntities.delete(entity); + } + + /** + * 检查实体是否被跟踪 + * + * @param entity 要检查的实体 + */ + public isTracked(entity: Entity): boolean { + return this._trackedEntities.has(entity); + } + + /** + * 使持久缓存失效 + * + * 当实体变化时调用,强制下次查询时重新计算 + */ + public invalidate(): void { + this._persistentCache = null; + } + + /** + * 清除帧缓存 + * + * 在每帧结束时调用 + */ + public clearFrame(): void { + this._frameCache = null; + } + + /** + * 清除所有缓存 + * + * 在系统重置或销毁时调用 + */ + public clearAll(): void { + this._frameCache = null; + this._persistentCache = null; + this._trackedEntities.clear(); + } + + /** + * 检查是否有有效的持久缓存 + */ + public hasPersistent(): boolean { + return this._persistentCache !== null; + } + + /** + * 检查是否有有效的帧缓存 + */ + public hasFrame(): boolean { + return this._frameCache !== null; + } + + /** + * 获取缓存统计信息 + */ + public getStats(): { + hasFrame: boolean; + hasPersistent: boolean; + trackedCount: number; + frameEntityCount: number; + persistentEntityCount: number; + } { + return { + hasFrame: this._frameCache !== null, + hasPersistent: this._persistentCache !== null, + trackedCount: this._trackedEntities.size, + frameEntityCount: this._frameCache?.length ?? 0, + persistentEntityCount: this._persistentCache?.length ?? 0 + }; + } +} diff --git a/packages/core/src/ECS/Systems/EntitySystem.ts b/packages/core/src/ECS/Systems/EntitySystem.ts index 4951d8a1..baa4faf2 100644 --- a/packages/core/src/ECS/Systems/EntitySystem.ts +++ b/packages/core/src/ECS/Systems/EntitySystem.ts @@ -9,14 +9,15 @@ 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'; +import { EntityCache } from './EntityCache'; /** * 事件监听器记录 + * 只存储引用信息,用于系统销毁时自动清理 */ interface EventListenerRecord { eventSystem: TypeSafeEventSystem; eventType: string; - handler: EventHandler; listenerRef: string; } @@ -63,9 +64,7 @@ interface EventListenerRecord { * } * ``` */ -export abstract class EntitySystem<_TComponents extends readonly ComponentConstructor[] = []> - implements ISystemBase, IService -{ +export abstract class EntitySystem implements ISystemBase, IService { private _updateOrder: number; private _enabled: boolean; private _performanceMonitor: PerformanceMonitor | null; @@ -85,30 +84,24 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr /** * 统一的实体缓存管理器 */ - private _entityCache: { - frame: readonly Entity[] | null; - persistent: readonly Entity[] | null; - tracked: Set; - invalidate(): void; - clearFrame(): void; - clearAll(): void; - }; + private _entityCache: EntityCache; /** * 获取系统处理的实体列表 */ public get entities(): readonly Entity[] { // 如果在update周期内,优先使用帧缓存 - if (this._entityCache.frame !== null) { - return this._entityCache.frame; + const frameCache = this._entityCache.getFrame(); + if (frameCache !== null) { + return frameCache; } // 否则使用持久缓存 - if (this._entityCache.persistent === null) { - this._entityCache.persistent = this.queryEntities(); + if (!this._entityCache.hasPersistent()) { + this._entityCache.setPersistent(this.queryEntities()); } - return this._entityCache.persistent; + return this._entityCache.getPersistent()!; } /** @@ -159,22 +152,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr // 初始化logger this.logger = createLogger(this.getLoggerName()); - this._entityCache = { - frame: null, - persistent: null, - tracked: new Set(), - invalidate() { - this.persistent = null; - }, - clearFrame() { - this.frame = null; - }, - clearAll() { - this.frame = null; - this.persistent = null; - this.tracked.clear(); - } - }; + this._entityCache = new EntityCache(); } /** @@ -521,7 +499,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr const entityMap = this.getEntityIdMap(allEntities); const size = idSet.size; - const result = new Array(size); + const result = new Array(size); let index = 0; for (const id of idSet) { @@ -564,10 +542,11 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr this.onBegin(); // 查询实体并存储到帧缓存中 // 响应式查询会自动维护最新的实体列表,updateEntityTracking会在检测到变化时invalidate - this._entityCache.frame = this.queryEntities(); - entityCount = this._entityCache.frame.length; + const queriedEntities = this.queryEntities(); + this._entityCache.setFrame(queriedEntities); + entityCount = queriedEntities.length; - this.process(this._entityCache.frame); + this.process(queriedEntities); } finally { monitor.endMonitoring(this._systemName, startTime, entityCount); } @@ -587,7 +566,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr try { // 使用缓存的实体列表,避免重复查询 - const entities = this._entityCache.frame || []; + const entities = this._entityCache.getFrame() || []; entityCount = entities.length; this.lateProcess(entities); this.onEnd(); @@ -697,17 +676,17 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr // 检查新增的实体 for (const entity of currentEntities) { - if (!this._entityCache.tracked.has(entity)) { - this._entityCache.tracked.add(entity); + if (!this._entityCache.isTracked(entity)) { + this._entityCache.addTracked(entity); this.onAdded(entity); hasChanged = true; } } // 检查移除的实体 - for (const entity of this._entityCache.tracked) { + for (const entity of this._entityCache.getTracked()) { if (!currentSet.has(entity)) { - this._entityCache.tracked.delete(entity); + this._entityCache.removeTracked(entity); this.onRemoved(entity); hasChanged = true; } @@ -778,15 +757,16 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr * @param eventType 事件类型 * @param handler 事件处理函数 * @param config 监听器配置 + * @returns 监听器引用ID,可用于手动移除监听器 */ - protected addEventListener( + protected addEventListener( eventType: string, handler: EventHandler, config?: EventListenerConfig - ): void { + ): string | null { if (!this.scene?.eventSystem) { this.logger.warn(`${this.systemName}: 无法添加事件监听器,scene.eventSystem 不可用`); - return; + return null; } const listenerRef = this.scene.eventSystem.on(eventType, handler, config); @@ -796,21 +776,22 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr this._eventListeners.push({ eventSystem: this.scene.eventSystem, eventType, - handler, listenerRef }); } + + return listenerRef; } /** * 移除特定的事件监听器 * * @param eventType 事件类型 - * @param handler 事件处理函数 + * @param listenerRef 监听器引用ID(由 addEventListener 返回) */ - protected removeEventListener(eventType: string, handler: EventHandler): void { + protected removeEventListener(eventType: string, listenerRef: string): void { const listenerIndex = this._eventListeners.findIndex( - (listener) => listener.eventType === eventType && listener.handler === handler + (listener) => listener.eventType === eventType && listener.listenerRef === listenerRef ); if (listenerIndex >= 0) { @@ -895,7 +876,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr * ``` */ protected requireComponent(entity: Entity, componentType: T): ComponentInstance { - const component = entity.getComponent(componentType as any); + const component = entity.getComponent(componentType); if (!component) { throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`); } @@ -929,7 +910,9 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr entity: Entity, ...components: T ): { [K in keyof T]: ComponentInstance } { - return components.map((type) => this.requireComponent(entity, type)) as any; + return components.map((type) => this.requireComponent(entity, type)) as { + [K in keyof T]: ComponentInstance; + }; } /** diff --git a/packages/core/src/Types/index.ts b/packages/core/src/Types/index.ts index 28ab3a11..14fdaa7f 100644 --- a/packages/core/src/Types/index.ts +++ b/packages/core/src/Types/index.ts @@ -142,8 +142,8 @@ export interface IEventListenerConfig { priority?: number; /** 是否异步执行 */ async?: boolean; - /** 执行上下文 */ - context?: unknown; + /** 事件处理函数的 this 绑定对象 */ + thisArg?: object; } /** diff --git a/packages/core/tests/ECS/Systems/EntitySystem.test.ts b/packages/core/tests/ECS/Systems/EntitySystem.test.ts index c82a9b3a..862c38a8 100644 --- a/packages/core/tests/ECS/Systems/EntitySystem.test.ts +++ b/packages/core/tests/ECS/Systems/EntitySystem.test.ts @@ -50,17 +50,19 @@ class ConcreteEntitySystem extends EntitySystem { const handler = (event: any) => { this.eventHandlerCallCount++; }; - this.addEventListener('manual_event', handler); - this.removeEventListener('manual_event', handler); + const listenerRef = this.addEventListener('manual_event', handler); + if (listenerRef) { + this.removeEventListener('manual_event', listenerRef); + } } // 公开测试方法 - public testAddEventListener(eventType: string, handler: (event: any) => void): void { - this.addEventListener(eventType, handler); + public testAddEventListener(eventType: string, handler: (event: any) => void): string | null { + return this.addEventListener(eventType, handler); } - public testRemoveEventListener(eventType: string, handler: (event: any) => void): void { - this.removeEventListener(eventType, handler); + public testRemoveEventListener(eventType: string, listenerRef: string): void { + this.removeEventListener(eventType, listenerRef); } } @@ -118,14 +120,16 @@ describe('EntitySystem', () => { const handler = jest.fn(); // 添加监听器 - system.testAddEventListener('manual_remove_event', handler); + const listenerRef = system.testAddEventListener('manual_remove_event', handler); // 发射事件验证监听器工作 scene.eventSystem.emitSync('manual_remove_event', {}); expect(handler).toHaveBeenCalledTimes(1); // 移除监听器 - system.testRemoveEventListener('manual_remove_event', handler); + if (listenerRef) { + system.testRemoveEventListener('manual_remove_event', listenerRef); + } // 再次发射事件 scene.eventSystem.emitSync('manual_remove_event', {}); @@ -205,11 +209,11 @@ describe('EntitySystem', () => { }); it('当移除不存在的监听器时,应该安全处理', () => { - const nonExistentHandler = () => {}; + const nonExistentListenerRef = 'non_existent_listener_ref'; // 应该不会抛出错误 expect(() => { - system.testRemoveEventListener('non_existent_event', nonExistentHandler); + system.testRemoveEventListener('non_existent_event', nonExistentListenerRef); }).not.toThrow(); }); });