using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace ZXKFramework { /// /// 音频管理器 /// public class AudioManager : MonoBehaviour, ISound { //各个声道的AudioSource组件 AudioSource bgmAudioSource; AudioSource bgsAudioSource; AudioSource voiceAudioSource; //各个声道的游戏对象 GameObject bgmController; GameObject soundController; GameObject sound2D; GameObject sound3D; GameObject bgsController; GameObject msController; GameObject voiceController; //控制器的名字 string bgmControllerName = "BgmController"; string soundControllerName = "SoundController"; string soundPool2DName = "SoundPool2D"; string soundClip2DName = "SoundClip2D"; string soundPool3DName = "SoundPool3D"; string soundClip3DName = "SoundClip3D"; string bgsControllerName = "BgsController"; string msControllerName = "MsController"; string msClipName = "MsClip"; string voiceControllerName = "VoiceController"; private string soundDir = ""; private bool isMute = false; IRes resManager; public void SetResType(IRes res) { resManager = res; } public void Init(string dirPath) { soundDir = dirPath; //创建并设置背景音乐的控制器 bgmController = CreateController(bgmControllerName, transform); bgmAudioSource = bgmController.AddComponent(); bgmAudioSource.playOnAwake = false; bgmAudioSource.loop = true; //创建音效控制器 soundController = CreateController(soundControllerName, transform); sound2D = CreateController(soundPool2DName, soundController.transform); sound3D = CreateController(soundPool3DName, soundController.transform); //创建并设置环境音效的控制器 bgsController = CreateController(bgsControllerName, transform); bgsAudioSource = bgsController.AddComponent(); bgsAudioSource.playOnAwake = false; bgsAudioSource.loop = true; //创建提示音效的控制器 msController = CreateController(msControllerName, transform); //创建并设置角色语音的控制器 voiceController = CreateController(voiceControllerName, transform); voiceAudioSource = voiceController.AddComponent(); voiceAudioSource.playOnAwake = false; voiceAudioSource.loop = false; } public void Mute(bool _isMute) { isMute = _isMute; bgmAudioSource.volume = isMute? 0:1; bgsAudioSource.volume = isMute ? 0 : 1; voiceAudioSource.volume = isMute ? 0 : 1; MuteSound(sound2D, isMute); MuteSound(sound3D, isMute); MuteSound(msController, isMute); } void MuteSound(GameObject parent, bool _isMute) { if (parent.transform.childCount == 0) return; for (int i = 0; i < parent.transform.childCount; i++) { Transform loObj = sound3D.transform.GetChild(i); if (loObj.gameObject.activeSelf || loObj.GetComponent() != null) { loObj.GetComponent().volume = _isMute ? 0 : 1; } } } /// /// 播放BGM /// public void PlayBGM(string _bgm, bool loop = true, Action callBack = null) { GetAudio(_bgm, bgm => { if (bgm == null) { Debug.LogWarning("播放BGM失败!要播放的BGM为null"); return; } callBack?.Invoke(bgm); bgmAudioSource.loop = loop; bgmAudioSource.clip = bgm; bgmAudioSource.Play(); }); } /// /// 暂停BGM /// public void PauseBGM() { bgmAudioSource.Pause(); } /// /// 取消暂停BGM /// public void UnPauseBGM() { bgmAudioSource.UnPause(); } /// /// 停止BGM /// public void StopBGM() { bgmAudioSource.Stop(); bgmAudioSource.clip = null; } /// /// 播放2D音效 /// public void PlaySound(string _sound, Action callBack = null) { GetAudio(_sound, sound => { if (sound == null) { Debug.LogWarning("播放Sound失败!要播放的Sound为null"); return; } callBack?.Invoke(sound); GameObject go = null; for (int i = 0; i < sound2D.transform.childCount; i++) { //如果对象池中有,则从对象池中取出来用。 if (!sound2D.transform.GetChild(i).gameObject.activeSelf) { go = sound2D.transform.GetChild(i).gameObject; go.SetActive(true); break; } } //如果对象池中没有,则创建一个游戏对象。 if (go == null) { go = new GameObject(soundClip2DName); go.transform.SetParent(sound2D.transform); } //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件并设置参数。 if (!go.TryGetComponent(out AudioSource audioSource)) { audioSource = go.AddComponent(); audioSource.playOnAwake = false; audioSource.loop = false; } //设置要播放的音效 audioSource.clip = sound; //播放音效 audioSource.Play(); if (isMute) audioSource.volume = 0; //每隔1秒检测一次,如果该音效播放完毕,则销毁音效的游戏对象。 StartCoroutine(DestroyWhenFinished()); //每隔1秒检测一次,如果该音效播放完毕,则销毁音效的游戏对象。 IEnumerator DestroyWhenFinished() { do { yield return new WaitForSeconds(1); if (go == null || audioSource == null) yield break;//如果播放音频的游戏对象,或者AudioSource组件被销毁了,则直接跳出协程。 } while (audioSource != null && audioSource.time > 0); if (go != null) { audioSource.clip = null; go.SetActive(false); } } }); } /// /// 播放3D音效 /// public void PlaySound(string _sound, GameObject target, Action callBack = null) { GetAudio(_sound, sound => { if (sound == null) { Debug.LogWarning("播放Sound失败!要播放的Sound为null"); return; } callBack?.Invoke(sound); if (target == null) { Debug.LogWarning("播放Sound失败!无法在目标对象身上播放Sound,因为目标对象为null"); return; } //临时的空物体,用来播放音效。 GameObject go = null; for (int i = 0; i < sound3D.transform.childCount; i++) { //如果对象池中有,则从对象池中取出来用。 if (!sound3D.transform.GetChild(i).gameObject.activeSelf) { go = sound3D.transform.GetChild(i).gameObject; go.SetActive(true); break; } } //如果对象池中没有,则创建一个游戏对象。 if (go == null) { go = new GameObject(soundClip3DName); } //把用于播放音效的游戏对象放到目标物体之下,作为它的子物体 go.transform.SetParent(target.transform); go.transform.localPosition = Vector3.zero; //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件并设置参数。 if (!go.TryGetComponent(out AudioSource audioSource)) { audioSource = go.AddComponent(); audioSource.playOnAwake = false; audioSource.loop = false; audioSource.spatialBlend = 1f;//3D效果,近大远小。 } //设置要播放的音频 audioSource.clip = sound; //播放音频 audioSource.Play(); if (isMute) audioSource.volume = 0; //每隔1秒检测一次,如果该音频播放完毕,则销毁游戏对象。 StartCoroutine(DestoryWhenFinisied()); //每隔1秒检测一次,如果该音频播放完毕,则销毁游戏对象。 IEnumerator DestoryWhenFinisied() { do { yield return new WaitForSeconds(1); if (go == null || audioSource == null) yield break;//如果播放音频的游戏对象,或者AudioSource组件被销毁了,则直接跳出协程。 } while (audioSource != null && audioSource.time > 0); if (go != null) { //放入对象池 go.transform.SetParent(sound3D.transform); go.transform.localPosition = Vector3.zero; audioSource.clip = null; go.SetActive(false); } } }); } /// /// 在世界空间中指定的位置播放3D音效 /// public void PlaySound(string _sound, Vector3 worldPosition, Transform parent = null, Action callBack = null) { GetAudio(_sound, sound => { if (sound == null) { Debug.LogWarning("播放Sound失败!要播放的Sound为null"); return; } callBack?.Invoke(sound); //临时的空物体,用来播放音效。 GameObject go = null; for (int i = 0; i < sound3D.transform.childCount; i++) { //如果对象池中有,则从对象池中取出来用。 if (!sound3D.transform.GetChild(i).gameObject.activeSelf) { go = sound3D.transform.GetChild(i).gameObject; go.SetActive(true); break; } } //如果对象池没有,则创建一个游戏对象。 if (go == null) { go = new GameObject(soundClip3DName); } go.transform.position = worldPosition; go.transform.SetParent(parent); //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件并设置参数。 if (!go.TryGetComponent(out AudioSource audioSource)) { audioSource = go.AddComponent(); audioSource.playOnAwake = false; audioSource.loop = false; audioSource.spatialBlend = 1f;//3D效果,近大远小。 } //设置要播放的音频 audioSource.clip = sound; //播放音频 audioSource.Play(); if (isMute) audioSource.volume = 0; //每隔一秒检测一次,如果该音频播放完毕,则销毁该游戏对象。 StartCoroutine(DestroyWhenFinished()); IEnumerator DestroyWhenFinished() { do { yield return new WaitForSeconds(1); if (go == null || audioSource == null) yield break;//如果播放音频的游戏对象,或者AudioSource组件被销毁了,则直接跳出协程。 } while (audioSource != null && audioSource.time > 0); if (go != null) { //放入对象池 go.transform.SetParent(sound3D.transform); go.transform.localPosition = Vector3.zero; audioSource.clip = null; go.SetActive(false); } } }); } /// /// 播放环境音效 /// public void PlayBGS(string _bgs, bool loop = true, Action callBack = null) { GetAudio(_bgs, bgs => { if (bgs == null) { Debug.LogWarning("播放BGS失败!要播放的BGS为null"); return; } callBack?.Invoke(bgs); bgsAudioSource.loop = loop; bgsAudioSource.clip = bgs; bgsAudioSource.Play(); }); } /// /// 暂停环境音效 /// public void PauseBGS() { bgsAudioSource.Pause(); } /// /// 取消暂停环境音效 /// public void UnPauseBGS() { bgsAudioSource.UnPause(); } /// /// 停止BGS /// public void StopBGS() { bgsAudioSource.Stop(); bgsAudioSource.clip = null; } /// /// 播放提示音效 /// /// public void PlayMS(string _ms, Action callBack = null) { GetAudio(_ms, ms => { if (ms == null) { Debug.LogWarning("播放MS失败!要播放的MS为null"); return; } callBack?.Invoke(ms); //临时的空物体,用来播放提示音效 GameObject go = null; for (int i = 0; i < msController.transform.childCount; i++) { //如果对象池中有,则从对象池中取出来用。 if (!msController.transform.GetChild(i).gameObject.activeSelf) { go = msController.transform.GetChild(i).gameObject; go.SetActive(true); break; } } //如果对象池中没有,则创建一个游戏对象。 if (go == null) { go = new GameObject(msClipName); go.transform.SetParent(msController.transform); } //如果该游戏对象身上有AudioSource组件,则添加AudioSource组件并设置参数。 if (!go.TryGetComponent(out AudioSource audioSource)) { audioSource = go.AddComponent(); audioSource.playOnAwake = false; audioSource.loop = false; } //设置要播放的音频 audioSource.clip = ms; //播放提示音效 audioSource.Play(); if (isMute) audioSource.volume = 0; //每隔一秒检测一次,如果该提示音效播放完毕,则销毁。 StartCoroutine(DestroyWhenFinished()); //每隔一秒检测一次,如果该提示音效播放完毕,则销毁。 IEnumerator DestroyWhenFinished() { do { yield return new WaitForSeconds(1); if (go == null || audioSource == null) yield break;//如果播放音频的游戏对象,或者AudioSource组件被销毁了,则直接跳出协程。 } while (audioSource != null && audioSource.time > 0); if (go != null) { //放入对象池 go.transform.SetParent(msController.transform); audioSource.clip = null; go.SetActive(false); } } }); } /// /// 播放角色语音 /// public void PlayVoice(string _voice, Action callBack = null) { GetAudio(_voice, voice => { if (voice == null) return; callBack?.Invoke(voice); voiceAudioSource.clip = voice; voiceAudioSource.Play(); }); } /// /// 停止角色语音 /// public void StopVoice() { voiceAudioSource.Stop(); } GameObject CreateController(string name, Transform parent) { GameObject go = new GameObject(name); go.transform.SetParent(parent); return go; } public void GetAudio(string audioName, Action callBack) { if (!Game.Instance.sceneObjFindAudioClip) { string path = string.IsNullOrEmpty(soundDir) ? audioName : soundDir + "/" + audioName; resManager?.Load(path, callBack); } else { if (string.IsNullOrEmpty(soundDir) || GameObject.Find(soundDir) == null) { Debug.LogError("场景中不存在声音父物体 :" + soundDir); return; } AudioClipInScene loAudioClipInScene = GameObject.Find(soundDir).GetOrAddComponent(); if (loAudioClipInScene.allClips.ContainsKey(audioName)) { callBack?.Invoke(loAudioClipInScene.allClips[audioName]); } } } } }