import { _decorator, Component, Node, AudioSourceComponent, loader, AudioClip, IsPowerOf2, url, instantiate, TERRAIN_HEIGHT_BASE } from 'cc'; const { ccclass, property } = _decorator; @ccclass('SoundManager') export class SoundManager extends Component { /** * 背景音乐通道 */ private musicSoundChannel:AudioChannel; /** * 固定通道 */ private soundChannelMap:Map; /** * 重复利用通道 */ private recycleSoundChannelList:AudioChannel[]; private recycleSoundChannelPool:AudioChannel[]; onLoad():void{ SoundManager.instance=this; this.soundChannelMap=new Map(); this.recycleSoundChannelList=[]; this.recycleSoundChannelPool=[]; } start () { //背景音乐通道 this.musicSoundChannel=new AudioChannel(); this.musicSoundChannel.aSComponent=this.addComponent(AudioSourceComponent); //最大重复利用通道4个 let channel:AudioChannel; for (let index = 0; index < 6; index++) { channel=new AudioChannel(); channel.aSComponent=this.addComponent(AudioSourceComponent); this.recycleSoundChannelPool.push(channel); } } public PlayMusic(soundPath:string):void{ this.musicSoundChannel.Play(soundPath,true); } /** * 固定通道播放音效 * @param channel 通道 * @param soundPath 音效地址 * @param isLoop 是否循环播放 * @param force 是否在相同音频的情况下强制从头开始播放 */ public PlaySound(channel:string,soundPath:string,isLoop:boolean=false,force:boolean=false):void{ let audioChannel:AudioChannel; if(this.soundChannelMap.has(channel)==false){ audioChannel=new AudioChannel(); audioChannel.aSComponent=this.addComponent(AudioSourceComponent); this.soundChannelMap.set(channel,audioChannel); }else{ audioChannel=this.soundChannelMap.get(channel); } audioChannel.Play(soundPath,isLoop,force); } /** * 清理通道 * @param channel */ public ClearSound(channel:string):void{ if(this.soundChannelMap.has(channel)==false){ return; } let audioChannel:AudioChannel=this.soundChannelMap.get(channel); audioChannel.Dispose(); this.soundChannelMap.delete(channel); } /** * 停止某个固定通道的音效 * @param channel */ public StopSound(channel:string):void{ if(this.soundChannelMap.has(channel)==false){ return; } let audioChannel:AudioChannel=this.soundChannelMap.get(channel); audioChannel.Stop(); } /** * 某个固定频道是否在播放中 * @param channel */ public ChannelIsPlaying(channel:string):boolean{ if(this.soundChannelMap.has(channel)==false){ return false; } let audioChannel:AudioChannel=this.soundChannelMap.get(channel); return audioChannel.isPlaying; } /** * 通道播放音效 * @param soundPath 音效地址 */ public PlaySoundRecycleChannel(soundPath:string):void{ let audioChannel:AudioChannel; //检测是否有已经播放完成的通道 for (let index = 0; index < this.recycleSoundChannelList.length; index++) { const element = this.recycleSoundChannelList[index]; if(element.isPlaying==false){ this.recycleSoundChannelPool.push(element); this.recycleSoundChannelList.splice(index,1); } } //如果池中没有,则不播放该音效! if(this.recycleSoundChannelPool.length==0){ return; } audioChannel=this.recycleSoundChannelPool.pop(); this.recycleSoundChannelList.push(audioChannel); //标记为被占有 audioChannel.Play(soundPath,false); } // update (deltaTime: number) { // // Your update function goes here. // } private static instance:SoundManager; public static get single():SoundManager{ return this.instance; } } class AudioChannel{ /** * 音频资源 */ private static audioClipMap:Map=new Map(); aSComponent:AudioSourceComponent; private soundUrl:string; private isLoop:boolean; private force:boolean; /** * 0 空闲 1加载中 2播放中 */ private state:number=0; constructor(){ } Play(soundUrl:string,isLoop:boolean,force:boolean=false):void{ if(this.soundUrl==soundUrl&&this.state==1){ return; } this.soundUrl=soundUrl; this.isLoop=isLoop; this.force=force; this.state=1; let key:string=url.raw("resources/"+this.soundUrl); if(AudioChannel.audioClipMap.has(key)){ let clip:AudioClip=AudioChannel.audioClipMap.get(key); console.log("播放音频缓存!"); this.__play(clip); }else{ loader.loadRes(this.soundUrl,AudioClip,this.audioLoadComplete.bind(this)); } } private audioLoadComplete(err:Error,asset:AudioClip):void{ if(err){ console.error("加载音乐错误!"); return; } let key:string=asset.nativeUrl.replace(asset["_native"],""); AudioChannel.audioClipMap.set(key,asset); if(this.state==0){ return; } this.__play(asset); } private __play(audioClip:AudioClip):void{ this.state=2; if(this.aSComponent==null){ return; } if(this.aSComponent.clip!=audioClip){ this.aSComponent.stop(); this.aSComponent.clip=audioClip; } this.aSComponent.loop=this.isLoop; if(this.force){ this.aSComponent.currentTime=0; } this.aSComponent.play(); } Stop():void{ this.state=0; this.soundUrl=null; this.aSComponent.stop(); } Dispose():void{ this.soundUrl=null; this.aSComponent.destroy(); this.aSComponent=null; } get isPlaying():boolean{ return this.state>0; } }