最终效果

在这里插入图片描述

前言

在游戏开发中,音乐和音效的管理是一个重要的环节。好的音乐和合适的音效可以为游戏增添氛围并提升玩家的体验。为了更好地管理音乐和音效,我们可以封装一个专门的音乐和音效管理器。

一、音频管理器

1、初始化

创建播放BGM背景音乐、Sound音效、BGS环境音效、MS提示音效、Voice角色语音的游戏对象

/// <summary>
/// 音频管理器
/// </summary>
public class AudioManager : SingletonMono<AudioManager>
{
	//各个声道的AudioSource组件
	AudioSource bgmAudioSource;
	AudioSource bgsAudioSource;
	AudioSource voiceAudioSource;
	
	//各个声道的游戏对象
	GameObject bgmController;
	GameObject soundController;
	GameObject bgsController;
	GameObject msController;
	GameObject voiceController;
        
	//控制器的名字
    string bgmControllerName = "BgmController";
    string soundControllerName = "SoundController";
    string bgsControllerName = "BgsController";
    string msControllerName = "MsController";
    string voiceControllerName = "VoiceController";

	void Awake()
    {
        //创建并设置背景音乐的控制器
        bgmController = CreateController(bgmControllerName, transform);
        bgmAudioSource = bgmController.AddComponent<AudioSource>();
        bgmAudioSource.playOnAwake = false;
        bgmAudioSource.loop = true;

        //创建音效控制器
        soundController = CreateController(soundControllerName, transform);

        //创建并设置环境音效的控制器
        bgsController = CreateController(bgsControllerName, transform);
        bgsAudioSource = bgsController.AddComponent<AudioSource>();
        bgsAudioSource.playOnAwake = false;
        bgsAudioSource.loop = true;

        //创建提示音效的控制器
        msController = CreateController(msControllerName, transform);

        //创建并设置角色语音的控制器
        voiceController = CreateController(voiceControllerName, transform);
        voiceAudioSource = voiceController.AddComponent<AudioSource>();
        voiceAudioSource.playOnAwake = false;
        voiceAudioSource.loop = false;
     }
        
	GameObject CreateController(string name, Transform parent)
	{
	    GameObject go = new GameObject(name);
	    go.transform.SetParent(parent);
	    return go;
	}
}

效果
在这里插入图片描述

2、播放、暂停、取消暂停、停止BGM

/// <summary>
/// 播放BGM
/// </summary>
/// <param name="bgm">背景音乐</param>
/// <param name="loop">是否循环</param>
public void PlayBGM(AudioClip bgm, bool loop = true)
{
    if (bgm == null)
    {
        Debug.LogWarning("播放BGM失败!要播放的BGM为null");
        return;
    }

    bgmAudioSource.loop = loop;
    bgmAudioSource.clip = bgm;
    bgmAudioSource.Play();
}

/// <summary>
/// 暂停BGM
/// </summary>
public void PauseBGM()
{
    bgmAudioSource.Pause();
}

/// <summary>
/// 取消暂停BGM
/// </summary>
public void UnPauseBGM()
{
    bgmAudioSource.UnPause();
}

/// <summary>
/// 停止BGM
/// </summary>
public void StopBGM()
{
    bgmAudioSource.Stop();
    bgmAudioSource.clip = null;
}

测试调用

public class AudioTest : MonoBehaviour
{
    AudioClip BGM1;
    AudioClip BGM2;
    
    void Start()
    {
        BGM1 = Resources.Load<AudioClip>("Audio/Bgm/BGM1");
        BGM2 = Resources.Load<AudioClip>("Audio/Bgm/BGM2");
    }

    private void OnGUI()
    {
        GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);   
        buttonStyle.fontSize = 50; // 设置字体大小

        if (GUI.Button(new Rect(0, 0, 400, 150), "播放BGM1", buttonStyle))
        {
            AudioManager.Instance.PlayBGM(BGM1);
        }
        if (GUI.Button(new Rect(0, 150, 400, 150), "播放BGM2", buttonStyle))
        {
            AudioManager.Instance.PlayBGM(BGM2);
        }
        if (GUI.Button(new Rect(0, 300, 400, 150), "暂停BGM", buttonStyle))
        {
            AudioManager.Instance.PauseBGM();
        }
        if (GUI.Button(new Rect(0, 450, 400, 150), "取消暂停BGM", buttonStyle))
        {
            AudioManager.Instance.UnPauseBGM();
        }
        if (GUI.Button(new Rect(0, 600, 400, 150), "停止BGM", buttonStyle))
        {
            AudioManager.Instance.StopBGM();
        }
    }
}

3、播放2D音效

/// <summary>
/// 播放2D音效
/// </summary>
public void PlaySound(AudioClip sound)
{
    //临时的空物体,用来播放音效。
    GameObject go = new GameObject(sound.name);

	//设置父物体
	go.transform.SetParent(soundController.transform);

    //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件并设置参数。
    if (!go.TryGetComponent<AudioSource>(out AudioSource audioSource))
    {
        audioSource = go.AddComponent<AudioSource>();
        audioSource.playOnAwake = false;
        audioSource.loop = false;
    }

    //设置要播放的音效
    audioSource.clip = sound;

    //播放音效
    audioSource.Play();

    //每隔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) Destroy(go);
    }
}

调用

AudioManager.Instance.PlaySound(Sound1);

4、在指定目标对象身上播放3D音效

/// </summary>
/// <summary>
/// 在指定目标对象身上播放3D音效
/// </summary>
/// <param name="sound">音效</param>
/// <param name="target">目标</param>
public void PlaySound(AudioClip sound, GameObject target)
{
    if (sound == null)
    {
        Debug.LogWarning("播放Sound失败!要播放的Sound为null");
        return;
    }

    if (target == null)
    {
        Debug.LogWarning("播放Sound失败!无法在目标对象身上播放Sound,因为目标对象为null");
        return;
    }

    //临时的空物体,用来播放音效。
    GameObject go = new GameObject(sound.name);

    //把用于播放音效的游戏对象放到目标物体之下,作为它的子物体
    go.transform.SetParent(target.transform);
    go.transform.localPosition = Vector3.zero;

    //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件并设置参数。
    if (!go.TryGetComponent<AudioSource>(out AudioSource audioSource))
    {
        audioSource = go.AddComponent<AudioSource>();
        audioSource.playOnAwake = false;
        audioSource.loop = false;
        audioSource.spatialBlend = 1f;//3D效果,近大远小。
    }

    //设置要播放的音频
    audioSource.clip = sound;

    //播放音频
    audioSource.Play();

    //每隔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) Destroy(go);
    }
}

