mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-06-19 19:17:21 +08:00
285 lines
8.6 KiB
TypeScript
285 lines
8.6 KiB
TypeScript
import { AudioClip, Node, NodePool } from "cc";
|
|
import { oops } from "../../Oops";
|
|
import { resLoader } from "../loader/ResLoader";
|
|
import { AudioEffect } from "./AudioEffect";
|
|
import { AudioEffectType } from "./AudioManager";
|
|
import { IAudioData, IAudioParams } from "./IAudio";
|
|
|
|
/** 音乐效缓冲编号最大值 */
|
|
const AE_ID_MAX = 30000;
|
|
|
|
/** 音效池 */
|
|
export class AudioEffectPool {
|
|
/** 音效配置数据 */
|
|
private data: { [node: string]: IAudioData } = null!;
|
|
/** 音效播放器节点对象池 */
|
|
private pool: NodePool = new NodePool();
|
|
/** 对象池集合 */
|
|
private effects: Map<string, AudioEffect> = new Map();
|
|
/** 用过的音效资源记录 */
|
|
private res: Map<string, string[]> = new Map();
|
|
/** 外网远程资源记录(地址、音效对象) */
|
|
private res_remote: Map<string, AudioClip> = new Map();
|
|
|
|
private _aeId: number = 0;
|
|
/** 获取请求唯一编号 */
|
|
private getAeId() {
|
|
if (this._aeId == AE_ID_MAX) this._aeId = 1;
|
|
this._aeId++;
|
|
return this._aeId;
|
|
}
|
|
|
|
/**
|
|
* 注册音效类型
|
|
* @param type
|
|
*/
|
|
register(type: string) {
|
|
this.data[type] = { switch: true, volume: 1 };
|
|
}
|
|
|
|
/**
|
|
* 音效开关
|
|
* @param type 音效类型
|
|
* @returns 音效开关
|
|
*/
|
|
getSwitch(type: string) {
|
|
let iad = this.data[type];
|
|
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
|
|
return iad.switch;
|
|
}
|
|
/**
|
|
* 音效音量设置
|
|
* @param type 音效类型
|
|
* @param value 音效开关
|
|
*/
|
|
setSwitch(type: string, value: boolean) {
|
|
let iad = this.data[type];
|
|
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
|
|
iad.switch = value;
|
|
|
|
if (!value) this.stop();
|
|
}
|
|
|
|
/**
|
|
* 音效音量获取
|
|
* @param type 音效类型
|
|
* @returns 音效音量
|
|
*/
|
|
getVolume(type: string) {
|
|
let iad = this.data[type];
|
|
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
|
|
return iad.volume;
|
|
}
|
|
|
|
/**
|
|
* 音效音量设置
|
|
* @param type 音效类型
|
|
* @param value 音效音量
|
|
*/
|
|
setVolume(type: string, value: number) {
|
|
let iad = this.data[type];
|
|
if (iad == null) console.error(`类型为【${type}】的音效配置不存在`);
|
|
iad.volume = value;
|
|
|
|
this.effects.forEach(ac => ac.volume = value);
|
|
}
|
|
|
|
/**
|
|
* 加载与播放音效
|
|
* @param path 音效资源地址与音效资源
|
|
* @param params 音效附加参数
|
|
* @returns
|
|
*/
|
|
async loadAndPlay(path: string | AudioClip, params?: IAudioParams): Promise<AudioEffect> {
|
|
return new Promise(async (resolve, reject) => {
|
|
if (params == null) {
|
|
params = {
|
|
bundle: resLoader.defaultBundleName,
|
|
loop: false,
|
|
type: AudioEffectType.Effect
|
|
}
|
|
}
|
|
else {
|
|
if (params.bundle == null) params.bundle = resLoader.defaultBundleName;
|
|
if (params.loop == null) params.loop = false;
|
|
if (params.type == null) params.type = AudioEffectType.Effect; // 默认音效类型
|
|
}
|
|
|
|
let iad = this.data[params.type!];
|
|
if (iad == null) console.error(`类型为【${params.type!}】的音效配置不存在`);
|
|
|
|
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;
|
|
}
|
|
// 非引擎管理的远程资源加载
|
|
else if (path.indexOf("http") == 0) {
|
|
key = `${params.type}_${path}`;
|
|
clip = this.res_remote.get(path);
|
|
if (clip == null) {
|
|
const extension = path.split('.').pop();
|
|
clip = await resLoader.loadRemote<AudioClip>(path, { ext: `.${extension}` });
|
|
this.res_remote.set(path, clip);
|
|
}
|
|
}
|
|
// 资源加载
|
|
else {
|
|
key = `${params.type}_${bundle}_${path}`;
|
|
clip = resLoader.get(path, AudioClip, bundle)!;
|
|
|
|
// 加载音效资源
|
|
if (clip == null) {
|
|
let urls = this.res.get(bundle);
|
|
if (urls == null) {
|
|
urls = [];
|
|
this.res.set(bundle, urls);
|
|
urls.push(path);
|
|
}
|
|
else if (urls.indexOf(path) == -1) {
|
|
urls.push(path);
|
|
}
|
|
clip = await resLoader.loadAsync(bundle, path, AudioClip);
|
|
}
|
|
}
|
|
|
|
// 资源已被释放
|
|
if (!clip.isValid) {
|
|
resolve(null!);
|
|
return;
|
|
}
|
|
|
|
// 获取音效果播放器播放音乐
|
|
let aeid: number = -1;
|
|
let ae: AudioEffect;
|
|
let node: Node = null!;
|
|
if (this.pool.size() == 0) {
|
|
aeid = this.getAeId();
|
|
key += "_" + aeid;
|
|
|
|
node = new Node("AudioEffect");
|
|
ae = node.addComponent(AudioEffect);
|
|
ae.key = key;
|
|
ae.aeid = aeid;
|
|
ae.onComplete = this.onAudioEffectPlayComplete.bind(this);
|
|
}
|
|
else {
|
|
node = this.pool.get()!;
|
|
ae = node.getComponent(AudioEffect)!;
|
|
}
|
|
|
|
// 记录正在播放的音效播放器
|
|
this.effects.set(ae.key, ae);
|
|
|
|
node.parent = oops.audio.node;
|
|
ae.path = path;
|
|
ae.params = params;
|
|
ae.loop = params.loop!;
|
|
ae.volume = params.volume!;
|
|
ae.clip = clip;
|
|
ae.play();
|
|
|
|
resolve(ae);
|
|
});
|
|
}
|
|
|
|
/** 音效播放完成 */
|
|
private onAudioEffectPlayComplete(ae: AudioEffect) {
|
|
this.put(ae);
|
|
ae.params && ae.params.onPlayComplete && ae.params.onPlayComplete(ae);
|
|
console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`);
|
|
}
|
|
|
|
/**
|
|
* 回收音效播放器
|
|
* @param ae loadAndPlay 方法返回的音效播放器对象
|
|
*/
|
|
put(ae: AudioEffect) {
|
|
let effect = this.effects.get(ae.key);
|
|
if (effect && effect.clip) {
|
|
effect.reset();
|
|
|
|
this.effects.delete(ae.key);
|
|
this.pool.put(effect.node);
|
|
}
|
|
}
|
|
|
|
/** 停止播放所有音效 */
|
|
stop() {
|
|
this.effects.forEach(ae => {
|
|
ae.stop();
|
|
this.onAudioEffectPlayComplete(ae);
|
|
});
|
|
this.effects.clear();
|
|
}
|
|
|
|
/** 恢复所有音效 */
|
|
play() {
|
|
this.effects.forEach(ae => ae.play());
|
|
}
|
|
|
|
/** 暂停所有音效 */
|
|
pause() {
|
|
this.effects.forEach(ae => {
|
|
ae.pause();
|
|
this.onAudioEffectPlayComplete(ae);
|
|
});
|
|
this.effects.clear();
|
|
}
|
|
|
|
/** 施放音乐资源对象 */
|
|
releaseAudioClip(ae: AudioEffect) {
|
|
if (ae.path instanceof AudioClip) {
|
|
ae.path.decRef();
|
|
}
|
|
else {
|
|
resLoader.release(ae.path, ae.params!.bundle)
|
|
}
|
|
}
|
|
|
|
/** 释放所有音效资源与对象池中播放器 */
|
|
release() {
|
|
// 释放池中音乐播放器
|
|
this.releasePool();
|
|
|
|
// 释放各个资源包中的音效资源
|
|
this.releaseRes();
|
|
|
|
// 释放外网远程音效资源
|
|
this.releaseResRemote();
|
|
}
|
|
|
|
/** 释放池中音乐播放器 */
|
|
releasePool() {
|
|
this.pool.clear();
|
|
|
|
// 释放正在播放的音效对象
|
|
this.effects.forEach(ae => ae.node.destroy());
|
|
this.effects.clear();
|
|
}
|
|
|
|
/** 释放各个资源包中的音效资源 */
|
|
releaseRes() {
|
|
this.res.forEach((paths: string[], bundleName: string) => {
|
|
paths.forEach(path => resLoader.release(path, bundleName));
|
|
});
|
|
}
|
|
|
|
/** 释放外网远程音效资源 */
|
|
releaseResRemote() {
|
|
this.res_remote.forEach((clip: AudioClip, path: string) => {
|
|
clip.decRef();
|
|
});
|
|
this.res_remote.clear();
|
|
}
|
|
} |