全局事件支持强类型事件参数

This commit is contained in:
dgflash
2026-02-20 17:08:36 +08:00
parent 87d9c6587e
commit 7295fc6a2a
5 changed files with 349 additions and 319 deletions

View File

@@ -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<string, Array<EventData>> = new Map();
/** 确保 MessageEventData 已初始化 */
private ensureMessageEventData(): MessageEventData {
if (this._msg == null) {
this._msg = new MessageEventData();
/**
* 注册全局事件(强类型)
* @param event 事件名(枚举)
* @param listener 处理事件的侦听器函数
* @param object 侦听函数绑定的作用域对象
*/
on<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
event: K,
data: TypedEventMap[K]
): Promise<void> {
return message.emitAsync(event, data);
}
/**
* 触发全局事件,支持同步与异步处理(兼容旧用法)
* @param event 事件名
* @param args 事件参数
*/
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
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();
}
}

View File

@@ -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<string, Array<EventData>> = new Map();
/**
* 注册全局事件(强类型重载)
* @param event 事件名(枚举)
* @param listener 处理事件的侦听器函数
* @param object 侦听函数绑定的作用域对象
*/
on<K extends keyof TypedEventMap>(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<K extends keyof TypedEventMap>(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<K extends keyof TypedEventMap>(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();
}
}

View File

@@ -1,9 +0,0 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "35a44c13-f854-4219-8210-ff706c9d5b07",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -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<string, Array<EventData>> = new Map();
/**
* 注册全局事件(强类型重载
* 注册全局事件(强类型)
* @param event 事件名(枚举)
* @param listener 处理事件的侦听器函数
* @param object 侦听函数绑定的作用域对象
*/
on<K extends keyof TypedEventMap>(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void;
on<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void;
once<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
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<EventData> = 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<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void>;
/**
* 触发全局事件,支持同步与异步处理(兼容旧用法)
* @param event 事件名
* @param args 事件参数
* @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历
* @example 事件响应示例
onTest(event: string, args: any): Promise<void> {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("异步事逻辑");
resolve();
}, 2000);
});
}
*/
dispatchEventAsync(event: string, ...args: any[]): Promise<void>;
/**
* 触发全局事件,支持同步与异步处理(实现)
*/
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
return new Promise((resolve) => {
const list = this.events.get(event);
if (list != null) {
// 创建副本以支持在回调中安全地修改监听器列表
const eds: Array<EventData> = list.concat();
const length = eds.length;
(async () => {
@@ -293,6 +228,50 @@ export class MessageManager {
}
});
}
/**
* 触发强类型事件(严格类型检查)
* @param event 事件名(枚举)
* @param data 事件数据(必须完全匹配类型定义)
* @note 使用此方法可获得编译时的强类型约束,参数不匹配会编译报错
*/
emit<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): void {
const list = this.events.get(event as string);
if (list != null) {
const eds: Array<EventData> = 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<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void> {
return new Promise((resolve) => {
const list = this.events.get(event as string);
if (list != null) {
const eds: Array<EventData> = 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();

View File

@@ -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<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(
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<K extends keyof TypedEventMap>(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<K extends keyof TypedEventMap>(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<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void> {
return this.event.emitAsync(event, data);
}
/**
* 触发全局事件,支持同步与异步处理(兼容旧用法)
* @param event 事件名
* @param args 事件参数
*/
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
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;
}