调用

AudioManager.Instance.PlaySound(Sound2, gameObject);

5、音效对象池

其实之前我们已经写过了对象池管理器:【unity进阶知识7】对象池的使用,如何封装一个对象池管理器

但是为了降低代码耦合性,就不用之前的对象池管理器了,我们从新建一个音频对象池,专门用来对音频服务

新增AudioObjectPool 音频对象池代码

/// <summary>
/// 音频对象池
/// </summary>
public class AudioObjectPool : Singleton<AudioObjectPool>
{
    /// <summary>
    /// 获取对象
    /// </summary>
    /// <param name="SoundPool">对象池</param>
    /// <param name="parent">父级</param>
    /// <returns></returns>
    public GameObject Spawn(GameObject SoundPool, Transform parent = null)
    {
        GameObject go = null;
        for (int i = 0; i < SoundPool.transform.childCount; i++)
        {
            //如果对象池中有,则从对象池中取出来用。
            if (!SoundPool.transform.GetChild(i).gameObject.activeSelf)
            {
                go = SoundPool.transform.GetChild(i).gameObject;
                go.SetActive(true);
                break;
            }
        }
        //如果对象池中没有,则创建一个游戏对象。
        go = go ? go : new GameObject(SoundPool.name + "_Pool");

        if (parent) go.transform.SetParent(parent);

        go.transform.localPosition = Vector3.zero;


        return go;
    }

    /// <summary>
    /// 回收对象
    /// </summary>
    /// <param name="go">对象</param>
    /// <param name="parent">父级</param>
    public void Despawn(GameObject go, Transform parent = null)
    {
        if (parent) go.transform.SetParent(parent);
        go.transform.localPosition = Vector3.zero;

        go.SetActive(false);
    }
}

6、封装用对象池播放音效方法

/// <summary>
/// 播放音效
/// </summary>
/// <param name="sound">音效</param>
/// <param name="controller">对象池</param>
/// <param name="worldPosition">世界空间的位置</param>
/// <param name="parent">父级</param>
/// <param name="is3D">是否是3D音效</param>
void PlaySound(AudioClip sound, GameObject controller, Vector3 worldPosition, Transform parent = null, bool is3D = false)
{
    if (sound == null)
    {
        Debug.LogWarning("播放Sound失败!要播放的Sound为null");
        return;
    }

    GameObject go = AudioObjectPool.Instance.Spawn(controller, parent);

    //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件
    if (!go.TryGetComponent<AudioSource>(out AudioSource audioSource))
    {
        audioSource = go.AddComponent<AudioSource>();
    }

    if(is3D) audioSource.spatialBlend = 1f;//3D效果,近大远小。

    go.transform.position = worldPosition;

    //播放音效
    StartCoroutine(PlaySoundCoroutine(go, sound, controller.transform));
}

/// <summary>
/// 携程控制播放音效
/// </summary>
/// <param name="go">音频对象</param>
/// <param name="sound">音效</param>
/// <param name="parent">回收父级</param>
/// <returns></returns>
IEnumerator PlaySoundCoroutine(GameObject go, AudioClip sound, Transform parent = null)
{
    AudioSource audioSource = go.GetComponent<AudioSource>();
    //播放音效
    audioSource.PlayOneShot(sound);
    
    // 等待音效播放完成
    yield return CoroutineTool.WaitForSeconds(sound.length);
    
    // 音效播放完成后的逻辑
    audioSource.clip = null;
    AudioObjectPool.Instance.Despawn(go, parent);//放入对象池
}

7、使用对象池播放2D音效

/// <summary>
/// 播放2D音效
/// </summary>
public void PlaySound(AudioClip sound)
{
    PlaySound(sound, audioGameObjects[E_AudioController.Sound2DController], Vector3.zero);
}

8 使用对象池在指定目标对象身上播放3D音效

/// </summary>
/// <summary>
/// 在指定目标对象身上播放3D音效
/// </summary>
/// <param name="sound">音效</param>
/// <param name="target">目标</param>
public void PlaySound(AudioClip sound, Transform target)
{
    PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], Vector3.zero, target, true);
}

9、使用对象池在世界空间中指定的位置播放3D音效

/// <summary>
/// 在世界空间中指定的位置播放3D音效
/// </summary>
public void PlaySound(AudioClip sound, Vector3 worldPosition)
{
    PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], worldPosition, null, true);
}

10、播放、暂停、取消暂停、停止BGS环境音效,和bgm差不多

/// <summary>
/// 播放环境音效
/// </summary>
public void PlayBGS(AudioClip bgs, bool loop = true)
{
    if (bgs == null)
    {
        Debug.LogWarning("播放BGS失败!要播放的BGS为null");
        return;
    }

    bgsAudioSource.loop = loop;
    bgsAudioSource.clip = bgs;
    bgsAudioSource.Play();
}

/// <summary>
/// 暂停环境音效
/// </summary>
public void PauseBGS()
{
    bgsAudioSource.Pause();
}

/// <summary>
/// 取消暂停环境音效
/// </summary>
public void UnPauseBGS()
{
    bgsAudioSource.UnPause();
}

/// <summary>
/// 停止BGS
/// </summary>
public void StopBGS()
{
    bgsAudioSource.Stop();
    bgsAudioSource.clip = null;
}

测试调用

//BGS环境音
if (GUI.Button(new Rect(width*2, 0, width, height), "播放环境音1", buttonStyle))
{
    AudioManager.Instance.PlayBGS(BGS1);
}
if (GUI.Button(new Rect(width*2, height, width, height), "播放环境音2", buttonStyle))
{
    AudioManager.Instance.PlayBGS(BGS2);
}
if (GUI.Button(new Rect(width*2, height*2, width, height), "暂停环境音", buttonStyle))
{
    AudioManager.Instance.PauseBGS();
}
if (GUI.Button(new Rect(width*2, height*3, width, height), "取消暂停环境音", buttonStyle))
{
    AudioManager.Instance.UnPauseBGS();
}
if (GUI.Button(new Rect(width*2, height*4, width, height), "停止环境音", buttonStyle))
{
    AudioManager.Instance.StopBGS();
}

