CocosCreator的音频管理相对容易一些,可以使用组件播放,也可以传入音频的路径使用cc.audioEngine播放。而且还自带暂停和继续播放所有音频的接口,封装起来相对容易一些。

Unity就不行了,必须要使用组件才能播放音频。亲测,一个音频片段可以同时被多个播放器播放,但一个播放器在当前只能播放一个音频。如果播放器播放的音频还没有停止,又立即播放另一个音频,则会打断之前的音频而播放新的音频。

我们要做到调用播放音频时立即播放,各个播放器之间互不影响。

主要使用AudioSource和AudioClip组件。

音频管理设计的主要思想:

  1. 免去在Unity Editor中手动创建播放器,并拖动音频片段到播放器上,完全由代码控制(把音频文件放在Resources文件夹中,这样就能用Resources.Load动态加载);
  2. 不需要在Unity Editor中把代码文件绑定到gameObject上,不需要继承MonoBehaviour;
  3. 缓存多个AudioSource(可以使用对象池缓存),缓存常用的AudioClip(使用Dictionary缓存);
  4. 当需要播放音频时,从AudioSource的缓存池中取出一个播放器audioSource,再从AudioClip缓存中取出播放片段audioClip,使用取出的播放器audioSource播放音频audioClip;
  5. 当播放器audioSource播放完成后,播放器audioSource回收到对象池中,等待下次被使用;
  6. 限制播放器无限制增加,根据游戏使用音频情况来确定播放器缓存的最大数量(遵循长时间内不频繁创建销毁播放器的原则,这样既能保证当前缓存的播放器不会占用太大内存,也能免去创建和销毁播放器带来的性能消耗);
  7. 背景音乐播放器独立出来,和音效互不干扰。

下面上代码(可直接使用):

using System;
using System.Collections;
using System.Collections.Generic;
using Models;
using UnityEngine;
using Object = UnityEngine.Object;

public static class ManagerAudio
{
    private static GameObject _audioGameObject;
    
    private static string _musicEnabled = "on";
    private static float _musicVolume = 1.0f;
    private static string _soundEnabled = "on";
    private static float _soundVolume = 1.0f;

    private static AudioSource _musicAudioSource;
    private static List<AudioSource> _unusedAudioSources;
    private static List<AudioSource> _usedAudioSources;
    private static Dictionary<string, AudioClip> _audioClips;
    private const int MaxCount = 7;

    public static void InitData(GameObject rootNode)
    {
        //空闲播放器列表
        _unusedAudioSources = new List<AudioSource>();
        //正在使用播放器列表
        _usedAudioSources = new List<AudioSource>();
        //音频片段表
        _audioClips = new Dictionary<string, AudioClip>();
        
        //设置播放器组件要添加到的gameObject
        _audioGameObject = rootNode;
    }

    //播放器回收
    private static void UsedToUnused(AudioSource audioSource)
    {
        if (audioSource != null)
        {
            if (_usedAudioSources.Contains(audioSource))
            {
                _usedAudioSources.Remove(audioSource);
            }

            if (!_unusedAudioSources.Contains(audioSource))
            {
                if (_unusedAudioSources.Count >= MaxCount)
                {
                    Object.Destroy(audioSource);
                }
                else
                {
                    _unusedAudioSources.Add(audioSource);
                }
            }
        }
    }

    //取出播放器
    private static AudioSource UnusedToUsed()
    {
        AudioSource audioSource;
        if (_unusedAudioSources.Count > 0)
        {
            audioSource = _unusedAudioSources[0];
            _unusedAudioSources.RemoveAt(0);
        }
        else
        {
            audioSource = _audioGameObject.AddComponent<AudioSource>();
        }
        _usedAudioSources.Add(audioSource);
        return audioSource;
    }

    //等待播放器播放完成
    private static IEnumerator WaitPlayEnd(AudioSource audioSource, Action action = null)
    {
        yield return new WaitUntil(() => !audioSource.isPlaying);
        UsedToUnused(audioSource);
        action?.Invoke();
    }

    //播放背景音乐
    public static void PlayMusic(string bgmPath, float volume = 0.0f)
    {
        _musicAudioSource = UnusedToUsed();
        _musicAudioSource.clip = Resources.Load<AudioClip>(bgmPath);
        _musicAudioSource.playOnAwake = false;
        _musicAudioSource.loop = true;
        _musicAudioSource.volume = volume > 0.0f ? volume : _musicVolume;
        _musicAudioSource.Play();

        if (!GetMusicEnabled())
        {
            _musicAudioSource.mute = true;
            _musicAudioSource.Pause();
        }
    }

    //播放音效
    public static void PlaySound(string soundPath, float volume = 0.0f)
    {
        if (!GetSoundEnabled()) return;
        var audioSource = UnusedToUsed();

        AudioClip audioClip;
        if (_audioClips.ContainsKey(soundPath))
        {
            audioClip = _audioClips[soundPath];
        }
        else
        {
            audioClip = Resources.Load<AudioClip>(soundPath);
            _audioClips.Add(soundPath, audioClip);
        }

        audioSource.clip = audioClip;
        audioSource.playOnAwake = false;
        audioSource.loop = false;
        audioSource.volume = volume > 0.0f? volume: _soundVolume;
        audioSource.Play();
        Constant.GamePlayScript.StartCoroutine(WaitPlayEnd(audioSource));
    }

    //暂停背景音乐
    public static void PauseBgm()
    {
        if (_musicAudioSource != null && _musicAudioSource.isPlaying)
        {
            _musicAudioSource.Pause();
        }
    }

    //继续背景音乐
    public static void ResumeBgm()
    {
        if (_musicAudioSource != null && !_musicAudioSource.isPlaying)
        {
            _musicAudioSource.Play();
        }
    }

    public static void SetMusicOn()
    {
        _musicEnabled = "on";

        if (_musicAudioSource != null)
        {
            _musicAudioSource.mute = false;
            _musicAudioSource.Play();
        }
    }

    public static void SetMusicOff()
    {
        _musicEnabled = "off";
        
        if (_musicAudioSource != null)
        {
            _musicAudioSource.mute = true;
            _musicAudioSource.Pause();
        }
    }

    private static bool GetMusicEnabled()
    {
        return _musicEnabled == "on";
    }

    public static void SetSoundOn()
    {
        _soundEnabled = "on";
    }

    public static void SetSoundOff()
    {
        _soundEnabled = "off";
    }

    private static bool GetSoundEnabled()
    {
        return _soundEnabled == "on";
    }
    
    public static void SetMusicVolume(float volume)
    {
        _musicVolume = volume;
        if (_musicAudioSource != null && _musicAudioSource.isPlaying)
        {
            _musicAudioSource.volume = _musicVolume;
        }
    }

    public static void SetSoundVolume(float volume)
    {
        _soundVolume = volume;
    }
}

调用代码:

//audioGameObject是音频组件要添加到的gameObject,要保证这个gameObject在游戏中不会被销毁
ManagerAudio.InitData(audioGameObject);
//bg是放在Resources文件夹下的音频文件
ManagerAudio.PlayMusic("bg");

还有开关设置,音量设置,可以根据需要自行存储在本地。

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注