背景音乐复用AudioSource对象池:实现播放和停止

背景音乐复用AudioSource对象池:实现播放和停止

Unity 工具类 之 简单的音频播放管理框架/仅通过音频名即可播放和停止(音效背景音乐复用AudioSource对象池)

目录

一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。

一个音频播放管理类,管理音频的播放和停止,只要传一个音频名字即可实现播放和停止。

二、实现原理

1、类似一个音频名播放使用接口:AudioPlayManager.Instance.Play("Click", true);

2、类似一个音频名播放使用接口:AudioPlayManager.Instance.Stop("Click");(当然背景音乐播放使用何必要)

3、AudioSourceManager 类管理 AudioSource 对象池,的获取对象,释放对象等

4、AudioClipManager 读取音频配置文件游戏图片素材,加载对应音频资源,管理音频资源

5、简单框架和说明如下

三、注意事项

1、如果的音频足够简单,可以 只要两个 AudioSource,固定一个作为背景音乐播放,一个作为音效播放,而可以不用对象池

2、如果你的音频很多,也不是同时马上用到,可以不用马上全加载到内存中,可以使用的时候才加载,常用的才缓存到起来

3、音频的配置文件内容格式多样,可以csv、json ,必要可以在加密数据使用

4、注意,如果使用本例的配置文件形式unity按钮点击音效,因为配置文件的音频路径在后面开发学习,分割字符串保存加载路径的时候,一定要吧结尾的 \n 裁剪掉(namesPaths[1].Trim()),不然加载不到资源,这个被坑了很久才发现(打印输出都没有看出,后面复制打印结果粘贴到代码中才发现(粘贴自动回车换行,才恍然大悟,不容易啊)),请注意哈,不要再踩坑了哈

四、效果预览

五、实现步骤

1、打开Unity,新建一个空工程

2、在场景中,添加两个按钮,一个Play,一个Stop

3、在场景中,导入音频资源和配置文件

4、在工程中添加脚本,各司其能unity按钮点击音效,实现音频播放

5、把 TestAudioPlayManager 挂载到场景中,并对应赋值

6、运行场景,效果如上

六、关键代码

1、TestAudioPlayManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestAudioPlayManager : MonoBehaviour
{
    public Button PlayButton;
    public Button StopButton;
    // Start is called before the first frame update
    void Start()
    {
        PlayButton.onClick.AddListener(()=> {
            AudioPlayManager.Instance.Play("Click", true);
        });
        StopButton.onClick.AddListener(() => {
            AudioPlayManager.Instance.Stop("Click");
        });
    }
   
}

2、AudioPlayManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioPlayManager : MonoSingleton
{
    AudioSourceManager mAudioSourceManager;
    AudioClipManager mAudioClipManager;
    protected override void Awake()
    {
        base.Awake();
        mAudioSourceManager = new AudioSourceManager(this.gameObject);
        mAudioClipManager = new AudioClipManager();
    }
    public void Play(string audioName,bool isLoop = false) {
        Debug.Log(GetType()+ "/Play()/ audioName : "+ audioName);
        SingleClip clip = mAudioClipManager.GetAudioByName(audioName);
        AudioSource source = mAudioSourceManager.GetIdleAudioSource();
        clip?.Play(source, isLoop);
    }
    public void Stop(string audioName) {
        Debug.Log(GetType() + "/Stop()/ audioName : " + audioName);
        mAudioSourceManager.Stop(audioName);
    }
}