11、使用对象池播放MS提示音效

/// <summary>
/// 播放提示音效
/// </summary>
/// <param name="ms">提示音效</param>
public void PlayMS(AudioClip ms)
{
    PlaySound(ms, audioGameObjects[E_AudioController.MsController], Vector3.zero);
}

12、播放和停止Voice角色语音

当然角色语言也可以通过3D的方式播放,代入感更强,具体取决于项目

/// <summary>
/// 播放角色语音
/// </summary>
public void PlayVoice(AudioClip voice)
{
    voiceAudioSource.clip = voice;
    voiceAudioSource.Play();
}

/// <summary>
/// 停止角色语音
/// </summary>
public void StopVoice()
{
    voiceAudioSource.Stop();
}

13、阶段性代码

E_AudioController.cs

/// <summary>
/// Audio控制器类型枚举
/// </summary>
public enum E_AudioController
{
    BgmController,
    SoundController,
    Sound2DController,
    Sound3DController,
    BgsController,
    MsController,
    VoiceController,
}

AudioObjectPool.cs

/// <summary>
/// 获取对象
/// </summary>
/// <param name="SoundPool">对象池</param>
/// <param name="parent">父级</param>
/// <returns></returns>
public GameObject Spawn(GameObject SoundPool, Transform parent = null)
{
    GameObject go = null;
    for (int i = 0; i < SoundPool.transform.childCount; i++)
    {
        //如果对象池中有,则从对象池中取出来用。
        if (!SoundPool.transform.GetChild(i).gameObject.activeSelf)
        {
            go = SoundPool.transform.GetChild(i).gameObject;
            go.SetActive(true);
            break;
        }
    }
    //如果对象池中没有,则创建一个游戏对象。
    go = go ? go : new GameObject(SoundPool.name + "_Pool");

    if(!parent) parent = SoundPool.transform;
    go.transform.SetParent(parent);

    go.transform.localPosition = Vector3.zero;


    return go;
}

AudioManager.cs

/// <summary>
/// 音频管理器
/// </summary>
public class AudioManager : SingletonMono<AudioManager>
{
    #region 初始化
    //各个声道的AudioSource组件
    AudioSource bgmAudioSource;
    AudioSource bgsAudioSource;
    AudioSource voiceAudioSource;

    //记录每个Audio控制器类型的父物体
    private Dictionary<E_AudioController, GameObject> audioGameObjects;
    
    void Awake()
    {
        //创建并设置背景音乐的控制器
        GameObject bgmController = CreateController(E_AudioController.BgmController.ToString(), transform);
        bgmAudioSource = bgmController.AddComponent<AudioSource>();
        bgmAudioSource.playOnAwake = false;
        bgmAudioSource.loop = true;

        //创建音效控制器
        GameObject soundController = CreateController(E_AudioController.SoundController.ToString(), transform);
        GameObject sound2DController = CreateController(E_AudioController.Sound2DController.ToString(), soundController.transform);
        GameObject sound3DController = CreateController(E_AudioController.Sound3DController.ToString(), soundController.transform);

        //创建并设置环境音效的控制器
        GameObject bgsController = CreateController(E_AudioController.BgsController.ToString(), transform);
        bgsAudioSource = bgsController.AddComponent<AudioSource>();
        bgsAudioSource.playOnAwake = false;
        bgsAudioSource.loop = true;

        //创建提示音效的控制器
        GameObject msController = CreateController(E_AudioController.MsController.ToString(), transform);

        //创建并设置角色语音的控制器
        GameObject voiceController = CreateController(E_AudioController.VoiceController.ToString(), transform);
        voiceAudioSource = voiceController.AddComponent<AudioSource>();
        voiceAudioSource.playOnAwake = false;
        voiceAudioSource.loop = false;
        
        //记录每个Audio控制器类型的父物体
        audioGameObjects = new Dictionary<E_AudioController, GameObject>
        {
            { E_AudioController.BgmController, bgmController },
            { E_AudioController.SoundController, soundController },
            { E_AudioController.Sound2DController, sound2DController },
            { E_AudioController.Sound3DController, sound3DController },
            { E_AudioController.BgsController, bgsController },
            { E_AudioController.MsController, msController },
            { E_AudioController.VoiceController, voiceController }
        };
    }
    GameObject CreateController(string name, Transform parent)
    {
        GameObject go = new GameObject(name);
        go.transform.SetParent(parent);
        return go;
    }
    #endregion
    
    #region BGM背景音乐
    /// <summary>
    /// 播放BGM
    /// </summary>
    /// <param name="bgm">背景音乐</param>
    /// <param name="loop">是否循环</param>
    public void PlayBGM(AudioClip bgm, bool loop = true)
    {
        if (bgm == null)
        {
            Debug.LogWarning("播放BGM失败!要播放的BGM为null");
            return;
        }

        bgmAudioSource.loop = loop;
        bgmAudioSource.clip = bgm;
        bgmAudioSource.Play();
    }

    /// <summary>
    /// 暂停BGM
    /// </summary>
    public void PauseBGM()
    {
        bgmAudioSource.Pause();
    }

    /// <summary>
    /// 取消暂停BGM
    /// </summary>
    public void UnPauseBGM()
    {
        bgmAudioSource.UnPause();
    }

    /// <summary>
    /// 停止BGM
    /// </summary>
    public void StopBGM()
    {
        bgmAudioSource.Stop();
        bgmAudioSource.clip = null;
    }
    #endregion

