音效模块支持扩展分类

This commit is contained in:
dgflash
2025-08-27 17:17:34 +08:00
parent a89eba46a8
commit 5bd45653bf
4 changed files with 179 additions and 60 deletions

View File

@@ -2,36 +2,16 @@ import { AudioClip, Node, NodePool } from "cc";
import { oops } from "../../Oops";
import { resLoader } from "../loader/ResLoader";
import { AudioEffect } from "./AudioEffect";
import { IAudioParams } from "./IAudio";
import { AudioEffectType } from "./AudioManager";
import { IAudioData, IAudioParams } from "./IAudio";
/** 音乐效缓冲编号最大值 */
const AE_ID_MAX = 30000;
/** 音效池 */
export class AudioEffectPool {
private _switch: boolean = true;
/** 音效开关 */
get switch(): boolean {
return this._switch;
}
set switch(value: boolean) {
this._switch = value;
if (value) this.stop();
}
private _volume: number = 1;
/** 所有音效音量 */
get volume(): number {
return this._volume;
}
set volume(value: number) {
this._volume = value;
this.effects.forEach(ae => {
ae.volume = value;
});
}
/** 音效配置数据 */
private data: { [node: string]: IAudioData } = null!;
/** 音效播放器节点对象池 */
private pool: NodePool = new NodePool();
/** 对象池集合 */
@@ -49,6 +29,61 @@ export class AudioEffectPool {
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 音效资源地址与音效资源
@@ -57,21 +92,26 @@ export class AudioEffectPool {
*/
async loadAndPlay(path: string | AudioClip, params?: IAudioParams): Promise<number> {
return new Promise(async (resolve, reject) => {
if (!this.switch) return resolve(-1);
if (params == null) {
params = {
bundle: resLoader.defaultBundleName,
volume: this.volume,
loop: false,
type: AudioEffectType.Effect
}
}
else {
if (params.bundle == null) params.bundle = resLoader.defaultBundleName;
if (params.volume == null) params.volume = this.volume;
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) return resolve(-1);
if (params.volume == null) params.volume = iad.volume;
let bundle = params.bundle!;
let key: string = null!;
@@ -157,7 +197,7 @@ export class AudioEffectPool {
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);
// console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`);
console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}`);
}
/**
@@ -189,19 +229,27 @@ export class AudioEffectPool {
/** 停止播放所有音效 */
stop() {
this.effects.forEach(ae => ae.stop());
this.effects.forEach(ae => {
ae.stop();
this.onAudioEffectPlayComplete(ae);
});
this.effects.clear();
}
/** 恢复所有音效 */
play() {
if (!this.switch) return;
// if (!this.switch) return;
this.effects.forEach(ae => ae.play());
}
/** 暂停所有音效 */
pause() {
if (!this.switch) return;
this.effects.forEach(ae => ae.pause());
// if (!this.switch) return;
this.effects.forEach(ae => {
ae.pause();
this.onAudioEffectPlayComplete(ae);
});
this.effects.clear();
}
/** 释放所有音效资源与对象池中播放器 */

View File

@@ -2,10 +2,18 @@ import { AudioClip, Component } from "cc";
import { oops } from "../../Oops";
import { AudioEffectPool } from "./AudioEffectPool";
import { AudioMusic } from "./AudioMusic";
import { IAudioParams } from "./IAudio";
import { IAudioData, IAudioParams } from "./IAudio";
const LOCAL_STORE_KEY = "game_audio";
/** 音乐音效默认类型 */
export enum AudioEffectType {
/** 背景音乐 */
Music = "music",
/** 音乐音效 */
Effect = "effect",
}
/**
* 音频管理
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037893&doc_id=2873565
@@ -20,7 +28,7 @@ export class AudioManager extends Component {
effect: AudioEffectPool = new AudioEffectPool();
/** 音乐管理状态数据 */
private localData: any = {};
private data: { [node: string]: IAudioData } = {};
/**
* 播放音效
@@ -38,13 +46,12 @@ export class AudioManager extends Component {
/** 恢复当前暂停的音乐与音效播放 */
resumeAll() {
if (!this.music.playing && this.music.progress > 0) this.music.play();
this.effect.play();
this.music.resume();
}
/** 暂停当前音乐与音效的播放 */
pauseAll() {
if (this.music.playing) this.music.pause();
this.music.pause();
this.effect.pause();
}
@@ -56,20 +63,15 @@ export class AudioManager extends Component {
/** 保存音乐音效的音量、开关配置数据到本地 */
save() {
this.localData.volume_music = this.music.volume;
this.localData.volume_effect = this.effect.volume;
this.localData.switch_music = this.music.switch;
this.localData.switch_effect = this.effect.switch;
oops.storage.set(LOCAL_STORE_KEY, this.localData);
oops.storage.set(LOCAL_STORE_KEY, this.data);
}
/** 本地加载音乐音效的音量、开关配置数据并设置到游戏中 */
load() {
this.music = this.getComponent(AudioMusic) || this.addComponent(AudioMusic)!;
this.localData = oops.storage.getJson(LOCAL_STORE_KEY);
if (this.localData) {
this.data = oops.storage.getJson(LOCAL_STORE_KEY);
if (this.data) {
try {
this.setState();
}
@@ -83,17 +85,37 @@ export class AudioManager extends Component {
}
private setState() {
this.music.volume = this.localData.volume_music;
this.effect.volume = this.localData.volume_effect;
this.music.switch = this.localData.switch_music;
this.effect.switch = this.localData.switch_effect;
for (let type in this.data) {
let iad = this.data[type];
switch (type) {
case "music":
this.music.switch = this.data.music.switch;
this.music.volume = this.data.music.volume;
break;
default:
this.effect.setSwitch(type, iad.switch);
this.effect.setVolume(type, iad.volume);
break;
}
}
}
private setStateDefault() {
this.localData = {};
this.data = {
music: { switch: true, volume: 1 },
effect: { switch: true, volume: 1 },
};
//@ts-ignore
this.music.data = this.data;
this.music.switch = true
this.music.volume = 1;
this.effect.volume = 1;
this.music.switch = true;
this.effect.switch = true;
//@ts-ignore
this.effect.data = this.data;
this.effect.setSwitch(AudioEffectType.Effect, true);
this.effect.setVolume(AudioEffectType.Effect, 1);
this.save();
}
}

View File

@@ -6,7 +6,8 @@
*/
import { AudioClip, AudioSource, _decorator } from 'cc';
import { resLoader } from '../loader/ResLoader';
import { IAudioParams } from './IAudio';
import { AudioEffectType } from './AudioManager';
import { IAudioData, IAudioParams } from './IAudio';
const { ccclass } = _decorator;
@@ -16,22 +17,50 @@ const { ccclass } = _decorator;
*/
@ccclass('AudioMusic')
export class AudioMusic extends AudioSource {
/** 音效配置数据 */
private data: { [node: string]: IAudioData } = null!;
private _progress: number = 0;
private _isLoading: boolean = false;
private _nextUrl: string = null!;
private _nextParams: IAudioParams = null!;
private _params: IAudioParams = null!;
/** 背景音乐开关 */
private _switch: boolean = true;
get switch(): boolean {
return this._switch;
/**
* 音效开关
* @param type 音效类型
* @returns 音效开关
*/
get switch() {
return this.data[AudioEffectType.Music].switch;
}
/**
* 音效音量设置
* @param type 音效类型
* @param value 音效开关
*/
set switch(value: boolean) {
this._switch = value;
this.data[AudioEffectType.Music].switch = value;
if (!value) this.stop();
}
/**
* 音效音量获取
* @param type 音效类型
* @returns 音效音量
*/
get volume() {
return this.data[AudioEffectType.Music].volume;
}
/**
* 音效音量设置
* @param value 音效音量
*/
set volume(value: number) {
this.data[AudioEffectType.Music].volume = value;
super.volume = value;
}
/** 获取音乐播放进度 */
get progress(): number {
if (this.duration > 0)
@@ -125,6 +154,17 @@ export class AudioMusic extends AudioSource {
}
}
/** 恢复当前暂停的音乐与音效播放 */
resume() {
if (!this.playing && this.progress > 0) super.play();
}
/** 暂停当前音乐与音效的播放 */
pause() {
if (this.playing) super.pause();
}
/** 停止当前音乐与音效的播放 */
stop(): void {
if (this.switch && this.playing) {
super.stop();

View File

@@ -1,4 +1,6 @@
export interface IAudioParams {
/** 音乐分类 */
type?: string,
/** 资源包名 */
bundle?: string,
/** 是否循环播放 */
@@ -7,4 +9,11 @@ export interface IAudioParams {
volume?: number;
/** 播放完成事件 */
onPlayComplete?: Function;
}
export interface IAudioData {
/** 音乐开关 */
switch: boolean;
/** 音量 */
volume: number;
}