全局音效管理器

近期经常用到全局音效的管理问题,就直接写了一个管理器,因为是在小游戏里面使用,暂时只用到了这些功能,后面有机会以在继续补充···

关于音效的动态加载,因为实际项目中并未用到(小游戏,采用序列化的方式),这里临时用Resources加载···

话不多说,都在注释里

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class AudioMgr : MonoBehaviour
{
    //序列化
    [Header("背景音乐")]
    [SerializeField] AudioClip backgroundMusic;
    [Header("音效")]
    [SerializeField] AudioClip[] audioClips;
    [Header("Resources加载路径")]
    [SerializeField] string clipResourcePath = "AudioClip";
    [Header("保留空闲播放器的数量")]
    [SerializeField] int emptySourceCount = 3;

    //播放器
    AudioSource baseSource;
    AudioSource bgmSource;

    //播放器list,音效Dictionary
    List<AudioSource> audioSourceList = new List<AudioSource>();
    Dictionary<string, AudioClip> audioClipDic = new Dictionary<string, AudioClip>();

    bool soundEnable;
    bool bgmEnable;

    string soundPlayerPrefsName = "soundPlayerPrefsName";
    string bgmPlayerPrefsName = "bgmPlayerPrefsName";
    
    //将该脚本挂载到场景GameObject,通过单例调用
    public static AudioMgr Instance;
    
    void Awake()
    {
        Instance = this;
    }
    
    void Start()
    {
        Init();
    }

    /*
    //若不需要序列化,音效采用动态加载的方式,可以不挂载该脚本,自动生成
    static AudioMgr instance;
    public static AudioMgr Instance
    {
        get
        {
            if(instance == null)
            {
                instance = new GameObject("AudioMgr").AddComponent<AudioMgr>();
                instance.Init();
            }
            return instance;
        }
    }
    */

    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
            DestroyEmptySource();
        if (Input.GetKeyDown(KeyCode.Alpha2))
            PlaySound("2");
        if (Input.GetKeyDown(KeyCode.Alpha3))
            PlaySound("3");
        if (Input.GetKeyDown(KeyCode.Alpha4))
            SoundAudioEnable = !SoundAudioEnable;
        if (Input.GetKeyDown(KeyCode.Alpha5))
            BgmAudioEnable = !BgmAudioEnable;

    }

    public void Init()
    {
        //生成base播放器
        baseSource = new GameObject("BaseAudioSource").AddComponent<AudioSource>();
        baseSource.transform.parent = AudioMgr.Instance.transform;
        baseSource.playOnAwake = true;
        baseSource.loop = false;

        //BGM播放器
        bgmSource = Instantiate(baseSource, transform);
        bgmSource.gameObject.name = "BackgroundSource";
        bgmSource.loop = true;

        if (backgroundMusic != null)
            bgmSource.clip = backgroundMusic;
        ResetAudio();
    }

    //读取并还原开关设置状态
    void ResetAudio()
    {
        soundEnable = (PlayerPrefs.GetInt(soundPlayerPrefsName, 1) > 0) ? true : false; ;
        bgmEnable = (PlayerPrefs.GetInt(bgmPlayerPrefsName, 1) > 0) ? true : false; ;
        if (bgmEnable)
            bgmSource.Play();
    }

    //设置、获取 音效、背景音乐开关状态
    public bool SoundAudioEnable
    {
        get { return soundEnable; }
        set
        {
            if (soundEnable != value)
            {
                soundEnable = value;
                PlayerPrefs.SetInt(soundPlayerPrefsName, soundEnable ? 1 : 0);
            }
        }
    }
    public bool BgmAudioEnable
    {
        get { return bgmEnable; }
        set
        {
            if(bgmEnable != value)
            {
                bgmEnable = value;
                PlayerPrefs.SetInt(bgmPlayerPrefsName, bgmEnable ? 1 : 0);
                if(bgmEnable)
                    bgmSource.Play();
                else
                    bgmSource.Stop();
            }
        }
    }

    //播放音效(音效/名字)
    public void PlaySound(string clipName)
    {
        PlaySound(GetClipByName(clipName));
    }
    public void PlaySound(AudioClip clip)
    {
        if (soundEnable && clip!= null)
            StartCoroutine(PlayAndDisableSource(clip));
    }

    //设置背景音乐(音效/名字)
    public void SetBGMClip(string bgmName)
    {
        SetBGMClip(GetClipByName(bgmName));
    }
    public void SetBGMClip(AudioClip bgmClip)
    {
        if (bgmClip != null)
        {
            bgmSource.clip = bgmClip;
            BgmAudioEnable = true;
        }
    }

    //销毁多余空闲播放器,保留指定数量备用
    //可在指定条件下触发,或者利用定时器间隔固定时间进行清理
    public void DestroyEmptySource()
    {
        if (audioSourceList.Count > emptySourceCount)
        {
            for (int i = audioSourceList.Count - 1; i >= emptySourceCount; i--)
            {
                if (audioSourceList[i].enabled)
                    return;
                else
                {
                    Destroy(audioSourceList[i].gameObject);
                    audioSourceList.RemoveAt(i);
                }
            }
        }
    }

    // --------------

    //播放一段音效,并在播放完成后,回收播放器
    IEnumerator PlayAndDisableSource(AudioClip clip)
    {
        AudioSource audioSource = GetOneEmptySource();
        
        audioSource.clip = clip;
        audioSource.Play();
        
        while (audioSource.isPlaying)
        {
            yield return new WaitForEndOfFrame();
        }
        audioSource.enabled = false;
    }
    
    //获取一个空的播放器
    AudioSource GetOneEmptySource()
    {
        //遍历是否有空闲播放器
        for (int i = 0; i < audioSourceList.Count; i++)
        {
            if (!audioSourceList[i].enabled)
            {
                audioSourceList[i].enabled = true;
                return audioSourceList[i];
            }
        }
        //若没有,创建新的,并添加到list中统一管理
        AudioSource tmpGo = Instantiate(baseSource, transform);
        audioSourceList.Add(tmpGo);
        return tmpGo;
    }
    
    //通过名字获取音效片段
    AudioClip GetClipByName(string clipName)
    {
        //获取过的音效,将存在字典中,下次直接通过字典获取
        if (audioClipDic.ContainsKey(clipName))
        {
            return audioClipDic[clipName];
        }
        else
        {
            //面板序列化
            if(audioClips != null)
            {
                for (int i = 0; i < audioClips.Length; i++)
                {
                    if (clipName == audioClips[i].name)
                    {
                        audioClipDic.Add(audioClips[i].name, audioClips[i]);
                        return audioClips[i];
                    }
                }
            }
            Debug.Log("<color=blue> 未序列化该音效 </color>" + clipName);

            //Resources加载
            if (!string.IsNullOrEmpty(clipResourcePath))
            {
                AudioClip tmpNewAudioClip;
                tmpNewAudioClip = Resources.Load<AudioClip>(clipResourcePath + "/" + clipName);
                if (tmpNewAudioClip != null)
                {
                    audioClipDic.Add(clipName, tmpNewAudioClip);
                    return tmpNewAudioClip;
                }
                else
                    Debug.Log("<color=red> Resources加载失败 </color>" + clipName);
            }
            else
                Debug.Log("<color=blue> Resources路径为空 </color>" + clipName);
            return null;
        }
    }

}

