using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; /// <summary> /// 音效 音乐管理器 /// 2D声音全局 /// 管理音乐、音效播放 暂停、声音大小管理 /// </summary> public class MusicManager : BaseManager<MusicManager> { private MusicManager() { musicObject = new GameObject("MusicObject"); GameObject.DontDestroyOnLoad(musicObject); musicObject.transform.position = Vector3.zero; MonoMgr.Instance.AddUpdateListener(Update); } /// <summary> /// 音乐音效组件挂在的对象 /// </summary> private readonly GameObject musicObject; /// <summary> /// 背景音乐播放组件 /// </summary> private AudioSource backMusicSource; /// <summary> /// 播放音效组件 /// </summary> private readonly List<AudioSource> audioSources = new List<AudioSource>(); /// <summary> /// 缓存池中的音效组件 /// </summary> private readonly List<AudioSource> audioSourcesCache =new List<AudioSource>(); /// <summary> /// 标记音效暂停 /// </summary> private bool isPauseSound = false; /// <summary> /// 播放背景音乐 /// </summary> /// <param name="clipName">b背景音乐资源文件名 Resources下路径名+文件名,不需要文件格式</param> /// <param name="volume">背景音乐声音大小</param> public void PlayBackMusic(string clipName,float volume) { ResourcesManager.Instance.LoadAsync<AudioClip>(clipName, (clip) => { if (!clip) { Debug.Log("资源加载失败!请检查文件名"); } //背景音乐播放组件 唯一 if (backMusicSource == null) backMusicSource = musicObject.AddComponent<AudioSource>(); backMusicSource.playOnAwake = false; //背景音乐声音 这个音乐根据项目 会有独立的设置数据 从设置数据传过来 backMusicSource.volume = volume; //背景音乐 文件 backMusicSource.clip = clip; //循环播放 backMusicSource.loop = true; //播放 backMusicSource.Play(); }); } /// <summary> /// 暂停背景音乐 /// </summary> public void PauseBackMusic() { if (backMusicSource == null) return; backMusicSource.Pause(); } /// <summary> /// 恢复播放 /// </summary> public void UnPauseBackMusic() { if (backMusicSource == null) return; backMusicSource.UnPause(); } /// <summary> /// 停止背景音乐 /// </summary> public void StopBackMusic() { if (backMusicSource == null) return; backMusicSource.Stop(); } /// <summary> /// 改变背景音乐声音大小 /// </summary> /// <param name="volume">声音值</param> public void ChangeBackMusic(float volume) { if (backMusicSource == null) return; backMusicSource.volume = volume; } /// <summary> /// 背景音乐 静音 /// </summary> /// <param name="isMute"></param> public void MuteMusic(bool isMute) { if (backMusicSource == null) return; backMusicSource.mute = isMute; } /// <summary> /// 播放音效 /// </summary> /// <param name="soundName">路径+音效文件名 不需要文件格式</param> /// <param name="volume">音效声音</param> /// <param name="isLoop">是否循环播放</param> /// <param name="action">获取音效播放组件</param> public void PlaySound(string soundName, float volume = 1, bool isLoop = false, UnityAction<AudioSource> action = null) { ResourcesManager.Instance.LoadAsync<AudioClip>(soundName, (clip) => { AudioSource audioSource; if (audioSourcesCache.Count==0) { audioSource = musicObject.AddComponent<AudioSource>(); audioSource.playOnAwake = false; audioSourcesCache.Add(audioSource); } audioSource = audioSourcesCache[0]; audioSourcesCache.RemoveAt(0); //设置声音大小 audioSource.volume = volume; //设置音效资源 audioSource.clip = clip; //循环 audioSource.loop = isLoop; //激活 audioSource.enabled = true; //播放 audioSource.Play(); //记录音效组件 这个有可能在多个地方同时调用 需要用锁 lock (this) { audioSources.Add(audioSource); } //播放音效后 获取音效组件 action?.Invoke(audioSource); }); } /// <summary> /// 暂停所有音效 /// </summary> public void PauseSound() { isPauseSound= true; lock (this) { for (int i = 0; i < audioSources.Count; i++) { audioSources[i].Pause(); } } } /// <summary> /// 重新播放所有正在播放的音效 /// </summary> public void UnPauseSounds() { isPauseSound = false; lock (this) { for (int i = 0; i < audioSources.Count; i++) { audioSources[i].UnPause(); } } } /// <summary> /// 静音 音效 /// </summary> /// <param name="isMute"></param> public void MuteSound(bool isMute) { lock(this) { for (int i = 0; i < audioSources.Count; i++) { audioSources[i].mute = isMute; } } } /// <summary> /// 改变音效声音 /// </summary> /// <param name="volume"></param> public void ChangeSoundVolume(float volume) { lock (this) { for (int i = 0; i < audioSources.Count; i++) { audioSources[i].volume = volume; } } } /// <summary> /// 检测音效是否播放完 对播放完的音效进行删除 考虑性能 使用缓存池 /// </summary> private void Update() { lock (this) { for (int i = audioSources.Count-1 ; i >= 0; i--) { if (!audioSources[i].isPlaying && !isPauseSound) { audioSources[i].clip = null; audioSources[i].mute = false; audioSources[i].loop = false; audioSources[i].enabled = false; audioSourcesCache.Add(audioSources[i]); audioSources.RemoveAt(i); } } } } ~MusicManager() { MonoMgr.Instance.RemoveUpdateListener(Update); } }