SoundManager.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import { _decorator, Component, Node, AudioSourceComponent, loader, AudioClip, IsPowerOf2, url, instantiate, TERRAIN_HEIGHT_BASE } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. @ccclass('SoundManager')
  4. export class SoundManager extends Component {
  5. /**
  6. * 背景音乐通道
  7. */
  8. private musicSoundChannel:AudioChannel;
  9. /**
  10. * 固定通道
  11. */
  12. private soundChannelMap:Map<string,AudioChannel>;
  13. /**
  14. * 重复利用通道
  15. */
  16. private recycleSoundChannelList:AudioChannel[];
  17. private recycleSoundChannelPool:AudioChannel[];
  18. onLoad():void{
  19. SoundManager.instance=this;
  20. this.soundChannelMap=new Map<string,AudioChannel>();
  21. this.recycleSoundChannelList=[];
  22. this.recycleSoundChannelPool=[];
  23. }
  24. start () {
  25. //背景音乐通道
  26. this.musicSoundChannel=new AudioChannel();
  27. this.musicSoundChannel.aSComponent=this.addComponent(AudioSourceComponent);
  28. //最大重复利用通道4个
  29. let channel:AudioChannel;
  30. for (let index = 0; index < 6; index++) {
  31. channel=new AudioChannel();
  32. channel.aSComponent=this.addComponent(AudioSourceComponent);
  33. this.recycleSoundChannelPool.push(channel);
  34. }
  35. }
  36. public PlayMusic(soundPath:string):void{
  37. this.musicSoundChannel.Play(soundPath,true);
  38. }
  39. /**
  40. * 固定通道播放音效
  41. * @param channel 通道
  42. * @param soundPath 音效地址
  43. */
  44. public PlaySound(channel:string,soundPath:string,isLoop:boolean=false):void{
  45. let audioChannel:AudioChannel;
  46. if(this.soundChannelMap.has(channel)==false){
  47. audioChannel=new AudioChannel();
  48. audioChannel.aSComponent=this.addComponent(AudioSourceComponent);
  49. this.soundChannelMap.set(channel,audioChannel);
  50. }else{
  51. audioChannel=this.soundChannelMap.get(channel);
  52. }
  53. audioChannel.Play(soundPath,isLoop);
  54. }
  55. /**
  56. * 清理通道
  57. * @param channel
  58. */
  59. public ClearSound(channel:string):void{
  60. if(this.soundChannelMap.has(channel)==false){
  61. return;
  62. }
  63. let audioChannel:AudioChannel=this.soundChannelMap.get(channel);
  64. audioChannel.Dispose();
  65. this.soundChannelMap.delete(channel);
  66. }
  67. /**
  68. * 停止某个固定通道的音效
  69. * @param channel
  70. */
  71. public StopSound(channel:string):void{
  72. if(this.soundChannelMap.has(channel)==false){
  73. return;
  74. }
  75. let audioChannel:AudioChannel=this.soundChannelMap.get(channel);
  76. audioChannel.Stop();
  77. }
  78. public ChannelIsPlaying(channel:string):boolean{
  79. if(this.soundChannelMap.has(channel)==false){
  80. return false;
  81. }
  82. let audioChannel:AudioChannel=this.soundChannelMap.get(channel);
  83. return audioChannel.isPlaying;
  84. }
  85. // /**
  86. // * 某个固定频道是否在播放中
  87. // * @param channel
  88. // */
  89. // public ChannelIsPlaying(channel:string):boolean{
  90. // if(this.soundChannelMap.has(channel)==false){
  91. // return false;
  92. // }
  93. // let audioChannel:AudioChannel=this.soundChannelMap.get(channel);
  94. // return audioChannel.isPlaying;
  95. // }
  96. /**
  97. * 固定通道播放音效
  98. * @param soundPath 音效地址
  99. */
  100. public PlaySoundRecycleChannel(soundPath:string):void{
  101. let audioChannel:AudioChannel;
  102. //检测是否有已经播放完成的通道
  103. for (let index = 0; index < this.recycleSoundChannelList.length; index++) {
  104. const element = this.recycleSoundChannelList[index];
  105. if(element.isPlaying==false){
  106. this.recycleSoundChannelPool.push(element);
  107. this.recycleSoundChannelList.splice(index,1);
  108. }
  109. }
  110. //如果池中没有,则不播放该音效!
  111. if(this.recycleSoundChannelPool.length==0){
  112. return;
  113. }
  114. audioChannel=this.recycleSoundChannelPool.pop();
  115. this.recycleSoundChannelList.push(audioChannel);
  116. //标记为被占有
  117. audioChannel.Play(soundPath,false);
  118. }
  119. // update (deltaTime: number) {
  120. // // Your update function goes here.
  121. // }
  122. private static instance:SoundManager;
  123. public static get single():SoundManager{
  124. return this.instance;
  125. }
  126. }
  127. class AudioChannel{
  128. /**
  129. * 音频资源
  130. */
  131. private static audioClipMap:Map<string,AudioClip>=new Map<string,AudioClip>();
  132. aSComponent:AudioSourceComponent;
  133. private soundUrl:string;
  134. private isLoop:boolean;
  135. /**
  136. * 0 空闲 1加载中 2播放中
  137. */
  138. private state:number=0;
  139. constructor(){
  140. }
  141. Play(soundUrl:string,isLoop:boolean):void{
  142. if(this.soundUrl==soundUrl&&this.state==1){
  143. return;
  144. }
  145. this.soundUrl=soundUrl;
  146. this.isLoop=isLoop;
  147. this.state=1;
  148. let key:string=url.raw("resources/"+this.soundUrl);
  149. if(AudioChannel.audioClipMap.has(key)){
  150. let clip:AudioClip=AudioChannel.audioClipMap.get(key);
  151. this.__play(clip);
  152. }else{
  153. loader.loadRes(this.soundUrl,AudioClip,this.audioLoadComplete.bind(this));
  154. }
  155. }
  156. private audioLoadComplete(err:Error,asset:AudioClip):void{
  157. if(err){
  158. console.error("加载音乐错误!");
  159. return;
  160. }
  161. let key:string=asset.nativeUrl.replace(asset["_native"],"");
  162. AudioChannel.audioClipMap.set(key,asset);
  163. if(this.state==0){
  164. return;
  165. }
  166. this.__play(asset);
  167. }
  168. private __play(audioClip:AudioClip):void{
  169. this.state=2;
  170. if(this.aSComponent==null){
  171. return;
  172. }
  173. if(this.aSComponent.clip!=audioClip){
  174. this.aSComponent.stop();
  175. this.aSComponent.clip=audioClip;
  176. }
  177. this.aSComponent.loop=this.isLoop;
  178. this.aSComponent.currentTime=0;
  179. this.aSComponent.play();
  180. }
  181. Stop():void{
  182. this.state=0;
  183. this.soundUrl=null;
  184. this.aSComponent.stop();
  185. }
  186. Dispose():void{
  187. this.soundUrl=null;
  188. this.aSComponent.destroy();
  189. this.aSComponent=null;
  190. }
  191. get isPlaying():boolean{
  192. return this.state>0;
  193. }
  194. }