3、AudioSourceManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioSourceManager
{
    List allSourcesLst;
    GameObject owner;
    public AudioSourceManager(GameObject owner) {
        this.owner = owner;
        Init();
    }
    /// 
    /// 初始化列表,并预加载两个 AudioSource
    /// 
    void Init() {
        allSourcesLst = new List();
        for (int i = 0; i < 2; i++)
        {
            AudioSource item = owner.AddComponent();
            allSourcesLst.Add(item);
        }
    }
    /// 
    /// 获得闲置的 AudioSource
    /// 
    /// 
    public AudioSource GetIdleAudioSource() {
        //Debug.Log(GetType() + "/GetIdleAudioSource()/");
        for (int i = 0; i < allSourcesLst.Count; i++)
        {
            if (allSourcesLst[i].isPlaying == false)
            {
                return allSourcesLst[i];
            }
        }
        AudioSource item = owner.AddComponent();
        allSourcesLst.Add(item);
        return item;
    }
    /// 
    /// 释放多余的 AudioSource
    /// 包正列表中不会有太多 AudioSource
    /// 
    public void ReleaseUnnecessaryAudioSource() {
        int tmpCount = 0;
        List tmpSourceLst = new List();
        for (int i = 0; i < allSourcesLst.Count; i++)
        {
            if (allSourcesLst[i].isPlaying == false)
            {
                tmpCount++;
                if (tmpCount > 3)
                {
                    tmpSourceLst.Add(allSourcesLst[i]);
                }
            }
        }
        for (int i = 0; i < tmpSourceLst.Count; i++)
        {
            AudioSource item = tmpSourceLst[i];
            allSourcesLst.Remove(item);
            GameObject.Destroy(item);
        }
        tmpSourceLst.Clear();
        tmpSourceLst = null;
    }
    public void Stop(string audioName) {
        if (string.IsNullOrEmpty(audioName)==false)
        {
            for (int i = 0; i < allSourcesLst.Count; i++)
            {
                if (allSourcesLst[i].isPlaying ==true && allSourcesLst[i].clip.name.Equals(audioName))
                {
                    allSourcesLst[i].Stop();
                }
            }
        }
        
    }
}

4、AudioClipManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioClipManager 
{
    const string cfgPath = "AudioClip/AudioClipCfg";
    Dictionary clipNamePathDic;
    Dictionary clipNameAudioDic;
    string[] clipPathLst;
    public AudioClipManager() {
        clipNamePathDic = new Dictionary();
        clipNameAudioDic = new Dictionary();
        ReadConfig();
        LoadClip();
    }
    public SingleClip GetAudioByName(string clipName) {
        SingleClip item = null;
        clipNameAudioDic.TryGetValue(clipName, out item);
        return item;
        
    }
    void ReadConfig() {
        string strConfig = Resources.Load(cfgPath).text;
        string[] linesStr = strConfig.Split('\n');
        int clipCount = 0;
        if (int.TryParse(linesStr[0],out clipCount)==true)
        {
            clipPathLst = new string[clipCount];
            for (int i = 1; i <= clipCount; i++)
            {
                string[] namesPaths = linesStr[i].Split(':');
                clipNamePathDic.Add(namesPaths[0], namesPaths[1].Trim());
                clipPathLst[i-1] = namesPaths[1];
            }
        }
    }
    void LoadClip() {
        foreach (var item in clipNamePathDic)
        {
            Debug.Log(GetType() + "/LoadClip()/item.Value == " + item.Value);
            AudioClip clip = Resources.Load(item.Value);
            SingleClip singleClip = new SingleClip(clip);
            clipNameAudioDic.Add(item.Key, singleClip);
        }       
        // clipNamePathDic 这个可能用不上了,可以清空,避免一直占用内存
        clipNamePathDic.Clear();
        clipNamePathDic = null;
    }
}

5、SingleClip

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleClip
{
    AudioClip clip;
    public SingleClip(AudioClip clip) {
        this.clip = clip;
    }
    public void Play(AudioSource audioSource,bool isLoop=false) {
        audioSource.clip = clip;
        audioSource.loop = isLoop;
        audioSource.Play();
    }
}

6、AudioClipCfg

3
ChangePage:AudioClip/ChangePage
Click:AudioClip/Click
Hover:AudioClip/Hover

文章来源:https://blog.csdn.net/u014361280/article/details/109517579