    #region 2D3D音效
    /// <summary>
    /// 播放2D音效
    /// </summary>
    public void PlaySound(AudioClip sound)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound2DController], Vector3.zero);
    }

    /// </summary>
    /// <summary>
    /// 在指定目标对象身上播放3D音效
    /// </summary>
    /// <param name="sound">音效</param>
    /// <param name="target">目标</param>
    public void PlaySound(AudioClip sound, Transform target)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], Vector3.zero, target, true);
    }

    /// <summary>
    /// 在世界空间中指定的位置播放3D音效
    /// </summary>
    public void PlaySound(AudioClip sound, Vector3 worldPosition)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], worldPosition, null, true);
    }
    #endregion

    #region BGS环境音效
    /// <summary>
    /// 播放环境音效
    /// </summary>
    public void PlayBGS(AudioClip bgs, bool loop = true)
    {
        if (bgs == null)
        {
            Debug.LogWarning("播放BGS失败!要播放的BGS为null");
            return;
        }

        bgsAudioSource.loop = loop;
        bgsAudioSource.clip = bgs;
        bgsAudioSource.Play();
    }

    /// <summary>
    /// 暂停环境音效
    /// </summary>
    public void PauseBGS()
    {
        bgsAudioSource.Pause();
    }

    /// <summary>
    /// 取消暂停环境音效
    /// </summary>
    public void UnPauseBGS()
    {
        bgsAudioSource.UnPause();
    }

    /// <summary>
    /// 停止BGS
    /// </summary>
    public void StopBGS()
    {
        bgsAudioSource.Stop();
        bgsAudioSource.clip = null;
    }
    #endregion

    #region 提示音效
    /// <summary>
    /// 播放提示音效
    /// </summary>
    /// <param name="ms">提示音效</param>
    public void PlayMS(AudioClip ms)
    {
        PlaySound(ms, audioGameObjects[E_AudioController.MsController], Vector3.zero);
    }
    #endregion

    #region 角色语言
    /// <summary>
    /// 播放角色语音
    /// </summary>
    public void PlayVoice(AudioClip voice)
    {
        voiceAudioSource.clip = voice;
        voiceAudioSource.Play();
    }

    /// <summary>
    /// 停止角色语音
    /// </summary>
    public void StopVoice()
    {
        voiceAudioSource.Stop();
    }
    #endregion

    #region 封装播放音效方法
    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="sound">音效</param>
    /// <param name="controller">对象池</param>
    /// <param name="worldPosition">世界空间的位置</param>
    /// <param name="parent">父级</param>
    /// <param name="is3D">是否是3D音效</param>
    void PlaySound(AudioClip sound, GameObject controller, Vector3 worldPosition, Transform parent = null, bool is3D = false)
    {
        if (sound == null)
        {
            Debug.LogWarning("播放Sound失败!要播放的Sound为null");
            return;
        }

        GameObject go = AudioObjectPool.Instance.Spawn(controller, parent);

        //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件
        if (!go.TryGetComponent<AudioSource>(out AudioSource audioSource))
        {
            audioSource = go.AddComponent<AudioSource>();
        }

        if(is3D) audioSource.spatialBlend = 1f;//3D效果,近大远小。

        go.transform.position = worldPosition;

        //播放音效
        StartCoroutine(PlaySoundCoroutine(go, sound, controller.transform));
    }

    /// <summary>
    /// 携程控制播放音效
    /// </summary>
    /// <param name="go">音频对象</param>
    /// <param name="sound">音效</param>
    /// <param name="parent">回收父级</param>
    /// <returns></returns>
    IEnumerator PlaySoundCoroutine(GameObject go, AudioClip sound, Transform parent = null)
    {
        AudioSource audioSource = go.GetComponent<AudioSource>();
        //播放音效
        audioSource.PlayOneShot(sound);
        
        // 等待音效播放完成
        yield return CoroutineTool.WaitForSeconds(sound.length);
        
        // 音效播放完成后的逻辑
        audioSource.clip = null;
        AudioObjectPool.Instance.Despawn(go, parent);//放入对象池
    }
    #endregion
}

三、AudioMixer混音器的作用

在这里插入图片描述

1、Audio Mixer简单的使用

1.1、创建Audio Mixer

创建方式:创建一个Mixer文件夹——>鼠标右键——>Create——>Audio Mixer即可

1.2、新建不同的音频控制器组

master就是主音量,里面每个又相互独立,可以单独控制各模块的音量
在这里插入图片描述

1.3、配置音频控制器组

在这里插入图片描述

1.4、调整音量

在这里插入图片描述

1.5、暴露音量控制参数

在这里插入图片描述
依次按照上图操作,得到下图,修改参数
在这里插入图片描述
代码控制音量变化

public AudioMixer audioMixer; // 进行控制的Mixer变量

public void SetMasterVolume(float volume) // 控制主音量的函数
{
	// MasterVolume为我们暴露出来的Master的参数
	audioMixer.SetFloat("MasterVolume", volume);
}

2、AudioMixer和我们的音效管理器结合,控制音量

绑定混音器控制器组

bgmAudioSource.outputAudioMixerGroup = audioMixer.FindMatchingGroups("BGM")[0];

音量控制,注意重置音量,不要用audioMixer.ClearFloat,获取音量时会有所延迟

/// <summary>
/// 设置总音量
/// </summary>
/// <param name="volume">音量</param>
public void SetMasterVolume(float volume)
{
    
    if (volume > 20f || volume < -80f)
    {
        Debug.LogWarning("音量必须在20到60之间");
        return;
    }
    audioMixer.SetFloat(MatserAudioMixerVolumeName, volume);
}

/// <summary>
/// 设置BGM音量
/// </summary>
/// <param name="volume">音量</param>
public void SetBGMVolume(float volume)
{
    // 确保 volume 在 0 到 1 之间
    if (volume < 0f || volume > 1f)
    {
        Debug.LogWarning("音量必须在 0 到 1 之间");
        return;
    }

    // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
    volume = Mathf.Lerp(-80f, 20f, volume);

    audioMixer.SetFloat(BGMAudioMixerVolumeName, volume);
}

/// <summary>
/// 设置音效音量
/// </summary>
/// <param name="volume">音量</param>
public void SetSoundVolume(float volume)
{
    // 确保 volume 在 0 到 1 之间
    if (volume < 0f || volume > 1f)
    {
        Debug.LogWarning("音量必须在 0 到 1 之间");
        return;
    }

    // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
    volume = Mathf.Lerp(-80f, 20f, volume);
    audioMixer.SetFloat(SoundAudioMixerVolumeName, volume);
}

/// <summary>
/// 设置环境音音量
/// </summary>
/// <param name="volume">音量</param>
public void SetBGSVolume(float volume)
{
    // 确保 volume 在 0 到 1 之间
    if (volume < 0f || volume > 1f)
    {
        Debug.LogWarning("音量必须在 0 到 1 之间");
        return;
    }

    // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
    volume = Mathf.Lerp(-80f, 20f, volume);
    audioMixer.SetFloat(BGSAudioMixerVolumeName, volume);
}

