diff --git a/assets/core/common/audio/AudioEffectPool.ts b/assets/core/common/audio/AudioEffectPool.ts index 5c740e7..34e1a32 100644 --- a/assets/core/common/audio/AudioEffectPool.ts +++ b/assets/core/common/audio/AudioEffectPool.ts @@ -2,6 +2,7 @@ import { AudioClip, Node, NodePool } from "cc"; import { oops } from "../../Oops"; import { resLoader } from "../loader/ResLoader"; import { AudioEffect } from "./AudioEffect"; +import { IAudioParams } from "./IAudio"; const AE_ID_MAX = 30000; @@ -9,10 +10,10 @@ const AE_ID_MAX = 30000; export class AudioEffectPool { private _switch: boolean = true; /** 音效开关 */ - public get switch(): boolean { + get switch(): boolean { return this._switch; } - public set switch(value: boolean) { + set switch(value: boolean) { this._switch = value; if (value) this.stop(); } @@ -52,10 +53,21 @@ export class AudioEffectPool { * @param onPlayComplete 播放完成回调 * @returns */ - async load(url: string | AudioClip, bundleName: string = resLoader.defaultBundleName, onPlayComplete?: Function): Promise { + async loadAndPlay(url: string | AudioClip, params?: IAudioParams): Promise { return new Promise(async (resolve, reject) => { if (!this.switch) return resolve(-1); + let bundleName = resLoader.defaultBundleName; + let loop = false; + let volume = this.volume; + let onPlayComplete: Function = null!; + if (params) { + if (params.bundle != null) bundleName = params.bundle; + if (params.loop != null) loop = params.loop; + if (params.volume != null) volume = params.volume; + if (params.onPlayComplete != null) onPlayComplete = params.onPlayComplete; + } + // 创建音效资源 let clip: AudioClip; if (url instanceof AudioClip) { @@ -63,6 +75,8 @@ export class AudioEffectPool { } else { clip = resLoader.get(url, AudioClip, bundleName)!; + + // 加载音效资源 if (clip == null) { let urls = this.res.get(bundleName); if (urls == null) { @@ -101,22 +115,24 @@ export class AudioEffectPool { node.name = "AudioEffect"; node.parent = oops.audio.node; ae = node.addComponent(AudioEffect)!; + ae.onComplete = () => { + this.put(aeid, url, bundleName); // 播放完回收对象 + onPlayComplete && onPlayComplete(aeid, url, bundleName); + // console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`); + }; } else { node = this.pool.get()!; ae = node.getComponent(AudioEffect)!; } - ae.onComplete = () => { - this.put(aeid, url, bundleName); // 播放完回收对象 - onPlayComplete && onPlayComplete(); - // console.log(`【音效】回收,池中剩余音效播放器【${this.pool.size()}】`); - }; // 记录正在播放的音效播放器 this.effects.set(key, ae); - ae.volume = this.volume; + ae.loop = loop; ae.clip = clip; + ae.volume = volume; + ae.currentTime = 0; ae.play(); resolve(aeid); @@ -147,23 +163,6 @@ export class AudioEffectPool { } } - /** 释放所有音效资源与对象池中播放器 */ - release() { - // 释放正在播放的音效 - this.effects.forEach(ae => { - ae.node.destroy(); - }); - this.effects.clear(); - - // 释放音效资源 - this.res.forEach((urls: string[], bundleName: string) => { - urls.forEach(url => resLoader.release(url, bundleName)); - }); - - // 释放池中播放器 - this.pool.clear(); - } - /** 停止播放所有音效 */ stop() { this.effects.forEach(ae => { @@ -188,4 +187,21 @@ export class AudioEffectPool { ae.pause(); }); } + + /** 释放所有音效资源与对象池中播放器 */ + release() { + // 释放正在播放的音效 + this.effects.forEach(ae => { + ae.node.destroy(); + }); + this.effects.clear(); + + // 释放音效资源 + this.res.forEach((urls: string[], bundleName: string) => { + urls.forEach(url => resLoader.release(url, bundleName)); + }); + + // 释放池中播放器 + this.pool.clear(); + } } \ No newline at end of file diff --git a/assets/core/common/audio/AudioManager.ts b/assets/core/common/audio/AudioManager.ts index 670fa3c..3eee464 100644 --- a/assets/core/common/audio/AudioManager.ts +++ b/assets/core/common/audio/AudioManager.ts @@ -2,6 +2,7 @@ import { AudioClip, Component } from "cc"; import { oops } from "../../Oops"; import { AudioEffectPool } from "./AudioEffectPool"; import { AudioMusic } from "./AudioMusic"; +import { IAudioParams } from "./IAudio"; const LOCAL_STORE_KEY = "game_audio"; @@ -19,100 +20,15 @@ export class AudioManager extends Component { effect: AudioEffectPool = new AudioEffectPool(); /** 音乐管理状态数据 */ - private local_data: any = {}; - - /** - * 设置背景音乐播放完成回调 - * @param callback 背景音乐播放完成回调 - */ - setMusicComplete(callback: Function | null = null) { - this.music.onComplete = callback; - } - - /** - * 播放背景音乐 - * @param url 资源地址 - * @param callback 音乐播放完成事件 - * @param bundleName 资源包名 - */ - playMusic(url: string, callback?: Function, bundleName?: string) { - if (this.music.switch) { - this.music.loop = false; - this.music.load(url, callback, bundleName).then(); - } - } - - /** 循环播放背景音乐 */ - playMusicLoop(url: string, bundleName?: string) { - if (this.music.switch) { - this.music.loop = true; - this.music.load(url, null!, bundleName).then(); - } - } - - /** 停止背景音乐播放 */ - stopMusic() { - if (this.music.switch && this.music.playing) { - this.music.stop(); - } - } - - /** - * 获取背景音乐播放进度 - */ - get progressMusic(): number { - return this.music.progress; - } - - /** - * 设置背景乐播放进度 - * @param value 播放进度值 - */ - set progressMusic(value: number) { - this.music.progress = value; - } - - /** - * 获取背景音乐音量 - */ - get volumeMusic(): number { - return this.music.volume; - } - - /** - * 设置背景音乐音量 - * @param value 音乐音量值 - */ - set volumeMusic(value: number) { - this.music.volume = value; - this.save(); - } - - /** - * 获取背景音乐开关值 - */ - get switchMusic(): boolean { - return this.music.switch; - } - - /** - * 设置背景音乐开关值 - * @param value 开关值 - */ - set switchMusic(value: boolean) { - this.music.switch = value; - if (!value) this.music.stop(); - this.save(); - } + private localData: any = {}; /** * 播放音效 * @param url 资源地址 - * @param callback 加载完成回调 - * @param bundleName 资源包名 + * @param params 音效参数 */ - playEffect(url: string | AudioClip, bundleName?: string, onPlayComplete?: Function): Promise { - return this.effect.load(url, bundleName, onPlayComplete); + playEffect(url: string | AudioClip, params?: IAudioParams): Promise { + return this.effect.loadAndPlay(url, params); } /** 回收音效播放器 */ @@ -120,35 +36,6 @@ export class AudioManager extends Component { this.effect.put(aeid, url, bundleName); } - /** 获取音效音量 */ - get volumeEffect(): number { - return this.effect.volume; - } - - /** - * 设置获取音效音量 - * @param value 音效音量值 - */ - set volumeEffect(value: number) { - this.effect.volume = value; - this.save(); - } - - /** 获取音效开关值 */ - get switchEffect(): boolean { - return this.effect.switch; - } - - /** - * 设置音效开关值 - * @param value 音效开关值 - */ - set switchEffect(value: boolean) { - this.effect.switch = value; - if (!value) this.effect.stop(); - this.save(); - } - /** 恢复当前暂停的音乐与音效播放 */ resumeAll() { if (!this.music.playing && this.music.progress > 0) this.music.play(); @@ -169,20 +56,20 @@ export class AudioManager extends Component { /** 保存音乐音效的音量、开关配置数据到本地 */ save() { - this.local_data.volume_music = this.music.volume; - this.local_data.volume_effect = this.effect.volume; - this.local_data.switch_music = this.music.switch; - this.local_data.switch_effect = this.effect.switch; + 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.local_data); + oops.storage.set(LOCAL_STORE_KEY, this.localData); } /** 本地加载音乐音效的音量、开关配置数据并设置到游戏中 */ load() { this.music = this.getComponent(AudioMusic) || this.addComponent(AudioMusic)!; - this.local_data = oops.storage.getJson(LOCAL_STORE_KEY); - if (this.local_data) { + this.localData = oops.storage.getJson(LOCAL_STORE_KEY); + if (this.localData) { try { this.setState(); } @@ -196,14 +83,14 @@ export class AudioManager extends Component { } private setState() { - this.music.volume = this.local_data.volume_music; - this.effect.volume = this.local_data.volume_effect; - this.music.switch = this.local_data.switch_music; - this.effect.switch = this.local_data.switch_effect; + 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; } private setStateDefault() { - this.local_data = {}; + this.localData = {}; this.music.volume = 1; this.effect.volume = 1; this.music.switch = true; diff --git a/assets/core/common/audio/AudioMusic.ts b/assets/core/common/audio/AudioMusic.ts index 8b1b395..0f30441 100644 --- a/assets/core/common/audio/AudioMusic.ts +++ b/assets/core/common/audio/AudioMusic.ts @@ -6,8 +6,9 @@ */ import { AudioClip, AudioSource, _decorator } from 'cc'; import { resLoader } from '../loader/ResLoader'; +import { IAudioParams } from './IAudio'; -const { ccclass, menu } = _decorator; +const { ccclass } = _decorator; /** * 背景音乐 @@ -15,25 +16,20 @@ const { ccclass, menu } = _decorator; */ @ccclass('AudioMusic') export class AudioMusic extends AudioSource { - /** 背景音乐开关 */ - switch: boolean = true; - /** 背景音乐播放完成回调 */ - onComplete: Function | null = null; - private _progress: number = 0; private _isLoading: boolean = false; - private _nextBundleName: string = null!; // 下一个音乐资源包 - private _nextUrl: string = null!; // 下一个播放音乐 + private _nextUrl: string = null!; + private _nextParams: IAudioParams = null!; + private _params: IAudioParams = null!; - start() { - // this.node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this); - this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this); + /** 背景音乐开关 */ + private _switch: boolean = true; + get switch(): boolean { + return this._switch; } - - // private onAudioStarted() { } - - private onAudioEnded() { - this.onComplete && this.onComplete(); + set switch(value: boolean) { + this._switch = value; + if (!value) this.stop(); } /** 获取音乐播放进度 */ @@ -51,34 +47,59 @@ export class AudioMusic extends AudioSource { this.currentTime = value * this.duration; } + start() { + // this.node.on(AudioSource.EventType.STARTED, this.onAudioStarted, this); + this.node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this); + } + + // private onAudioStarted() { } + + private onAudioEnded() { + if (this._params && this._params.onPlayComplete) { + this._params.onPlayComplete(); + } + } + /** * 加载音乐并播放 * @param url 音乐资源地址 - * @param callback 加载完成回调 - * @param bundleName 资源包名 + * @param params 背景音乐资源播放参数 */ - async load(url: string, callback?: Function, bundleName: string = resLoader.defaultBundleName) { + async loadAndPlay(url: string, params?: IAudioParams) { + if (!this.switch) return; // 禁止播放音乐 + // 下一个加载的背景音乐资源 if (this._isLoading) { - this._nextBundleName = bundleName; this._nextUrl = url; + this._nextParams = params!; return; } + let bundleName = resLoader.defaultBundleName; + let loop = false; + let volume = this.volume; + let onPlayComplete: Function = null!; + if (params) { + this._params = params! + if (params.bundle != null) bundleName = params.bundle; + if (params.loop != null) loop = params.loop; + if (params.volume != null) volume = params.volume; + if (params.onPlayComplete != null) onPlayComplete = params.onPlayComplete; + }; + this._isLoading = true; - var data: AudioClip = await resLoader.loadAsync(bundleName, url, AudioClip); - if (data) { + var clip: AudioClip = await resLoader.loadAsync(bundleName, url, AudioClip); + if (clip) { this._isLoading = false; // 处理等待加载的背景音乐 if (this._nextUrl != null) { // 加载等待播放的背景音乐 - this.load(this._nextUrl, callback, this._nextBundleName); - this._nextBundleName = this._nextUrl = null!; + this.loadAndPlay(this._nextUrl, this._nextParams); + this._nextUrl = null!; + this._nextParams = null!; } else { - callback && callback(); - // 正在播放的时候先关闭 if (this.playing) { this.stop(); @@ -88,12 +109,21 @@ export class AudioMusic extends AudioSource { this.release(); // 播放背景音乐 - this.clip = data; + this.clip = clip; + this.loop = loop; + this.volume = volume; + this.currentTime = 0; this.play(); } } } + stop(): void { + if (this.switch && this.playing) { + super.stop(); + } + } + /** 释放当前背景音乐资源 */ release() { if (this.clip) { diff --git a/assets/core/common/audio/IAudio.ts b/assets/core/common/audio/IAudio.ts new file mode 100644 index 0000000..68b5ecf --- /dev/null +++ b/assets/core/common/audio/IAudio.ts @@ -0,0 +1,10 @@ +export interface IAudioParams { + /** 资源包名 */ + bundle?: string, + /** 是否循环播放 */ + loop?: boolean; + /** 音效音量 */ + volume?: number; + /** 播放完成事件 */ + onPlayComplete?: Function; +} \ No newline at end of file diff --git a/assets/core/common/audio/IAudio.ts.meta b/assets/core/common/audio/IAudio.ts.meta new file mode 100644 index 0000000..158a088 --- /dev/null +++ b/assets/core/common/audio/IAudio.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "82ec630f-ea0b-4e37-a671-1b4555a756db", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 68f02c5..4a0e35e 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 { IAudioParams } from "../../core/common/audio/IAudio"; import { EventDispatcher } from "../../core/common/event/EventDispatcher"; import { EventMessage, ListenerFunc } from "../../core/common/event/EventMessage"; import { AssetType, CompleteCallback, Paths, ProgressCallback, resLoader } from "../../core/common/loader/ResLoader"; @@ -339,41 +340,44 @@ export class GameComponent extends Component { /** * 播放背景音乐(不受自动释放资源管理) * @param url 资源地址 - * @param callback 资源加载完成回调 - * @param bundleName 资源包名 + * @param params 背景音乐资源播放参数 */ - playMusic(url: string, callback?: Function, bundleName?: string) { - oops.audio.playMusic(url, callback, bundleName); - } - - /** - * 循环播放背景音乐(不受自动释放资源管理) - * @param url 资源地址 - * @param bundleName 资源包名 - */ - playMusicLoop(url: string, bundleName?: string) { - oops.audio.stopMusic(); - oops.audio.playMusicLoop(url, bundleName); + playMusic(url: string, params?: IAudioParams) { + oops.audio.music.loadAndPlay(url, params); } /** * 播放音效 * @param url 资源地址 - * @param callback 资源加载完成回调 - * @param bundleName 资源包名 + * @param params 音效播放参数 */ - async playEffect(url: string, bundleName?: string) { - if (bundleName == null) bundleName = oops.res.defaultBundleName; - let resId = await oops.audio.playEffect(url, bundleName, () => { - if (!this.isValid) return; - - const rps = this.resPaths.get(ResType.Audio); - if (rps) { - const key = this.getResKey(bundleName, url); - rps.delete(key); + 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 (!this.isValid) return; + + // 删除界面音效的播放记录 + const rps = this.resPaths.get(ResType.Audio); + if (rps) { + const key = this.getResKey(bundleName, url, aeid); + rps.delete(key); + } + } + + let resId = await oops.audio.playEffect(url, params); + this.addPathToRecord(ResType.Audio, bundleName, url, resId); // 支持界面释放时,立即停止所有音效的播放 + resolve(resId); }); - this.addPathToRecord(ResType.Audio, bundleName, url, resId); } //#endregion