若有任何意见或建议,欢迎分享讨论~~~

-------------------- 分割线 --------------------

2019.9.11

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioHandler : MonoBehaviour
{
    Dictionary<string, AudioClip> clipDic = new Dictionary<string, AudioClip>();

    Queue<AudioSource> audioSourceQueue = new Queue<AudioSource>();

    void Start()
    {

    }

    public void Init()
    {

    }

    public void Clear()
    {
        DestroyEmptySource();
    }

    public void PlayBtnClickSound()
    {
        PlaySound(ConstConfig.uiBtnClipName);
    }

    //播放音效(音效/名字)
    public void PlaySound(string clipName)
    {
        PlaySound(GetClipByName(clipName));
    }
    public void PlaySound(AudioClip clip)
    {
        if (clip != null)
            StartCoroutine(PlayAudioClip(clip));
    }

    //销毁多余空闲播放器
    public void DestroyEmptySource()
    {
        List<AudioSource> audioSourceList = new List<AudioSource>(audioSourceQueue);

        for (int i = audioSourceList.Count - 1; i >= 0; i--)
        {
            if (!audioSourceList[i].isPlaying)
            {
                Destroy(audioSourceList[i]);
                audioSourceList.RemoveAt(i);
            }
        }

        audioSourceQueue.Clear();
        for (int i = 0; i < audioSourceList.Count; i++)
        {
            audioSourceQueue.Enqueue(audioSourceList[i]);
        }
    }

    // --------------

    //播放一段音效,并在播放完成后,回收播放器
    IEnumerator PlayAudioClip(AudioClip clip)
    {
        AudioSource audioSource = GetEmptySource();

        audioSource.loop = false;
        audioSource.clip = clip;
        audioSource.Play();

        while (audioSource.isPlaying)
        {
            yield return new WaitForEndOfFrame();
        }
        yield return null;
        audioSource.clip = null;
        audioSourceQueue.Enqueue(audioSource);
    }

    //获取一个空的播放器
    AudioSource GetEmptySource()
    {
        AudioSource tmpSource = null;
        //是否有空闲播放器
        if (audioSourceQueue.Count > 0)
        {
            tmpSource = audioSourceQueue.Dequeue();
        }
        else
        {
            //若没有,生成
            tmpSource = gameObject.AddComponent<AudioSource>();
            tmpSource.playOnAwake = false;
            tmpSource.loop = false;
        }
        return tmpSource;
    }

    //通过名字获取音效片段
    AudioClip GetClipByName(string clipName)
    {
        //获取过的音效,将存在字典中,下次直接通过字典获取
        if (clipDic.ContainsKey(clipName))
        {
            return clipDic[clipName];
        }
        else
        {
            //Resources加载
            AudioClip newClip = ResourcesLoader.LoadObject<AudioClip>(ConstConfig.audioClipPath, clipName);
            if (newClip != null)
            {
                clipDic.Add(clipName, newClip);
                return newClip;
            }

            Debug.Log("<color=red> Audio Clip == null </color>" + clipName);
            return null;
        }
    }

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧然CS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值