Unity游戏框架设计之音频管理器

Unity游戏框架设计之音频管理器

简单介绍

在游戏中,主要的音频分为两种类型。第一种类型是 BGM(背景音乐),第二种类型是音效。BGM 的特点是音频持续时间长,一般在游戏中的同一时间内只能播放一个 BGM。音效的特点是音频持续时间短,一般在游戏中的同一时间内允许同时播放多个音效。

在下述代码中,实现了对 BGM 音量和音效音量的全局配置。玩家可以在游戏的设置 UI 中配置 BGM 音量和音效音量。同时实现了播放 BGM 和播放音效的功能,以及音频的生命周期方法。

代码设计

public class AudioManager : SingletonMono<AudioManager>
{
    private static AudioMixer _audioMixer;
    private static string _audioMixerGroupBGMPath;
    private static string _audioMixerGroupSoundsPath;
    private static string _bgmVolumeParameter;
    private static string _soundVolumeParameter;
    private readonly Dictionary<string, AudioClip> _audioClipSet = new();

    public static void Initialize(string audioMixerAssetPath, string audioMixerGroupBGMPath, string audioMixerGroupSoundsPath,
        string audioMixerBGMVolumeParameter, string audioMixerSoundsVolumeParameter)
    {
        _audioMixer = ResourceManager.Instance.LoadAsset<AudioMixer>(audioMixerAssetPath);
        _audioMixerGroupBGMPath = audioMixerGroupBGMPath;
        _audioMixerGroupSoundsPath = audioMixerGroupSoundsPath;
        _bgmVolumeParameter = audioMixerBGMVolumeParameter;
        _soundVolumeParameter = audioMixerSoundsVolumeParameter;
    }

    public void ConfigBGMVolume(float bgmVolume)
    {
        if (FloatUtils.IsEqualsTo(bgmVolume, 0f))
        {
            _audioMixer.SetFloat(_bgmVolumeParameter, -80);
            return;
        }
        _audioMixer.SetFloat(_bgmVolumeParameter, 5f / Mathf.Log10(2) * Mathf.Log10(bgmVolume));
    }

    public void ConfigSoundsVolume(float soundsVolume)
    {
        if (FloatUtils.IsEqualsTo(soundsVolume, 0f))
        {
            _audioMixer.SetFloat(_soundVolumeParameter, -80);
            return;
        }
        _audioMixer.SetFloat(_soundVolumeParameter, 5f / Mathf.Log10(2) * Mathf.Log10(soundsVolume));
    }

    public void PlayBGM(GameObject target, string audioAssetPath)
    {
        if (!_audioClipSet.ContainsKey(audioAssetPath))
        {
            LoadAsset(audioAssetPath);
        }
        SetBGM(target, audioAssetPath);
        PlayBGM(target);
    }

    public void PlaySound(GameObject target, string audioAssetPath)
    {
        if (!_audioClipSet.ContainsKey(audioAssetPath))
        {
            LoadAsset(audioAssetPath);
        }
        SetSounds(target, audioAssetPath);
        PlaySound(target);
    }

    public void PlaySound(GameObject target, List<string> audioAssetPathSet)
    {
        if (audioAssetPathSet.Count == 1)
        {
            PlaySound(target, audioAssetPathSet[0]);
            return;
        }
        foreach (string audioAssetPath in audioAssetPathSet)
        {
            if (!_audioClipSet.ContainsKey(audioAssetPath))
            {
                LoadAsset(audioAssetPath);
            }
        }
        foreach (string audioAssetPath in audioAssetPathSet)
        {
            SetSounds(target, audioAssetPath);
            PlaySound(target);
        }
    }

    public void Stop(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        if (audioSource.clip == null)
        {
            return;
        }
        if (!audioSource.isPlaying)
        {
            return;
        }
        audioSource.Stop();
    }

    public void Pause(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        if (audioSource.clip == null)
        {
            return;
        }
        if (!audioSource.isPlaying)
        {
            return;
        }
        audioSource.Pause();
    }

    public void UnPause(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        if (audioSource.clip == null)
        {
            return;
        }
        if (audioSource.isPlaying)
        {
            return;
        }
        audioSource.UnPause();
    }

    private void LoadAsset(string audioAssetPath)
    {
        _audioClipSet[audioAssetPath] = ResourceManager.Instance.LoadAsset<AudioClip>(audioAssetPath);
    }

    private void UnloadAsset(string audioAssetPath)
    {
        if (!_audioClipSet.ContainsKey(audioAssetPath))
        {
            return;
        }
        AudioClip audioClip = _audioClipSet[audioAssetPath];
        if (audioClip == null)
        {
            return;
        }
        Destroy(audioClip);
        _audioClipSet.Remove(audioAssetPath);
    }

    private void SetBGM(GameObject target, string bgmAssetPath)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            audioSource = target.AddComponent<AudioSource>();
        }
        if (!_audioClipSet.ContainsKey(bgmAssetPath))
        {
            return;
        }
        AudioClip audioClip = _audioClipSet[bgmAssetPath];
        if (audioClip == null)
        {
            return;
        }
        audioSource.outputAudioMixerGroup = _audioMixer.FindMatchingGroups(_audioMixerGroupBGMPath)[0];
        audioSource.clip = audioClip;
    }

    private void SetSounds(GameObject target, string soundAssetPath)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            audioSource = target.AddComponent<AudioSource>();
        }
        if (!_audioClipSet.ContainsKey(soundAssetPath))
        {
            return;
        }
        AudioClip audioClip = _audioClipSet[soundAssetPath];
        if (audioClip == null)
        {
            return;
        }
        audioSource.outputAudioMixerGroup = _audioMixer.FindMatchingGroups(_audioMixerGroupSoundsPath)[0];
        audioSource.clip = audioClip;
    }

    private void PlayBGM(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        if (audioSource.clip == null)
        {
            return;
        }
        if (audioSource.isPlaying)
        {
            return;
        }
        audioSource.playOnAwake = false;
        audioSource.loop = true;
        audioSource.Play();
    }

    private void PlaySound(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        if (audioSource.clip == null)
        {
            return;
        }
        audioSource.playOnAwake = false;
        audioSource.loop = false;
        audioSource.PlayOneShot(audioSource.clip);
    }

    private void UnsetAudio(GameObject target)
    {
        AudioSource audioSource = target.GetComponent<AudioSource>();
        if (audioSource == null)
        {
            return;
        }
        audioSource.Stop();
        audioSource.clip = null;
    }
}

代码说明

(一)实现 BGM 和音效的音量大小的全局控制。

(二)实现播放 BGM 和播放音效的功能。

(三)实现对音频生命周期的控制,包括播放、暂停、恢复和停止操作。

后记

由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。

posted @ 2024-04-30 15:25  珂霖  阅读(15)  评论(0编辑  收藏  举报