!11 修复音乐资源对象池同一个资源包中资源记录相互覆盖导致,释放音效资源时内存泄漏

Merge pull request !11 from dgflash/develop
This commit is contained in:
dgflash
2025-05-14 02:41:47 +00:00
committed by Gitee
7 changed files with 67 additions and 66 deletions

View File

@@ -4,7 +4,7 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-08-28 10:02:57
*/
import { _decorator, Component, director, Game, game, JsonAsset, Node, screen, sys } from "cc";
import { _decorator, Component, director, Game, game, JsonAsset, Node, resources, screen, sys } from "cc";
import { GameConfig } from "../module/config/GameConfig";
import { GameQueryConfig } from "../module/config/GameQueryConfig";
import { oops, version } from "./Oops";
@@ -20,8 +20,6 @@ import { LayerManager } from "./gui/layer/LayerManager";
const { property } = _decorator;
let isInited = false;
/** 框架显示层根节点 */
export class Root extends Component {
/** 游戏层节点 */
@@ -42,16 +40,12 @@ export class Root extends Component {
private persist: Node = null!
onLoad() {
if (!isInited) {
isInited = true; // 注这里是规避cc3.8在编辑器模式下运行时,关闭游戏会两次初始化报错
console.log(`Oops Framework ${version}`);
this.enabled = false;
console.log(`Oops Framework ${version}`);
this.enabled = false;
this.initModule();
this.iniStart();
this.loadConfig().then();
}
this.initModule();
this.iniStart();
this.loadConfig().then();
}
private initModule() {
@@ -75,8 +69,12 @@ export class Root extends Component {
private async loadConfig() {
const config_name = "config";
const config = await oops.res.loadAsync(config_name, JsonAsset);
if (config) {
resources.load(config_name, JsonAsset, (err, config) => {
if (err) {
this.loadConfig().then();
return;
}
oops.config.game = new GameConfig(config);
// 本地存储模块
@@ -90,7 +88,6 @@ export class Root extends Component {
// 设置默认资源包
oops.res.defaultBundleName = oops.config.game.bundleDefault;
oops.res.init(oops.config.game.data.bundle);
// 游戏界面管理
oops.gui.mobileSafeArea = oops.config.game.mobileSafeArea;
@@ -104,11 +101,8 @@ export class Root extends Component {
this.init();
this.run();
oops.res.release(config_name);
}
else {
this.loadConfig().then();
}
resources.release(config_name);
});
}
update(dt: number) {

View File

@@ -35,7 +35,7 @@ export class AudioEffectPool {
/** 对象池集合 */
private effects: Map<string, AudioEffect> = new Map();
/** 用过的音效资源记录 */
private res: Map<string, string> = new Map();
private res: Map<string, string[]> = new Map();
private _aeId: number = 0;
/** 获取请求唯一编号 */
@@ -63,8 +63,16 @@ export class AudioEffectPool {
}
else {
clip = resLoader.get(url, AudioClip, bundleName)!;
if (!clip) {
this.res.set(bundleName, url);
if (clip == null) {
let urls = this.res.get(bundleName);
if (urls == null) {
urls = [];
this.res.set(bundleName, urls);
urls.push(url);
}
else if (urls.indexOf(url) == -1) {
urls.push(url);
}
clip = await resLoader.loadAsync(bundleName, url, AudioClip);
}
}
@@ -148,8 +156,8 @@ export class AudioEffectPool {
this.effects.clear();
// 释放音效资源
this.res.forEach((url: string, bundleName: string) => {
resLoader.release(bundleName, url);
this.res.forEach((urls: string[], bundleName: string) => {
urls.forEach(url => resLoader.release(bundleName, url));
});
// 释放池中播放器

View File

@@ -1,4 +1,4 @@
import { Asset, AssetManager, __private, assetManager, error, js, resources, warn } from "cc";
import { __private, Asset, AssetManager, assetManager, error, js, resources, warn } from "cc";
export type AssetType<T = Asset> = __private.__types_globals__Constructor<T> | null;
export type Paths = string | string[];
@@ -35,8 +35,6 @@ export class ResLoader {
//#region 资源配置数据
/** 全局默认加载的资源包名 */
defaultBundleName: string = "resources";
/** 是否使用远程 CDN 资源 */
cdn: boolean = false;
/** 下载时的最大并发数 - 项目设置 -> 项目数据 -> 资源下载并发数设置默认值初始值为15 */
get maxConcurrency() {
@@ -70,17 +68,6 @@ export class ResLoader {
assetManager.downloader.retryInterval = value;
}
/** 资源包配置 */
private bundles: Map<string, string> = new Map<string, string>();
//#endregion
init(config: any) {
this.cdn = config.enable;
for (let bundleName in config.packages) {
this.bundles.set(bundleName, config.packages[bundleName]);
}
}
//#region 加载远程资源
/**
* 加载远程资源
@@ -120,16 +107,13 @@ oops.res.loadRemote<ImageAsset>(this.url, opt, onComplete);
//#region 资源包管理
/**
* 加载资源包
* @param url 资源地址
* @param v 资源MD5版本号
* @param name 资源地址
* @example
var serverUrl = "http://192.168.1.8:8080/"; // 服务器地址
var md5 = "8e5c0"; // Cocos Creator 构建后的MD5字符
await oops.res.loadBundle(serverUrl,md5);
await oops.res.loadBundle(name);
*/
loadBundle(url: string, v?: string) {
loadBundle(name: string) {
return new Promise<AssetManager.Bundle>((resolve, reject) => {
assetManager.loadBundle(url, { version: v }, (err, bundle: AssetManager.Bundle) => {
assetManager.loadBundle(name, (err, bundle: AssetManager.Bundle) => {
if (err) {
return error(err);
}
@@ -366,7 +350,7 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback);
*/
release(path: string, bundleName?: string) {
if (bundleName == undefined) bundleName = this.defaultBundleName;
const bundle = assetManager.getBundle(bundleName);
if (bundle) {
const asset = bundle.get(path);
@@ -483,8 +467,7 @@ oops.res.loadDir("game", onProgressCallback, onCompleteCallback);
}
// 自动加载资源包
else {
const v = this.cdn ? this.bundles.get(args.bundle) : "";
bundle = await this.loadBundle(args.bundle, v);
bundle = await this.loadBundle(args.bundle);
if (bundle) this.loadByBundleAndArgs(bundle, args);
}
}

View File

@@ -5,6 +5,7 @@
* @LastEditTime: 2022-09-02 13:44:12
*/
import { BlockInputEvents, Layers, Node, Widget, instantiate } from "cc";
import { EDITOR } from "cc/env";
import { ViewUtil } from "../../utils/ViewUtil";
import { PromptResType } from "../GuiEnum";
import { Notify } from "../prompt/Notify";
@@ -29,10 +30,7 @@ export class LayerNotify extends Node {
widget.left = widget.right = widget.top = widget.bottom = 0;
widget.alignMode = 2;
widget.enabled = true;
this.init();
}
private init() {
this.layer = Layers.Enum.UI_2D;
this.black = this.addComponent(BlockInputEvents);
this.black.enabled = false;
@@ -41,9 +39,13 @@ export class LayerNotify extends Node {
/** 打开等待提示 */
async waitOpen() {
if (this.wait == null) {
this.wait = ViewUtil.createPrefabNode(PromptResType.Wait);
// 兼容编辑器预览模式
if (this.wait == null) this.wait = await ViewUtil.createPrefabNodeAsync(PromptResType.Wait);
if (EDITOR) {
this.wait = await ViewUtil.createPrefabNodeAsync(PromptResType.Wait);
}
else {
this.wait = ViewUtil.createPrefabNode(PromptResType.Wait);
}
}
if (this.wait.parent == null) {
@@ -67,9 +69,13 @@ export class LayerNotify extends Node {
*/
async toast(content: string, useI18n: boolean) {
if (this.notify == null) {
this.notify = ViewUtil.createPrefabNode(PromptResType.Toast);
// 兼容编辑器预览模式
if (this.notify == null) this.notify = await ViewUtil.createPrefabNodeAsync(PromptResType.Toast);
if (EDITOR) {
this.notify = await ViewUtil.createPrefabNodeAsync(PromptResType.Toast);
}
else {
this.notify = ViewUtil.createPrefabNode(PromptResType.Toast);
}
this.notifyItem = this.notify.children[0];
this.notifyItem.parent = null;
}

View File

@@ -20,10 +20,7 @@ export class LayerPopUp extends LayerUI {
constructor(name: string) {
super(name);
this.init();
}
private init() {
this.layer = Layers.Enum.UI_2D;
this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this);

View File

@@ -30,6 +30,11 @@ export default class LabelTime extends Label {
})
zeroize: boolean = true;
@property({
tooltip: "游戏进入后台时间暂时",
})
paused: boolean = false;
private backStartTime: number = 0; // 进入后台开始时间
private dateDisable!: boolean; // 时间能否由天数显示
private result!: string; // 时间结果字符串
@@ -152,6 +157,11 @@ export default class LabelTime extends Label {
}
private onGameShow() {
// 时间到了
if (this.countDown <= 0) return;
// 时间暂停
if (this.paused) return;
const interval = Math.floor((oops.timer.getTime() - (this.backStartTime || oops.timer.getTime())) / 1000);
this.countDown -= interval;
if (this.countDown < 0) {

View File

@@ -1,5 +1,6 @@
import { Node, __private } from "cc";
import { oops } from "../../core/Oops";
import { resLoader } from "../../core/common/loader/ResLoader";
import { UICallbacks } from "../../core/gui/layer/Defines";
import { ViewUtil } from "../../core/utils/ViewUtil";
import { ecs } from "../../libs/ecs/ECS";
@@ -60,17 +61,19 @@ export class ModuleUtil {
/**
* 通过资源内存中获取预制上的组件添加到ECS实体中
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param parent 显示对象父级
* @param url 显示资源地址
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param parent 显示对象父级
* @param url 显示资源地址
* @param bundleName 资源包名称
*/
static addView<T extends CCVMParentComp | CCComp>(
ent: ecs.Entity,
ctor: __private.__types_globals__Constructor<T> | __private.__types_globals__AbstractedConstructor<T>,
parent: Node,
url: string) {
const node = ViewUtil.createPrefabNode(url);
url: string,
bundleName: string = resLoader.defaultBundleName) {
const node = ViewUtil.createPrefabNode(url, bundleName);
const comp = node.getComponent(ctor)!;
ent.add(comp);
node.parent = parent;