/// <summary>
/// 设置角色语音音量
/// </summary>
/// <param name="volume">音量</param>
public void SetVoiceVolume(float volume)
{
    // 确保 volume 在 0 到 1 之间
    if (volume < 0f || volume > 1f)
    {
        Debug.LogWarning("音量必须在 0 到 1 之间");
        return;
    }

    // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
    volume = Mathf.Lerp(-80f, 20f, volume);
    audioMixer.SetFloat(VoiceAudioMixerVolumeName, volume);
}

/// <summary>
/// 重置音量
/// </summary>
public void ResetVolume()
{
    SetMasterVolume(0.8f);
   	SetBGMVolume(0.8f);
    SetSoundVolume(0.8f);
    SetBGSVolume(0.8f);
    SetVoiceVolume(0.8f);
}

调用

if (GUI.Button(new Rect(width*5, 0, width, height), "设置总音量为1", buttonStyle))
{
    AudioManager.Instance.SetMasterVolume(1);
}
if (GUI.Button(new Rect(width*5, height, width, height), "设置BGM音量为0.8", buttonStyle))
{
    AudioManager.Instance.SetBGMVolume(0.8f);
}
if (GUI.Button(new Rect(width*5, height*2, width, height), "设置音效音量为0.5", buttonStyle))
{
    AudioManager.Instance.SetSoundVolume(0.5f);
}
if (GUI.Button(new Rect(width*5, height*3, width, height), "设置环境音音量为0.2", buttonStyle))
{
    AudioManager.Instance.SetBGSVolume(0.2f);
}
if (GUI.Button(new Rect(width*5, height*4, width, height), "设置角色语音音量为0", buttonStyle))
{
    AudioManager.Instance.SetVoiceVolume(0);
}
if (GUI.Button(new Rect(width*5, height*5, width, height), "重置音量", buttonStyle))
{
    AudioManager.Instance.ResetVolume();
}

3、实现bgm背景音和BGS环境音的淡入淡出效果,使切换不会那么突兀

新增携程,控制声音淡入淡出

//声音淡入淡出
private IEnumerator FadeOutAndPlay(AudioSource audioSource, AudioClip newBGM, float duration, bool loop, string VolumeName)
{
    // 获取当前音量值
    audioMixer.GetFloat(VolumeName, out float startVolume);

    // 淡出当前 BGM
    if (audioSource.clip){
        yield return StartCoroutine(FadeAudio(-30f, duration, VolumeName)); // 将音量降到 -30dB,持续 duration 秒
    }else{
        audioMixer.SetFloat(VolumeName, -30f);
    }

    // 播放新 BGM
    audioSource.loop = loop;
    audioSource.clip = newBGM;
    audioSource.Play();

    // 淡入新 BGM
    yield return StartCoroutine(FadeAudio(startVolume, duration, VolumeName)); // 将音量升回startVolume,持续 duration 秒
}

private IEnumerator FadeAudio(float targetVolume, float duration, string VolumeName)
{
    // 获取当前音量值
    audioMixer.GetFloat(VolumeName, out float startVolume);

    float elapsed = 0f;

    while (elapsed < duration)
    {
        elapsed += Time.deltaTime;
        float newVolume = Mathf.Lerp(startVolume, targetVolume, elapsed / duration);
        audioMixer.SetFloat(VolumeName, newVolume);
        yield return CoroutineTool.WaitForFrame();
    }

    // 确保最终音量准确
    audioMixer.SetFloat(VolumeName, targetVolume);
}

修改BGM和BGS播放方法

/// <summary>
/// 播放BGM
/// </summary>
/// <param name="bgm">背景音乐</param>
/// <param name="duration">过渡时间</param>
/// <param name="loop">是否循环</param>
/// <param name="isFade">是否淡入淡出</param>
public void PlayBGM(AudioClip bgm, float duration = 10f, bool loop = true, bool isFade = true)
{
    if (bgm == null)
    {
        Debug.LogWarning("播放BGM失败!要播放的BGM为null");
        return;
    }

    if (isFade)
    {
        StartCoroutine(FadeOutAndPlay(bgmAudioSource, bgm, duration, loop, BGMVolumeName));
    }
    else
    {
        bgmAudioSource.loop = loop;
        bgmAudioSource.clip = bgm;
        bgmAudioSource.Play();
    }
}

/// <summary>
/// 播放环境音
/// </summary>
/// <param name="bgs">环境音</param>
/// <param name="duration">过渡时间</param>
/// <param name="loop">是否循环</param>
/// <param name="isFade">是否淡入淡出</param>
public void PlayBGS(AudioClip bgs, float duration = 10f, bool loop = true, bool isFade = true)
{
    if (bgs == null)
    {
        Debug.LogWarning("播放BGS失败!要播放的BGS为null");
        return;
    }

    if (isFade)
    {
        StartCoroutine(FadeOutAndPlay(bgsAudioSource, bgs, duration, loop, BGSVolumeName));
    }
    else
    {
        bgsAudioSource.loop = loop;
        bgsAudioSource.clip = bgs;
        bgsAudioSource.Play();
    }
}

4、获取音量

public float MatserVolume => GetVolume(MatserVolumeName);
public float BGMVolume => GetVolume(BGMVolumeName);
public float BGSVolume => GetVolume(BGSVolumeName);
public float SoundVolum => GetVolume(SoundVolumeName);
public float VoiceVolume => GetVolume(VoiceVolumeName);
public float GetVolume(string VolumeName){
    audioMixer.GetFloat(VolumeName, out float volume);
    Debug.Log(volume);
    // 使用 Mathf.Lerp 将 volume 从[-80, 20]映射到[0, 1]
    volume = Mathf.Lerp(0f, 1f, (volume + 80f) / 100f);;
    Debug.Log(volume);
    return volume;
}

测试调用

//获取音量
float matserVolume = AudioManager.Instance.MatserVolume;
float bGMVolume = AudioManager.Instance.BGMVolume;
float bGSVolume = AudioManager.Instance.BGSVolume;
float soundVolum = AudioManager.Instance.SoundVolum;
float voiceVolume = AudioManager.Instance.VoiceVolume;

