天天看點

Unity的音頻管理器

Unity的音頻管理器

public class MusicManager : MonoBehaviour
{
    #region 單例
    private static MusicManager instance = null;
    public static MusicManager Instance
    {
        get
        {
            GameObject musicMgr = GameObject.Find("MusicManager");
            if (musicMgr == null)
            {
                musicMgr = new GameObject("MusicManager");
            }
            if (instance == null)
            {
                instance = musicMgr.GetComponent<MusicManager>();
                if (instance == null)
                {
                    instance = musicMgr.AddComponent<MusicManager>();
                }
            }
            return instance;
        }
    }
    #endregion
    private AudioSource musicAudioSource;//背景音樂的AudioSource

    private List<AudioSource> unusedSoundAudioSourceList;   // 存放可以使用的音頻元件

    private List<AudioSource> usedSoundAudioSourceList;     // 存放正在使用的音頻元件

    private Dictionary<string, AudioClip> audioClipDict;       // 緩存音頻檔案

    private float musicVolume = 1; //背景音樂聲音

    private float soundVolume = 1; //音效聲音

    public string musicVolumePrefs = "MusicVolume";//本地緩存背景音樂的鍵

    public string soundVolumePrefs = "SoundVolume";//本地緩存音效的鍵

    private int poolCount = 5;         // AudioSource對象池數量

    void Awake()
    {
        //初始化
        musicAudioSource = gameObject.AddComponent<AudioSource>();
        unusedSoundAudioSourceList = new List<AudioSource>();
        usedSoundAudioSourceList = new List<AudioSource>();
        audioClipDict = new Dictionary<string, AudioClip>();
        DontDestroyOnLoad(this.gameObject);
    }
    void Start() { }
    public void Init()
    {
        // 從本地緩存讀取聲音音量
        if (PlayerPrefs.HasKey(musicVolumePrefs))
        {
            musicVolume = PlayerPrefs.GetFloat(musicVolumePrefs,1);
        }
        if (PlayerPrefs.HasKey(soundVolumePrefs))
        {
            soundVolume = PlayerPrefs.GetFloat(soundVolumePrefs,1);
        }
    }

    /// <summary>
    /// 播放背景音樂
    /// </summary>
    /// <param name="path">路徑</param>
    /// <param name="isLoop">是否循環</param>
    public void PlayMusic(string path, bool isLoop = true)
    {
        //TODO背景音樂的淡入淡出用DOTWEEN
        musicAudioSource.clip = GetAudioClip(path);
        musicAudioSource.clip.LoadAudioData();
        musicAudioSource.loop = isLoop;
        musicAudioSource.volume = musicVolume;
        musicAudioSource.Play();
    }

    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="path">音效路徑</param>
    /// <param name="func">回調</param>
    public void PlaySound(string path, LuaFunction func)
    {

        AudioSource audioSource = null;
        if (unusedSoundAudioSourceList.Count != 0)
        {
            audioSource = UnusedToUsed();
        }
        else
        {
            AddAudioSource();
            audioSource = UnusedToUsed();
        }
        audioSource.clip = GetAudioClip(path);
        audioSource.clip.LoadAudioData();
        audioSource.volume = soundVolume;
        audioSource.loop = false;
        audioSource.Play();
        StartCoroutine(WaitPlayEnd(audioSource, func));
    }

    /// <summary>
    /// 播放3d音效
    /// </summary>
    /// <param name="path"></param>
    /// <param name="position"></param>
    public void Play3dSound(string path, Vector3 position)
    {
        AudioClip ac = GetAudioClip(path);
        AudioSource.PlayClipAtPoint(ac, position);
    }

    /// <summary>
    /// 設定音量
    /// </summary>
    /// <param name="music">背景音樂的音量</param>
    /// <param name="sound">音效的音量</param>
    public void SetVolume(float music,float sound)
    {
        ChangeMusicVolume(music);
        ChangeSoundVolume(sound);
    }

    /// <summary>
    /// 擷取音頻檔案,擷取後會緩存一份
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    private AudioClip GetAudioClip(string path)
    {
        if (audioClipDict.ContainsKey(path) == false)
        {
            AudioClip ac = Resources.Load(path) as AudioClip;
            if (ac == null)
            {
                Debug.LogError("音頻在Resource中不存在,請檢查音頻資源--path" + path);
                return null;
            }
            audioClipDict.Add(path, ac);
        }
        return audioClipDict[path];
    }


    /// <summary>
    /// 添加音頻元件
    /// </summary>
    /// <returns></returns>
    private AudioSource AddAudioSource()
    {
        if (unusedSoundAudioSourceList.Count != 0)
        {
            return UnusedToUsed();
        }
        else
        {
            AudioSource audioSource = gameObject.AddComponent<AudioSource>();
            unusedSoundAudioSourceList.Add(audioSource);
            return audioSource;
        }
    }

    /// <summary>
    /// 将未使用的音頻元件移至已使用集合裡
    /// </summary>
    /// <returns></returns>
    private AudioSource UnusedToUsed()
    {
        AudioSource audioSource = unusedSoundAudioSourceList[0];
        unusedSoundAudioSourceList.RemoveAt(0);
        usedSoundAudioSourceList.Add(audioSource);
        return audioSource;
    }

    /// <summary>
    /// 當播放音效結束後,将其移至未使用集合
    /// </summary>
    /// <param name="audioSource"></param>
    /// <returns></returns>
    IEnumerator WaitPlayEnd(AudioSource audioSource, LuaFunction func)
    {
        yield return new WaitUntil(() => { return !audioSource.isPlaying; });
        UsedToUnused(audioSource);
        if (func != null)
        {
            func.Call();
            func.Dispose();
            func = null;
        }
    }

    /// <summary>
    /// 将使用完的音頻元件移至未使用集合裡
    /// </summary>
    /// <param name="audioSource"></param>
    private void UsedToUnused(AudioSource audioSource)
    {
        if (usedSoundAudioSourceList.Contains(audioSource))
        {
            usedSoundAudioSourceList.Remove(audioSource);
        }
        if (unusedSoundAudioSourceList.Count >= poolCount)
        {
            Destroy(audioSource);
        }
        else if (audioSource != null && !unusedSoundAudioSourceList.Contains(audioSource))
        {
            unusedSoundAudioSourceList.Add(audioSource);
        }
    }


    /// <summary>
    /// 修改背景音樂音量
    /// </summary>
    /// <param name="volume"></param>
    private void ChangeMusicVolume(float volume)
    {
        musicVolume = volume;
        musicAudioSource.volume = volume;
        PlayerPrefs.SetFloat(musicVolumePrefs, volume);
    }

    /// <summary>
    /// 修改音效音量
    /// </summary>
    /// <param name="volume"></param>
    private void ChangeSoundVolume(float volume)
    {
        soundVolume = volume;
        for (int i = 0; i < unusedSoundAudioSourceList.Count; i++)
        {
            unusedSoundAudioSourceList[i].volume = volume;
        }
        for (int i = 0; i < usedSoundAudioSourceList.Count; i++)
        {
            usedSoundAudioSourceList[i].volume = volume;
        }
        PlayerPrefs.SetFloat(soundVolumePrefs, volume);
    }
           

繼續閱讀