在Unity中使用音频管理
有什么不明白的地方,扫描右方二维码加我微信交流。
CocosCreator的音频管理相对容易一些,可以使用组件播放,也可以传入音频的路径使用cc.audioEngine播放。而且还自带暂停和继续播放所有音频的接口,封装起来相对容易一些。
Unity就不行了,必须要使用组件才能播放音频。亲测,一个音频片段可以同时被多个播放器播放,但一个播放器在当前只能播放一个音频。如果播放器播放的音频还没有停止,又立即播放另一个音频,则会打断之前的音频而播放新的音频。
我们的需求:调用播放音频方法时立即播放,且各个播放器之间互不影响。
主要使用AudioSource和AudioClip组件。
音频管理设计的主要思想:
- 免去在Unity Editor中手动创建播放器,并拖动音频片段到播放器上,完全由代码控制(把音频文件放在Resources文件夹中,这样就能用Resources.Load动态加载);
- 不需要在Unity Editor中把代码文件绑定到gameObject上;
- 缓存多个AudioSource(可以使用对象池缓存),缓存常用的AudioClip(使用Dictionary缓存);
- 当需要播放音频时,从AudioSource的缓存池中取出一个播放器audioSource,再从AudioClip缓存中取出播放片段audioClip,使用取出的播放器audioSource播放音频audioClip;
- 当播放器audioSource播放完成后,播放器audioSource回收到对象池中,等待下次被使用;
- 限制播放器无限制增加,根据游戏使用音频情况来确定播放器缓存的最大数量(遵循长时间内不频繁创建销毁播放器的原则,这样既能保证当前缓存的播放器不会占用太大内存,也能免去创建和销毁播放器带来的性能消耗);
- 背景音乐播放器独立出来,和音效互不干扰;
- 目前只支持播放一个背景音乐,可以切换,但同一时间,只能有一个背景音乐。
下面上代码(可直接使用):
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Object = UnityEngine.Object; public static class SoundManager { private static GameObject _soundManagerGameObject; 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() { //空闲播放器列表 _unusedAudioSources = new List<AudioSource>(); //正在使用播放器列表 _usedAudioSources = new List<AudioSource>(); //音频片段表 _audioClips = new Dictionary<string, AudioClip>(); //添加音频播放组件 _soundManagerGameObject = new GameObject("SoundManager"); _soundManagerGameObject.AddComponent<SoundManagerComponent>(); } //播放器回收 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 = _soundManagerGameObject.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) { if (_musicAudioSource == null) { _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(); _soundManagerGameObject.GetComponent<SoundManagerComponent>().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; } }
public class SoundManagerComponent : MonoBehaviour { void Start() { DontDestroyOnLoad(gameObject); } }
调用代码:
//初始化 ManagerAudio.InitData(); //bg是放在Resources文件夹下的音频文件 ManagerAudio.PlayMusic("bg");
还有开关设置,音量设置,可以根据需要自行存储在本地。