最终AudioManager代码

/// <summary>
/// 音频管理器
/// </summary>
public class AudioManager : SingletonMono<AudioManager>
{
    #region 参数
    //各个声道的AudioSource组件
    AudioSource bgmAudioSource;
    AudioSource bgsAudioSource;
    AudioSource voiceAudioSource;

    //记录每个Audio控制器类型的父物体
    private Dictionary<E_AudioController, GameObject> audioGameObjects;

    //混音器
    AudioMixer audioMixer;

    //混音器控制器组
    string BGMAudioMixerGroupName = "BGM";
    string SoundAudioMixerGroupName = "Sound";
    string BGSAudioMixerGroupName = "BGS";
    string VoiceAudioMixerGroupName = "Voice";

    //混音器控制器组暴露的音量变量
    string MatserVolumeName = "MasterVolume";
    string BGMVolumeName = "BGMVolume";
    string SoundVolumeName = "SoundVolume";
    string BGSVolumeName = "BGSVolume";
    string VoiceVolumeName = "VoiceVolume";

    //是否正在淡入淡出
    private bool isBGMFading = false;
    private bool isBGSFading = false;

    #endregion

    #region 初始化
    void Awake()
    {
        //加载混音器
        audioMixer = Resources.Load<AudioMixer>("AudioMixer/AudioMixer");

        //创建并设置背景音乐的控制器
        GameObject bgmController = CreateController(E_AudioController.BgmController.ToString(), transform);
        bgmAudioSource = bgmController.AddComponent<AudioSource>();
        bgmAudioSource.playOnAwake = false;
        bgmAudioSource.loop = true;
        bgmAudioSource.outputAudioMixerGroup = audioMixer.FindMatchingGroups(BGMAudioMixerGroupName)[0];

        //创建音效控制器
        GameObject soundController = CreateController(E_AudioController.SoundController.ToString(), transform);
        GameObject sound2DController = CreateController(E_AudioController.Sound2DController.ToString(), soundController.transform);
        GameObject sound3DController = CreateController(E_AudioController.Sound3DController.ToString(), soundController.transform);

        //创建并设置环境音效的控制器
        GameObject bgsController = CreateController(E_AudioController.BgsController.ToString(), transform);
        bgsAudioSource = bgsController.AddComponent<AudioSource>();
        bgsAudioSource.playOnAwake = false;
        bgsAudioSource.loop = true;
        bgsAudioSource.outputAudioMixerGroup = audioMixer.FindMatchingGroups(BGSAudioMixerGroupName)[0];

        //创建提示音效的控制器
        GameObject msController = CreateController(E_AudioController.MsController.ToString(), transform);

        //创建并设置角色语音的控制器
        GameObject voiceController = CreateController(E_AudioController.VoiceController.ToString(), transform);
        voiceAudioSource = voiceController.AddComponent<AudioSource>();
        voiceAudioSource.playOnAwake = false;
        voiceAudioSource.loop = false;
        voiceAudioSource.outputAudioMixerGroup = audioMixer.FindMatchingGroups(VoiceAudioMixerGroupName)[0];

        //记录每个Audio控制器类型的父物体
        audioGameObjects = new Dictionary<E_AudioController, GameObject>
        {
            { E_AudioController.BgmController, bgmController },
            { E_AudioController.SoundController, soundController },
            { E_AudioController.Sound2DController, sound2DController },
            { E_AudioController.Sound3DController, sound3DController },
            { E_AudioController.BgsController, bgsController },
            { E_AudioController.MsController, msController },
            { E_AudioController.VoiceController, voiceController }
        };
    }
    GameObject CreateController(string name, Transform parent)
    {
        GameObject go = new GameObject(name);
        go.transform.SetParent(parent);
        return go;
    }
    #endregion

    #region BGM背景音乐
    /// <summary>
    /// 播放BGM
    /// </summary>
    /// <param name="bgm">背景音乐</param>
    /// <param name="duration">过渡时间</param>
    /// <param name="loop">是否循环</param>
    /// <param name="isFade">是否淡入淡出</param>
    public void PlayBGM(AudioClip bgm, float duration = 10f, bool loop = true, bool isFade = true)
    {
        if (bgm == null)
        {
            Debug.LogWarning("播放BGM失败!要播放的BGM为null");
            return;
        }

        if (isBGMFading)
        {
            Debug.LogWarning("当前BGM正在淡入淡出,请稍后再试!");
            return;
        }

        if (isFade)
        {
            isBGMFading = true;
            StartCoroutine(FadeOutAndPlay(bgmAudioSource, bgm, duration, loop, BGMVolumeName));
        }
        else
        {
            bgmAudioSource.loop = loop;
            bgmAudioSource.clip = bgm;
            bgmAudioSource.Play();
        }
    }

    /// <summary>
    /// 暂停BGM
    /// </summary>
    public void PauseBGM()
    {
        bgmAudioSource.Pause();
    }

    /// <summary>
    /// 取消暂停BGM
    /// </summary>
    public void UnPauseBGM()
    {
        bgmAudioSource.UnPause();
    }

    /// <summary>
    /// 停止BGM
    /// </summary>
    public void StopBGM()
    {
        bgmAudioSource.Stop();
        bgmAudioSource.clip = null;
    }
    #endregion

    #region 角色语音
    /// <summary>
    /// 播放角色语音
    /// </summary>
    public void PlayVoice(AudioClip voice)
    {
        voiceAudioSource.clip = voice;
        voiceAudioSource.Play();
    }

    /// <summary>
    /// 停止角色语音
    /// </summary>
    public void StopVoice()
    {
        voiceAudioSource.Stop();
    }
    #endregion

    #region BGS环境音
    /// <summary>
    /// 播放环境音
    /// </summary>
    /// <param name="bgs">环境音</param>
    /// <param name="duration">过渡时间</param>
    /// <param name="loop">是否循环</param>
    /// <param name="isFade">是否淡入淡出</param>
    public void PlayBGS(AudioClip bgs, float duration = 10f, bool loop = true, bool isFade = true)
    {
        if (bgs == null)
        {
            Debug.LogWarning("播放BGS失败!要播放的BGS为null");
            return;
        }

        if (isBGSFading)
        {
            Debug.LogWarning("当前BGS正在淡入淡出,请稍后再试!");
            return;
        }

        if (isFade)
        {
            // 停止当前对象上所有正在运行的协程
            isBGSFading = true;
            StartCoroutine(FadeOutAndPlay(bgsAudioSource, bgs, duration, loop, BGSVolumeName));
        }
        else
        {
            bgsAudioSource.loop = loop;
            bgsAudioSource.clip = bgs;
            bgsAudioSource.Play();
        }
    }

