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]);
}
}
}
}
}