在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");
还有开关设置,音量设置,可以根据需要自行存储在本地。