    /// <summary>
    /// 暂停环境音效
    /// </summary>
    public void PauseBGS()
    {
        bgsAudioSource.Pause();
    }

    /// <summary>
    /// 取消暂停环境音效
    /// </summary>
    public void UnPauseBGS()
    {
        bgsAudioSource.UnPause();
    }

    /// <summary>
    /// 停止BGS
    /// </summary>
    public void StopBGS()
    {
        bgsAudioSource.Stop();
        bgsAudioSource.clip = null;
    }
    #endregion
    
    #region 2D3D音效
    /// <summary>
    /// 播放2D音效
    /// </summary>
    public void PlaySound(AudioClip sound)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound2DController], Vector3.zero);
    }

    /// </summary>
    /// <summary>
    /// 在指定目标对象身上播放3D音效
    /// </summary>
    /// <param name="sound">音效</param>
    /// <param name="target">目标</param>
    public void PlaySound(AudioClip sound, Transform target)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], Vector3.zero, target, true);
    }

    /// <summary>
    /// 在世界空间中指定的位置播放3D音效
    /// </summary>
    public void PlaySound(AudioClip sound, Vector3 worldPosition)
    {
        PlaySound(sound, audioGameObjects[E_AudioController.Sound3DController], worldPosition, null, true);
    }
    #endregion
    
    #region 提示音效
    /// <summary>
    /// 播放提示音效
    /// </summary>
    /// <param name="ms">提示音效</param>
    public void PlayMS(AudioClip ms)
    {
        PlaySound(ms, audioGameObjects[E_AudioController.MsController], Vector3.zero);
    }
    #endregion

    #region 封装播放音效方法
    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="sound">音效</param>
    /// <param name="controller">对象池</param>
    /// <param name="worldPosition">世界空间的位置</param>
    /// <param name="parent">父级</param>
    /// <param name="is3D">是否是3D音效</param>
    void PlaySound(AudioClip sound, GameObject controller, Vector3 worldPosition, Transform parent = null, bool is3D = false)
    {
        if (sound == null)
        {
            Debug.LogWarning("播放Sound失败!要播放的Sound为null");
            return;
        }

        GameObject go = AudioObjectPool.Instance.Spawn(controller, parent);

        //如果该游戏对象身上没有AudioSource组件,则添加AudioSource组件
        if (!go.TryGetComponent<AudioSource>(out AudioSource audioSource))
        {
            audioSource = go.AddComponent<AudioSource>();
        }

        if (is3D) audioSource.spatialBlend = 1f;//3D效果,近大远小。

        audioSource.outputAudioMixerGroup = audioMixer.FindMatchingGroups(SoundAudioMixerGroupName)[0];

        go.transform.position = worldPosition;

        //播放音效
        StartCoroutine(PlaySoundCoroutine(go, sound, controller.transform));
    }

    /// <summary>
    /// 携程控制播放音效
    /// </summary>
    /// <param name="go">音频对象</param>
    /// <param name="sound">音效</param>
    /// <param name="parent">回收父级</param>
    /// <returns></returns>
    IEnumerator PlaySoundCoroutine(GameObject go, AudioClip sound, Transform parent = null)
    {
        AudioSource audioSource = go.GetComponent<AudioSource>();
        //播放音效
        audioSource.PlayOneShot(sound);

        // 等待音效播放完成
        yield return CoroutineTool.WaitForSeconds(sound.length);

        // 音效播放完成后的逻辑
        audioSource.clip = null;
        AudioObjectPool.Instance.Despawn(go, parent);//放入对象池
    }
    #endregion

    #region 设置音量
    /// <summary>
    /// 设置总音量
    /// </summary>
    /// <param name="volume">音量</param>
    public void SetMasterVolume(float volume)
    {
        if (volume < 0f || volume > 1f)
        {
            Debug.LogWarning("音量必须在 0 到 1 之间");
            return;
        }
        // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
        volume = Mathf.Lerp(-80f, 20f, volume);
        audioMixer.SetFloat(MatserVolumeName, volume);
    }

    /// <summary>
    /// 设置BGM音量
    /// </summary>
    /// <param name="volume">音量</param>
    public void SetBGMVolume(float volume)
    {
        if (volume < 0f || volume > 1f)
        {
            Debug.LogWarning("音量必须在 0 到 1 之间");
            return;
        }
        // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
        volume = Mathf.Lerp(-80f, 20f, volume);
        audioMixer.SetFloat(BGMVolumeName, volume);
    }

    /// <summary>
    /// 设置音效音量
    /// </summary>
    /// <param name="volume">音量</param>
    public void SetSoundVolume(float volume)
    {
        if (volume < 0f || volume > 1f)
        {
            Debug.LogWarning("音量必须在 0 到 1 之间");
            return;
        }
        // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
        volume = Mathf.Lerp(-80f, 20f, volume);
        audioMixer.SetFloat(SoundVolumeName, volume);
    }

    /// <summary>
    /// 设置环境音音量
    /// </summary>
    /// <param name="volume">音量</param>
    public void SetBGSVolume(float volume)
    {
        if (volume < 0f || volume > 1f)
        {
            Debug.LogWarning("音量必须在 0 到 1 之间");
            return;
        }
        // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
        volume = Mathf.Lerp(-80f, 20f, volume);
        audioMixer.SetFloat(BGSVolumeName, volume);
    }

    /// <summary>
    /// 设置角色语音音量
    /// </summary>
    /// <param name="volume">音量</param>
    public void SetVoiceVolume(float volume)
    {
        if (volume < 0f || volume > 1f)
        {
            Debug.LogWarning("音量必须在 0 到 1 之间");
            return;
        }
        // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-80, 20]
        volume = Mathf.Lerp(-80f, 20f, volume);

        audioMixer.SetFloat(VoiceVolumeName, volume);
    }

    /// <summary>
    /// 重置音量
    /// </summary>
    public void ResetVolume()
    {
        SetMasterVolume(0.8f);
        SetBGMVolume(0.8f);
        SetSoundVolume(0.8f);
        SetBGSVolume(0.8f);
        SetVoiceVolume(0.8f);
    }
    #endregion

    #region 获取音量
    public float MatserVolume => GetVolume(MatserVolumeName);

    public float BGMVolume => GetVolume(BGMVolumeName);

    public float BGSVolume => GetVolume(BGSVolumeName);

    public float SoundVolum => GetVolume(SoundVolumeName);

    public float VoiceVolume => GetVolume(VoiceVolumeName);
    
    public float GetVolume(string VolumeName){
        audioMixer.GetFloat(VolumeName, out float volume);
        // 使用 Mathf.Lerp 将 volume 从[-80, 20]映射到[0, 1]
        volume = Mathf.Lerp(0f, 1f, (volume + 80f) / 100f);
        return volume;
    }
    #endregion
    #region 声音淡入淡出
    //声音淡入淡出
    private IEnumerator FadeOutAndPlay(AudioSource audioSource, AudioClip newBGM, float duration, bool loop, string VolumeName)
    {
        // 获取当前音量值
        audioMixer.GetFloat(VolumeName, out float startVolume);

        // 淡出当前 BGM
        if (audioSource.clip)
        {
            yield return StartCoroutine(FadeAudio(-30f, duration, VolumeName)); // 将音量降到 -30dB,持续 duration 秒
        }
        else
        {
            audioMixer.SetFloat(VolumeName, -30f);
        }

        // 播放新 BGM
        audioSource.loop = loop;
        audioSource.clip = newBGM;
        audioSource.Play();

        // 淡入新 BGM
        yield return StartCoroutine(FadeAudio(startVolume, duration, VolumeName)); // 将音量升回startVolume,持续 duration 秒

        isBGMFading = false;
        isBGSFading = false;
    }

    private IEnumerator FadeAudio(float targetVolume, float duration, string VolumeName)
    {
        // 获取当前音量值
        audioMixer.GetFloat(VolumeName, out float startVolume);

        float elapsed = 0f;

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float newVolume = Mathf.Lerp(startVolume, targetVolume, elapsed / duration);
            audioMixer.SetFloat(VolumeName, newVolume);
            yield return CoroutineTool.WaitForFrame();
        }

        // 确保最终音量准确
        audioMixer.SetFloat(VolumeName, targetVolume);
    }
    #endregion
}

