diff --git a/assets/core/common/event/EventDispatcher.ts b/assets/core/common/event/EventDispatcher.ts index 042c51b..bee76e1 100644 --- a/assets/core/common/event/EventDispatcher.ts +++ b/assets/core/common/event/EventDispatcher.ts @@ -1,94 +1,203 @@ -/* - * @Author: dgflash - * @Date: 2022-09-01 18:00:28 - * @LastEditors: dgflash - * @LastEditTime: 2022-09-02 10:57:01 - */ import type { ListenerFunc } from './EventMessage'; -import { MessageEventData } from './MessageEventData'; +import type { TypedEventMap } from './MessageManager'; +import { EventData } from './EventData'; +import { EventDataPool } from './EventDataPool'; +import { message } from './MessageManager'; -/** - * 事件对象基类,继承该类将拥有发送和接收事件的能力 - * - * @性能优化 - * - 懒加载 MessageEventData 实例,未使用事件功能时不占用内存 - * - 支持批量清理事件,避免逐个移除的性能损耗 - * - 使用对象池管理内部 EventData 对象 - * - * @内存管理 - * ⚠️ 必须在对象销毁时调用 destroy() 方法,否则会导致内存泄漏 - * - * @example - * class MyClass extends EventDispatcher { - * constructor() { - * super(); - * this.on('myEvent', this.onMyEvent, this); - * } - * - * onMyEvent(event: string, data: any) { - * console.log('收到事件:', event, data); - * } - * - * destroy() { - * super.destroy(); // 清理所有事件监听 - * } - * } - */ +/** 批量注册、移除全局事件对象(用于组件级事件管理) */ export class EventDispatcher { - protected _msg: MessageEventData | null = null; + /** 本地事件列表,用于批量清理 */ + private events: Map> = new Map(); - /** 确保 MessageEventData 已初始化 */ - private ensureMessageEventData(): MessageEventData { - if (this._msg == null) { - this._msg = new MessageEventData(); + /** + * 注册全局事件(强类型) + * @param event 事件名(枚举) + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的作用域对象 + */ + on( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: object + ): void; + + /** + * 注册全局事件(兼容旧用法) + * @param event 事件名 + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的作用域对象 + */ + on(event: string, listener: ListenerFunc, object: object): void; + + /** + * 注册全局事件(实现) + */ + on(event: string, listener: ListenerFunc, object: object): void { + // 先注册到全局消息管理器 + message.on(event, listener, object); + + // 记录到本地事件列表,用于批量清理 + let eds = this.events.get(event); + if (eds == null) { + eds = []; + this.events.set(event, eds); } - return this._msg; + + const ed: EventData = EventDataPool.get(); + ed.event = event; + ed.listener = listener; + ed.object = object; + eds.push(ed); } /** - * 注册全局事件 - * @param event 事件名 - * @param listener 处理事件的侦听器函数 + * 监听一次事件,事件响应后,该监听自动移除(强类型) + * @param event 事件名(枚举) + * @param listener 事件触发回调方法 * @param object 侦听函数绑定的作用域对象 */ - on(event: string, listener: ListenerFunc, object: any) { - this.ensureMessageEventData().on(event, listener, object); + once( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: object + ): void; + + /** + * 监听一次事件,事件响应后,该监听自动移除(兼容旧用法) + * @param event 事件名 + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的作用域对象 + */ + once(event: string, listener: ListenerFunc, object: object): void; + + /** + * 监听一次事件,事件响应后,该监听自动移除(实现) + */ + once(event: string, listener: ListenerFunc, object: object): void { + message.once(event, listener, object); + + // 记录到本地事件列表 + let eds = this.events.get(event); + if (eds == null) { + eds = []; + this.events.set(event, eds); + } + + const ed: EventData = EventDataPool.get(); + ed.event = event; + ed.listener = listener; + ed.object = object; + eds.push(ed); } /** - * 移除全局事件 - * @param event 事件名 - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) + * 移除全局事件(强类型) + * @param event 事件名(枚举) + * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) + * @param object 侦听函数绑定的作用域对象(可选) */ - off(event: string, listener?: ListenerFunc, object?: any) { - if (this._msg) { - // 支持精确移除单个监听器 - if (listener) { - this._msg.off(event, listener, object); - } else { - // 移除该事件的所有监听器 - this._msg.off(event); + off( + event: K, + listener?: (event: K, data: TypedEventMap[K]) => void, + object?: object + ): void; + + /** + * 移除全局事件(兼容旧用法) + * @param event 事件名 + * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) + * @param object 侦听函数绑定的作用域对象(可选) + */ + off(event: string, listener?: ListenerFunc, object?: object): void; + + /** + * 移除全局事件(实现) + */ + off(event: string, listener?: ListenerFunc, object?: object): void { + const eds = this.events.get(event); + if (!eds) return; + + // 如果没有指定 listener,移除该事件的所有监听器 + if (!listener) { + for (const eb of eds) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); } + this.events.delete(event); + return; + } + + // 移除指定的监听器 + const length = eds.length; + for (let i = 0; i < length; i++) { + const eb = eds[i]; + if (eb.listener == listener && eb.object == object) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); + eds.splice(i, 1); + break; + } + } + + // 如果该事件已无监听器,删除事件 + if (eds.length == 0) { + this.events.delete(event); } } /** - * 触发全局事件 + * 触发强类型事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + */ + emit( + event: K, + data: TypedEventMap[K] + ): void { + message.emit(event, data); + } + + /** + * 触发全局事件(兼容旧用法) * @param event 事件名 * @param args 事件参数 */ - dispatchEvent(event: string, ...args: any) { - this.ensureMessageEventData().dispatchEvent(event, ...args); + + dispatchEvent(event: string, ...args: any[]): void { + message.dispatchEvent(event, ...args); } /** - * 销毁事件对象,释放所有事件监听 + * 触发强类型异步事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) */ - destroy() { - if (this._msg) { - this._msg.clear(); - this._msg = null; + emitAsync( + event: K, + data: TypedEventMap[K] + ): Promise { + return message.emitAsync(event, data); + } + + /** + * 触发全局事件,支持同步与异步处理(兼容旧用法) + * @param event 事件名 + * @param args 事件参数 + */ + + dispatchEventAsync(event: string, ...args: any[]): Promise { + return message.dispatchEventAsync(event, ...args); + } + + /** 清除所有的全局事件监听 */ + clear(): void { + // 直接遍历 Map,避免创建临时数组 + for (const [event, eds] of this.events) { + for (const eb of eds) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); + } } + this.events.clear(); } } diff --git a/assets/core/common/event/MessageEventData.ts b/assets/core/common/event/MessageEventData.ts deleted file mode 100644 index 5d99f2b..0000000 --- a/assets/core/common/event/MessageEventData.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { ListenerFunc } from './EventMessage'; -import type { TypedEventMap } from './MessageManager'; -import { EventData } from './EventData'; -import { EventDataPool } from './EventDataPool'; -import { message } from './MessageManager'; - -/** 批量注册、移除全局事件对象(用于组件级事件管理) */ -export class MessageEventData { - /** 本地事件列表,用于批量清理 */ - private events: Map> = new Map(); - - /** - * 注册全局事件(强类型重载) - * @param event 事件名(枚举) - * @param listener 处理事件的侦听器函数 - * @param object 侦听函数绑定的作用域对象 - */ - on(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void; - - /** - * 注册全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数 - * @param object 侦听函数绑定的作用域对象 - */ - on(event: string, listener: ListenerFunc, object: object): void; - - /** - * 注册全局事件(实现) - */ - on(event: string, listener: ListenerFunc, object: object) { - // 先注册到全局消息管理器 - message.on(event, listener, object); - - // 记录到本地事件列表,用于批量清理 - let eds = this.events.get(event); - if (eds == null) { - eds = []; - this.events.set(event, eds); - } - - const ed: EventData = EventDataPool.get(); - ed.event = event; - ed.listener = listener; - ed.object = object; - eds.push(ed); - } - - /** - * 移除全局事件(强类型重载) - * @param event 事件名(枚举) - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) - */ - off(event: K, listener?: (event: K, data: TypedEventMap[K]) => void, object?: object): void; - - /** - * 移除全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) - */ - off(event: string, listener?: ListenerFunc, object?: object): void; - - /** - * 移除全局事件(实现) - */ - off(event: string, listener?: ListenerFunc, object?: object) { - const eds = this.events.get(event); - if (!eds) return; - - // 如果没有指定 listener,移除该事件的所有监听器 - if (!listener) { - for (const eb of eds) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - } - this.events.delete(event); - return; - } - - // 移除指定的监听器 - const length = eds.length; - for (let i = 0; i < length; i++) { - const eb = eds[i]; - if (eb.listener == listener && eb.object == object) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - eds.splice(i, 1); - break; - } - } - - // 如果该事件已无监听器,删除事件 - if (eds.length == 0) { - this.events.delete(event); - } - } - - /** - * 触发全局事件(强类型重载) - * @param event 事件名(枚举) - * @param data 事件数据 - */ - dispatchEvent(event: K, data: TypedEventMap[K]): void; - - /** - * 触发全局事件(兼容旧用法) - * @param event 事件名 - * @param args 事件参数 - */ - - dispatchEvent(event: string, ...args: any[]): void; - - /** - * 触发全局事件(实现) - */ - - dispatchEvent(event: string, ...args: any[]) { - message.dispatchEvent(event, ...args); - } - - /** 清除所有的全局事件监听 */ - clear() { - // 直接遍历 Map,避免创建临时数组 - for (const [event, eds] of this.events) { - for (const eb of eds) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - } - } - this.events.clear(); - } -} diff --git a/assets/core/common/event/MessageEventData.ts.meta b/assets/core/common/event/MessageEventData.ts.meta deleted file mode 100644 index 9a84cb1..0000000 --- a/assets/core/common/event/MessageEventData.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "35a44c13-f854-4219-8210-ff706c9d5b07", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/assets/core/common/event/MessageManager.ts b/assets/core/common/event/MessageManager.ts index 10ac9a8..8088d18 100644 --- a/assets/core/common/event/MessageManager.ts +++ b/assets/core/common/event/MessageManager.ts @@ -15,6 +15,7 @@ import { EventDataPool } from './EventDataPool'; * } * } */ + export interface TypedEventMap { // 业务层通过 declare module 扩展此接口 } @@ -32,55 +33,26 @@ export interface TypedEventMap { * ⚠️ 重要:组件销毁时必须调用 off() 移除事件监听,否则会导致内存泄漏 * ⚠️ 建议:在 onDestroy() 或 destroy() 中移除所有注册的事件 * + * @强类型事件说明 + * - 使用 emit() 和 emitAsync() 方法可获得编译时的强类型约束 + * - 使用 dispatchEvent() 和 dispatchEventAsync() 兼容旧代码 + * * @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037894&doc_id=2873565 - * @example -// 注册持续监听的全局事件 -export class RoleViewComp extends Component{ - onLoad(){ - // 监听全局事件 - oops.message.on(GameEvent.GameServerConnected, this.onHandler, this); - } - - protected onDestroy() { - // 对象释放时取消注册的全局事件 - oops.message.off(GameEvent.GameServerConnected, this.onHandler, this); - } - - private onHandler(event: string, args: any) { - switch (event) { - case GameEvent.GameServerConnected: - console.log("处理游戏服务器连接成功后的逻辑"); - break; - } - } -} - -// 注册只触发一次的全局事件 -export class RoleViewComp extends Component{ - onLoad(){ - // 监听一次事件,事件响应后,该监听自动移除 - oops.message.once(GameEvent.GameServerConnected, this.onHandler, this); - } - - private onHandler(event: string, args: any) { - switch (event) { - case GameEvent.GameServerConnected: - console.log("处理游戏服务器连接成功后的逻辑"); - break; - } - } -} */ export class MessageManager { private events: Map> = new Map(); /** - * 注册全局事件(强类型重载) + * 注册全局事件(强类型) * @param event 事件名(枚举) * @param listener 处理事件的侦听器函数 * @param object 侦听函数绑定的作用域对象 */ - on(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void; + on( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: object + ): void; /** * 注册全局事件(兼容旧用法) @@ -93,7 +65,7 @@ export class MessageManager { /** * 注册全局事件(实现) */ - on(event: string, listener: ListenerFunc, object: object) { + on(event: string, listener: ListenerFunc, object: object): void { if (!event || !listener) { warn(`注册【${event}】事件的侦听器函数为空`); return; @@ -124,12 +96,16 @@ export class MessageManager { } /** - * 监听一次事件,事件响应后,该监听自动移除(强类型重载) + * 监听一次事件,事件响应后,该监听自动移除(强类型) * @param event 事件名(枚举) * @param listener 事件触发回调方法 * @param object 侦听函数绑定的作用域对象 */ - once(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void; + once( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: object + ): void; /** * 监听一次事件,事件响应后,该监听自动移除(兼容旧用法) @@ -142,17 +118,17 @@ export class MessageManager { /** * 监听一次事件,事件响应后,该监听自动移除(实现) */ - once(event: string, listener: ListenerFunc, object: object) { + once(event: string, listener: ListenerFunc, object: object): void { + const _listener: any = ($event: string, ...$args: any[]) => { this.off(event, _listener, object); - // 正确展开参数传递 listener.call(object, $event, ...$args); }; this.on(event, _listener, object); } /** - * 移除全局事件(强类型重载) + * 移除全局事件(强类型) * @param event 事件名(枚举) * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) * @param object 侦听函数绑定的作用域对象(可选) @@ -174,7 +150,7 @@ export class MessageManager { /** * 移除全局事件(实现) */ - off(event: string, listener?: Function, object?: object) { + off(event: string, listener?: Function, object?: object): void { const eds = this.events.get(event); if (!eds) { @@ -207,17 +183,6 @@ export class MessageManager { } } - /** - * 触发全局事件(强类型重载) - * @param event 事件名(枚举) - * @param data 事件数据 - * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 - */ - dispatchEvent( - event: K, - data: TypedEventMap[K] - ): void; - /** * 触发全局事件(兼容旧用法) * @param event 事件名 @@ -225,16 +190,9 @@ export class MessageManager { * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 */ - dispatchEvent(event: string, ...args: any[]): void; - - /** - * 触发全局事件(实现) - */ - - dispatchEvent(event: string, ...args: any[]) { + dispatchEvent(event: string, ...args: any[]): void { const list = this.events.get(event); if (list != null) { - // 创建副本以支持在回调中安全地修改监听器列表 const eds: Array = list.concat(); const length = eds.length; for (let i = 0; i < length; i++) { @@ -244,40 +202,17 @@ export class MessageManager { } } - /** - * 触发全局事件,支持同步与异步处理(强类型重载) - * @param event 事件名(枚举) - * @param data 事件数据 - * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 - */ - dispatchEventAsync(event: K, data: TypedEventMap[K]): Promise; - /** * 触发全局事件,支持同步与异步处理(兼容旧用法) * @param event 事件名 * @param args 事件参数 * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 - * @example 事件响应示例 - onTest(event: string, args: any): Promise { - return new Promise((resolve, reject) => { - setTimeout(() => { - console.log("异步事逻辑"); - resolve(); - }, 2000); - }); - } - */ - dispatchEventAsync(event: string, ...args: any[]): Promise; - - /** - * 触发全局事件,支持同步与异步处理(实现) */ dispatchEventAsync(event: string, ...args: any[]): Promise { return new Promise((resolve) => { const list = this.events.get(event); if (list != null) { - // 创建副本以支持在回调中安全地修改监听器列表 const eds: Array = list.concat(); const length = eds.length; (async () => { @@ -293,6 +228,50 @@ export class MessageManager { } }); } + + /** + * 触发强类型事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + * @note 使用此方法可获得编译时的强类型约束,参数不匹配会编译报错 + */ + emit(event: K, data: TypedEventMap[K]): void { + const list = this.events.get(event as string); + if (list != null) { + const eds: Array = list.concat(); + const length = eds.length; + for (let i = 0; i < length; i++) { + const ed = eds[i]; + ed.listener.call(ed.object, event, data); + } + } + } + + /** + * 触发强类型异步事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + * @note 使用此方法可获得编译时的强类型约束,参数不匹配会编译报错 + */ + emitAsync(event: K, data: TypedEventMap[K]): Promise { + return new Promise((resolve) => { + const list = this.events.get(event as string); + if (list != null) { + const eds: Array = list.concat(); + const length = eds.length; + (async () => { + for (let i = 0; i < length; i++) { + const ed = eds[i]; + await Promise.resolve(ed.listener.call(ed.object, event, data)); + } + resolve(); + })(); + } + else { + resolve(); + } + }); + } } export const message = new MessageManager(); diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 43feb3a..4b1549c 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -12,6 +12,7 @@ import type { IAudioParams } from '../../core/common/audio/IAudio'; import { EventDispatcher } from '../../core/common/event/EventDispatcher'; import type { ListenerFunc } from '../../core/common/event/EventMessage'; import { EventMessage } from '../../core/common/event/EventMessage'; +import type { TypedEventMap } from '../../core/common/event/MessageManager'; import type { AssetType, CompleteCallback, Paths, ProgressCallback } from '../../core/common/loader/ResLoader'; import { resLoader } from '../../core/common/loader/ResLoader'; import { ViewUtil } from '../../core/utils/ViewUtil'; @@ -52,31 +53,115 @@ export class GameComponent extends Component { } /** - * 注册全局事件 + * 注册全局事件(强类型) + * @param event 事件名(枚举) + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的this对象 + */ + on( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: any + ): void; + + /** + * 注册全局事件(兼容旧用法) * @param event 事件名 * @param listener 处理事件的侦听器函数 * @param object 侦听函数绑定的this对象 */ - on(event: string, listener: ListenerFunc, object: any) { + on(event: string, listener: ListenerFunc, object: any): void; + + /** + * 注册全局事件(实现) + */ + on(event: string, listener: ListenerFunc, object: any): void { this.event.on(event, listener, object); } /** - * 移除全局事件 + * 监听一次事件,事件响应后,该监听自动移除(强类型) + * @param event 事件名(枚举) + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的this对象 + */ + once( + event: K, + listener: (event: K, data: TypedEventMap[K]) => void, + object: any + ): void; + + /** + * 监听一次事件,事件响应后,该监听自动移除(兼容旧用法) + * @param event 事件名 + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的this对象 + */ + once(event: string, listener: ListenerFunc, object: any): void; + + /** + * 监听一次事件,事件响应后,该监听自动移除(实现) + */ + once(event: string, listener: ListenerFunc, object: any): void { + this.event.once(event, listener, object); + } + + /** + * 移除全局事件(强类型) + * @param event 事件名(枚举) + */ + off(event: K): void; + + /** + * 移除全局事件(兼容旧用法) * @param event 事件名 */ - off(event: string) { + off(event: string): void; + + /** + * 移除全局事件(实现) + */ + off(event: string): void { this.event.off(event); } /** - * 触发全局事件 + * 触发强类型全局事件 + * @param event 事件名(枚举) + * @param data 事件数据 + */ + emit(event: K, data: TypedEventMap[K]): void { + this.event.emit(event, data); + } + + /** + * 触发全局事件(兼容旧用法) * @param event 事件名 * @param args 事件参数 */ - dispatchEvent(event: string, ...args: any) { + + dispatchEvent(event: string, ...args: any[]): void { this.event.dispatchEvent(event, ...args); } + + /** + * 触发强类型异步全局事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + */ + emitAsync(event: K, data: TypedEventMap[K]): Promise { + return this.event.emitAsync(event, data); + } + + /** + * 触发全局事件,支持同步与异步处理(兼容旧用法) + * @param event 事件名 + * @param args 事件参数 + */ + + dispatchEventAsync(event: string, ...args: any[]): Promise { + return this.event.dispatchEventAsync(event, ...args); + } //#endregion //#region 预制节点管理 @@ -248,12 +333,12 @@ export class GameComponent extends Component { * @param bundleName 资源包名 * @param releaseAll 是否释放所有引用计数(默认只释放一次) */ - releaseRes(path: string, bundleName: string = resLoader.defaultBundleName, releaseAll: boolean = false) { + releaseRes(path: string, bundleName: string = resLoader.defaultBundleName, releaseAll = false) { if (!this.resPaths) return; - + const rps = this.resPaths.get(ResType.Load); if (!rps) return; - + const key = this.getResKey(bundleName, path); const record = rps.get(key); if (record) { @@ -317,10 +402,10 @@ export class GameComponent extends Component { */ getResRefCount(path: string, bundleName: string = resLoader.defaultBundleName): number { if (!this.resPaths) return 0; - + const rps = this.resPaths.get(ResType.Load); if (!rps) return 0; - + const key = this.getResKey(bundleName, path); const record = rps.get(key); return record ? record.refCount : 0; @@ -333,14 +418,14 @@ export class GameComponent extends Component { getAllResRecords(): ResRecord[] { const records: ResRecord[] = []; if (!this.resPaths) return records; - + const rps = this.resPaths.get(ResType.Load); if (rps) { rps.forEach((value: ResRecord) => { records.push({ ...value }); }); } - + return records; } @@ -352,27 +437,27 @@ export class GameComponent extends Component { console.log('[资源管理] 暂无资源记录'); return; } - + const loadRps = this.resPaths.get(ResType.Load); const dirRps = this.resPaths.get(ResType.LoadDir); - + console.log('========== 资源使用情况 =========='); console.log(`组件: ${this.node.name}`); - + if (loadRps && loadRps.size > 0) { console.log(`\n[普通资源] 共 ${loadRps.size} 个:`); loadRps.forEach((value: ResRecord, key: string) => { console.log(` - ${key} (引用计数: ${value.refCount})`); }); } - + if (dirRps && dirRps.size > 0) { console.log(`\n[文件夹资源] 共 ${dirRps.size} 个:`); dirRps.forEach((value: ResRecord, key: string) => { console.log(` - ${key} (引用计数: ${value.refCount})`); }); } - + console.log('=================================='); } @@ -393,13 +478,13 @@ export class GameComponent extends Component { } return; } - + // 释放旧的 spriteFrame 引用,避免内存泄漏 const oldSpriteFrame = target.spriteFrame; if (oldSpriteFrame && isValid(oldSpriteFrame)) { oldSpriteFrame.decRef(); } - + // 增加新 spriteFrame 引用并设置 spriteFrame.addRef(); target.spriteFrame = spriteFrame; @@ -430,10 +515,10 @@ export class GameComponent extends Component { else if (params.bundle == null) { params.bundle = resLoader.defaultBundleName; } - + const bundle = params.bundle || resLoader.defaultBundleName; const ae = await oops.audio.playEffect(url, params); - + if (ae) { // 音效加载成功,记录资源引用 this.addPathToRecord(ResType.Load, bundle, url); @@ -588,7 +673,7 @@ export class GameComponent extends Component { protected onDestroy() { // 释放消息对象 if (this._event) { - this._event.destroy(); + this._event.clear(); this._event = null; }