import { AssetManager, assetManager, AudioClip, AudioSource} from "cc"; import { constants } from "../data/constants"; import settingData from "../data/settingData"; /**音乐播放数据结构*/ export interface IAudioData { clip: AudioClip;//音乐片段 audioSource: AudioSource;//音乐具柄 path: string //音乐名称路径 playStatus: boolean //播放状态 totalTime: number;//音乐总长度时间 time_id: number;//定时器句柄 t: number;//统计记时 } class audioManager { private static instance: audioManager = null; //缓存的音乐片段和音乐具柄一体 是为了 同时播放多个攻击音效 private cachedAudioArr: Array = []; private bundleAudios: AssetManager.Bundle = null; //单例 public static ins() { if (!this.instance) { this.instance = new audioManager(); } return this.instance; } /** * 预加载音乐 */ public async initialize(): Promise { this.bundleAudios = await new Promise((resolve: Function, reject: Function) => { assetManager.loadBundle('audios', (err: Error, bundle: AssetManager.Bundle) => { if (err) { reject(err); } else { resolve(bundle); } }); }); for (let path of Object.values(constants.audios)) { if(path == "") continue; let audioClip: AudioClip = await new Promise((resolve: Function, reject: Function) => { this.bundleAudios.load(path, AudioClip, (err: Error, clip: AudioClip) => { if (err) { reject(err); } else { resolve(clip); } }); }); this.cachedAudioArr.push({ clip: audioClip, audioSource: null, path: path , playStatus: false, totalTime: audioClip.getDuration(), time_id: -1, t: 0 }); } window["youxi"] = { SoundManager: { pauseAll: () => { settingData.data.bg_music_status = false; settingData.data.sound_status = false; settingData.saveToCache(); if(settingData.data.bg_music_status){ this.play(constants.audios.bg_music,true); }else{ this.stop(constants.audios.bg_music); } }, resumeAll: () => { settingData.data.bg_music_status = true; settingData.data.sound_status = true; settingData.saveToCache(); } }, TargetedAds: { open: () => { }, clos: () => { } }, Fps: { setfps: (value) => { } } }; } /** * 播放音效 不会两个相同的音乐重复播放 可以停止 * @param path 播放音乐的路径 * @param loop 是否循环播放 * @param s 如果为-1则最大音量立即播放 如果为其他则慢慢音量递增起来播放 * @returns */ private bgVolumeMax: number = 0.8; public play(path: string,loop: boolean = false,s: number = -1): void { if(!settingData.data.bg_music_status)return; const fun = (audio:IAudioData)=>{ if(audio.audioSource == null){ audio.audioSource = this.audioSourceLoop(loop); } if(audio.playStatus)return; audio.audioSource.clip = a.clip; if(audio.time_id){ clearInterval(audio.time_id); if(audio.audioSource.playing){ audio.audioSource.pause(); } } audio.audioSource.play(); if(s == -1){ audio.audioSource.volume = this.bgVolumeMax; }else{ audio.t = 0; audio.audioSource.volume = 0; let interval: number = ((1 / s) / 10); audio.time_id = setInterval(()=>{ audio.t += interval; let volume: number = audio.t / s; if(volume >= this.bgVolumeMax){ clearInterval(audio.time_id); }else{ audio.audioSource.volume = volume; } },interval * 1000); } audio.playStatus = true; } let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path); if(a){ fun(a); }else{ this.bundleAudios.load(path, AudioClip, (err, clip)=>{ if (err) { console.warn(err); }else{ let data: IAudioData = { path: path, clip: clip, audioSource: null, playStatus: false, totalTime: clip.getDuration(), time_id: -1, t: 0 }; fun(data); } }); } } /** * 单次播放一次的音效 可以停止 * @param path 音乐路径 * @param overlap 是否可以重复两个同一个音效连续播放 * @returns */ public playOneShot(path: string,overlap: boolean = true): void { if(!settingData.data.sound_status)return; const fun = (audio:IAudioData)=>{ if(overlap || !audio.playStatus){ if(audio.audioSource == null){ audio.audioSource = this.audioSourceLoop(false); } audio.audioSource.clip = audio.clip; audio.audioSource.play(); audio.audioSource.volume = 1; audio.playStatus = true; } } let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path); if(a){ fun(a); }else{ this.bundleAudios.load(path, AudioClip, (err, clip)=>{ if (err) { console.warn(err); }else{ let data: IAudioData = { path: path, clip: clip, audioSource: null, playStatus: false, totalTime: clip.getDuration(), time_id: -1, t: 0 }; this.cachedAudioArr.push(data); fun(data); } }); } } /** * 停止播放音效 * @param path 音效路径名称 * @param s 为-1立即停止播放 非-1则是慢慢的声音越来越小的停止播放 * @returns */ public stop(path: string,s: number = -1): void { let audio: IAudioData = this.cachedAudioArr.find(e =>e.path == path); if(audio){ if(!audio.audioSource)return; if(!audio.audioSource.playing)return; if(audio.time_id){ clearInterval(audio.time_id); } let audioSource = audio.audioSource; if(s == -1){ audioSource?.pause(); }else{ audio.t = 0; let interval: number = ((1 / s) / 10); audio.time_id = setInterval(()=>{ if(audioSource){ audio.t += interval; let volume: number = this.bgVolumeMax - audio.t / s; if(volume <= 0){ clearInterval(audio.time_id); audioSource?.pause(); }else{ audioSource.volume = volume <= 0 ? 0 :volume; } } },interval * 1000); } audio.playStatus = false; } } /** * 加载音效 * @param loop 是否循环 */ public audioSourceLoop(loop: boolean): AudioSource{ let audioSource: AudioSource = null; if(loop){//播放单次的时候具柄 audioSource = this.getAudioSource(null,true,this.bgVolumeMax) }else{//循环播放的时候具柄 audioSource = this.getAudioSource(null,false,1); } return audioSource; } /** * 得到一个播放音乐的控制类 * @param clip 音效片段 * @param loop 是否循环 * @param volume 音量 * @returns 播放类 */ public getAudioSource(clip: AudioClip = null, loop: boolean = false, volume: number = 1): AudioSource{ let audioSource: AudioSource = new AudioSource(); if(clip){ audioSource.clip = clip; } audioSource.loop = loop; audioSource.volume = volume; return audioSource; } } export default audioManager.ins();