四、制作设置音量面板

参考:【unity进阶知识10】从零手搓一个UI管理器/UI框架,自带一个提示界面,还有自带DOTween动画效果

可以和我们之前做的UI框架配合,制作一个设置音量面板

1、UI绘制

在这里插入图片描述

2、SettingsUI参考代码

public class SettingsUI : UIBase {
    void Awake(){
        OnBtnClick("bg/退出按钮", OnCloseBtn);
        OnBtnClick("bg/重置按钮", OnResetBtn);
        OnSliderChanged("bg/Volume/Master/Slide", OnSliderMasterVolume);
        OnSliderChanged("bg/Volume/BGM/Slide", OnSliderBGMVolume);
        OnSliderChanged("bg/Volume/BGS/Slide", OnSliderBGSVolume);
        OnSliderChanged("bg/Volume/Sound/Slide", OnSliderSoundVolume);
        OnSliderChanged("bg/Volume/Voice/Slide", OnSliderVoiceVolume);

        SetSliderValue();
    }

    void OnCloseBtn(){
        //关闭界面
        Close();
        //提示
        UIManager.Instance.ShowTips("关闭界面!", Color.red);
    }

    void OnResetBtn(){
        UIManager.Instance.ShowTips("重置成功!", Color.blue);
        AudioManager.Instance.ResetVolume();
        SetSliderValue();
    }

    //修改总音量
    void OnSliderMasterVolume(float value){
        AudioManager.Instance.SetMasterVolume(value);
    }

    void OnSliderBGMVolume(float value){
        AudioManager.Instance.SetBGMVolume(value);
    }
    void OnSliderBGSVolume(float value){
        AudioManager.Instance.SetBGSVolume(value);
    }
    void OnSliderSoundVolume(float value){
        AudioManager.Instance.SetSoundVolume(value);
    }
    void OnSliderVoiceVolume(float value){
        AudioManager.Instance.SetVoiceVolume(value);
    }



    void SetSliderValue(){
        transform.Find("bg/Volume/Master/Slide").GetComponent<Slider>().value = AudioManager.Instance.MatserVolume;
        transform.Find("bg/Volume/BGM/Slide").GetComponent<Slider>().value = AudioManager.Instance.BGMVolume;
        transform.Find("bg/Volume/BGS/Slide").GetComponent<Slider>().value = AudioManager.Instance.BGSVolume;
        transform.Find("bg/Volume/Sound/Slide").GetComponent<Slider>().value = AudioManager.Instance.SoundVolum;
        transform.Find("bg/Volume/Voice/Slide").GetComponent<Slider>().value = AudioManager.Instance.VoiceVolume;
    } 
}

3、打开设置面板

UIManager.Instance.ShowUI<SettingsUI>();

4、效果

设置面板

音量映射范围取为[-20,0](2024/12/3补充)

这个建议来源于评论大佬的补充,SetXXXVolume函数将[0,1]映射到[-80,20],这里映射范围取为[-20,0]即原音量的0.1-1倍会更符合需求,也会使slider的调整更平滑一些。

确实,将映射范围改为 [-20, 0] 更符合用户调节音量时的需求,特别是当你希望音量调整更加精细和平滑时。这个范围使得音量变化不会太过于急剧,特别是在较低音量时调整会更加平滑,提升了用户体验。

改进后的代码类似:

/// <summary>
/// 设置总音量
/// </summary>
/// <param name="volume">音量</param>
public void SetMasterVolume(float volume)
{
    if (volume < 0f || volume > 1f)
    {
        Debug.LogWarning("音量必须在 0 到 1 之间");
        return;
    }
    // 使用 Mathf.Lerp 将 volume 从 [0, 1] 映射到 [-20, 0]
    volume = Mathf.Lerp(-20f, 0f, volume);
    audioMixer.SetFloat(MatserVolumeName, volume);
}

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