diff --git a/assets/core/common/audio/AudioEffectPool.ts b/assets/core/common/audio/AudioEffectPool.ts index 10dfe66..2a4979f 100644 --- a/assets/core/common/audio/AudioEffectPool.ts +++ b/assets/core/common/audio/AudioEffectPool.ts @@ -87,10 +87,10 @@ export class AudioEffectPool { /** * 加载与播放音效 * @param path 音效资源地址与音效资源 - * @param params 音效附加参数 + * @param params 音效附加参数 * @returns */ - async loadAndPlay(path: string | AudioClip, params?: IAudioParams): Promise { + async loadAndPlay(path: string | AudioClip, params?: IAudioParams): Promise { return new Promise(async (resolve, reject) => { if (params == null) { params = { @@ -102,28 +102,30 @@ export class AudioEffectPool { else { if (params.bundle == null) params.bundle = resLoader.defaultBundleName; if (params.loop == null) params.loop = false; - if (params.type == null) params.type = AudioEffectType.Effect; + if (params.type == null) params.type = AudioEffectType.Effect; // 默认音效类型 } let iad = this.data[params.type!]; if (iad == null) console.error(`类型为【${params.type!}】的音效配置不存在`); - if (!iad.switch) return resolve(-1); + if (!iad.switch) { + resolve(null!); + return; + } if (params.volume == null) params.volume = iad.volume; let bundle = params.bundle!; - let key: string = null!; let clip: AudioClip | undefined; // 通过预制自动加载的音效资源(音效内存跟随预制体的内存一并释放) if (path instanceof AudioClip) { + key = `${params.type}_${path.uuid}`; clip = path; - key = path.uuid; } // 非引擎管理的远程资源加载 else if (path.indexOf("http") == 0) { - key = path; + key = `${params.type}_${path}`; clip = this.res_remote.get(path); if (clip == null) { const extension = path.split('.').pop(); @@ -133,7 +135,7 @@ export class AudioEffectPool { } // 资源加载 else { - key = `${bundle}_${path}`; + key = `${params.type}_${bundle}_${path}`; clip = resLoader.get(path, AudioClip, bundle)!; // 加载音效资源 @@ -153,7 +155,7 @@ export class AudioEffectPool { // 资源已被释放 if (!clip.isValid) { - resolve(-1); + resolve(null!); return; } @@ -177,8 +179,7 @@ export class AudioEffectPool { else { node = this.pool.get()!; ae = node.getComponent(AudioEffect)!; - ae.key = ae.key; - ae.aeid = ae.aeid; + key = ae.key; } // 记录正在播放的音效播放器 @@ -189,41 +190,28 @@ export class AudioEffectPool { ae.volume = params.volume!; ae.clip = clip; ae.play(); - resolve(aeid); + resolve(ae); }); } + /** 音效播放完成 */ private onAudioEffectPlayComplete(ae: AudioEffect) { - const bundle = ae.params!.bundle!; - this.put(ae.aeid, ae.path, bundle); // 播放完回收对象 - ae.params && ae.params.onPlayComplete && ae.params.onPlayComplete(ae.aeid, ae.path, bundle); + this.put(ae); + ae.params && ae.params.onPlayComplete && ae.params.onPlayComplete(ae); console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`); } /** * 回收音效播放器 - * @param aeid 播放器编号 - * @param path 音效路径 - * @param bundleName 资源包名 + * @param ae loadAndPlay 方法返回的音效播放器对象 */ - put(aeid: number, path: string | AudioClip, bundleName: string = resLoader.defaultBundleName) { - let key: string; - if (path instanceof AudioClip) { - key = path.uuid; - } - else if (path.indexOf("http") == 0) { - key = path; - } - else { - key = `${bundleName}_${path}`; - } - key += "_" + aeid; - - let ae = this.effects.get(key); - if (ae && ae.clip) { - this.effects.delete(key); - ae.stop(); - this.pool.put(ae.node); + put(ae: AudioEffect) { + let effect = this.effects.get(ae.key); + if (effect && effect.clip) { + effect.stop(); + effect.clip = null; + this.effects.delete(ae.key); + this.pool.put(effect.node); } } @@ -238,13 +226,11 @@ export class AudioEffectPool { /** 恢复所有音效 */ play() { - // if (!this.switch) return; this.effects.forEach(ae => ae.play()); } /** 暂停所有音效 */ pause() { - // if (!this.switch) return; this.effects.forEach(ae => { ae.pause(); this.onAudioEffectPlayComplete(ae); @@ -252,6 +238,16 @@ export class AudioEffectPool { this.effects.clear(); } + /** 施放音乐资源对象 */ + releaseAudioClip(ae: AudioEffect) { + if (ae.path instanceof AudioClip) { + ae.path.decRef(); + } + else { + resLoader.release(ae.path, ae.params!.bundle) + } + } + /** 释放所有音效资源与对象池中播放器 */ release() { // 释放池中音乐播放器 diff --git a/assets/core/common/audio/AudioManager.ts b/assets/core/common/audio/AudioManager.ts index 03edee2..71c4f3f 100644 --- a/assets/core/common/audio/AudioManager.ts +++ b/assets/core/common/audio/AudioManager.ts @@ -1,5 +1,6 @@ import { AudioClip, Component } from "cc"; import { oops } from "../../Oops"; +import { AudioEffect } from "./AudioEffect"; import { AudioEffectPool } from "./AudioEffectPool"; import { AudioMusic } from "./AudioMusic"; import { IAudioData, IAudioParams } from "./IAudio"; @@ -35,13 +36,13 @@ export class AudioManager extends Component { * @param url 资源地址 * @param params 音效参数 */ - playEffect(url: string | AudioClip, params?: IAudioParams): Promise { + playEffect(url: string | AudioClip, params?: IAudioParams): Promise { return this.effect.loadAndPlay(url, params); } /** 回收音效播放器 */ - putEffect(aeid: number, url: string | AudioClip, bundleName?: string) { - this.effect.put(aeid, url, bundleName); + putEffect(ae: AudioEffect) { + this.effect.put(ae); } /** 恢复当前暂停的音乐与音效播放 */ diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 4a0e35e..7ea2bb5 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -6,6 +6,7 @@ */ import { Asset, Button, Component, EventHandler, EventKeyboard, EventTouch, Input, Node, Prefab, Sprite, SpriteFrame, __private, _decorator, input, isValid } from "cc"; import { oops } from "../../core/Oops"; +import { AudioEffect } from "../../core/common/audio/AudioEffect"; import { IAudioParams } from "../../core/common/audio/IAudio"; import { EventDispatcher } from "../../core/common/event/EventDispatcher"; import { EventMessage, ListenerFunc } from "../../core/common/event/EventMessage"; @@ -17,8 +18,7 @@ const { ccclass } = _decorator; /** 加载资源类型 */ enum ResType { Load, - LoadDir, - Audio + LoadDir } /** 资源加载记录 */ @@ -33,7 +33,6 @@ interface ResRecord { resId?: number } - /** * 游戏显示对象组件模板 * 1、当前对象加载的资源,会在对象释放时,自动释放引用的资源 @@ -138,7 +137,7 @@ export class GameComponent extends Component { * @param bundleName 资源包名 * @param paths 资源路径 */ - private addPathToRecord(type: ResType, bundleName: string, paths?: string | string[] | AssetType | ProgressCallback | CompleteCallback | null, resId?: number) { + private addPathToRecord(type: ResType, bundleName: string, paths?: string | string[] | AssetType | ProgressCallback | CompleteCallback | null) { if (this.resPaths == null) this.resPaths = new Map(); var rps = this.resPaths.get(type); @@ -151,45 +150,44 @@ export class GameComponent extends Component { let realBundle = bundleName; for (let index = 0; index < paths.length; index++) { let realPath = paths[index]; - let key = this.getResKey(realBundle, realPath, resId); + let key = this.getResKey(realBundle, realPath); let rp = rps.get(key); if (rp) { rp.refCount++; } else { - rps.set(key, { path: realPath, bundle: realBundle, refCount: 1, resId: resId }); + rps.set(key, { path: realPath, bundle: realBundle, refCount: 1 }); } } } else if (typeof paths === "string") { let realBundle = bundleName; let realPath = paths; - let key = this.getResKey(realBundle, realPath, resId); + let key = this.getResKey(realBundle, realPath); let rp = rps.get(key); if (rp) { rp.refCount++; } else { - rps.set(key, { path: realPath, bundle: realBundle, refCount: 1, resId: resId }); + rps.set(key, { path: realPath, bundle: realBundle, refCount: 1 }); } } else { let realBundle = oops.res.defaultBundleName; let realPath = bundleName; - let key = this.getResKey(realBundle, realPath, resId); + let key = this.getResKey(realBundle, realPath); let rp = rps.get(key); if (rp) { rp.refCount++; } else { - rps.set(key, { path: realPath, bundle: realBundle, refCount: 1, resId: resId }); + rps.set(key, { path: realPath, bundle: realBundle, refCount: 1 }); } } } - private getResKey(realBundle: string, realPath: string, resId?: number): string { + private getResKey(realBundle: string, realPath: string): string { let key = `${realBundle}:${realPath}`; - if (resId != null) key += ":" + resId; return key; } @@ -304,13 +302,12 @@ export class GameComponent extends Component { /** 释放音效资源 */ releaseAudioEffect() { - if (this.resPaths) { - const rps = this.resPaths.get(ResType.Audio); - if (rps) { - rps.forEach((value: ResRecord) => { - oops.audio.putEffect(value.resId!, value.path, value.bundle); // 回收音乐效到音效池中等下次使用 - }); - } + if (this.audioEffects) { + this.audioEffects.forEach((ae: AudioEffect) => { + ae.stop(); + oops.audio.effect.releaseAudioClip(ae); + }); + this.audioEffects.clear(); } } @@ -346,37 +343,30 @@ export class GameComponent extends Component { oops.audio.music.loadAndPlay(url, params); } + /** 音效缓存 */ + private audioEffects: Map = null!; + /** * 播放音效 * @param url 资源地址 * @param params 音效播放参数 */ - async playEffect(url: string, params?: IAudioParams): Promise { + async playEffect(url: string, params?: IAudioParams): Promise { return new Promise(async (resolve, reject) => { - let bundleName = resLoader.defaultBundleName; - if (params == null) { - params = { bundle: bundleName } - } - else if (params.bundle != null) { - bundleName = params.bundle; - } - // 音效播放完,关闭正在播放状态的音乐效果 - params.onPlayComplete = (aeid: number, url: string, bundleName: string) => { + if (params == null) params = {}; + params.onPlayComplete = (ae: AudioEffect) => { // 音效播放完前,界面被释放 if (!this.isValid) return; // 删除界面音效的播放记录 - const rps = this.resPaths.get(ResType.Audio); - if (rps) { - const key = this.getResKey(bundleName, url, aeid); - rps.delete(key); - } + this.audioEffects.delete(ae.key); } - let resId = await oops.audio.playEffect(url, params); - this.addPathToRecord(ResType.Audio, bundleName, url, resId); // 支持界面释放时,立即停止所有音效的播放 - resolve(resId); + let ae = await oops.audio.playEffect(url, params); + if (this.audioEffects == null) this.audioEffects = new Map(); + this.audioEffects.set(ae.key, ae); + resolve(ae); }); } //#endregion @@ -528,11 +518,12 @@ export class GameComponent extends Component { // 自动释放资源 if (this.resPaths) { - this.releaseAudioEffect(); this.release(); this.releaseDir(); this.resPaths.clear(); this.resPaths = null!; } + + this.releaseAudioEffect(); } } \ No newline at end of file