欢迎加入Unity业内qq交流群:956187480



在项目里做音频管理的时候,我们往往是跟资源管理结合起来的,但是这里我们就单音频管理展开。其实音频管理无非就是对几种固定的音效类型进行加载,播放,暂停,调音等一系列操作。我们只需要把一些常规操作写出来满足大部分的需求即可,对于其他一些特殊功能的比如在线剪切片段,动态调整音素的就需要我们另外实现。

我们一般会把音频分为四类:以农场类项目为例

1.背景音乐:全局只有一个,不同的场景不同的时间不同的天气都会有不同的背景音乐,其主要作用是为了烘托氛围。所以大部分的背景音乐都是2d的且音量是所有音效中最低的,目的为不突兀不刺激为主。

// 播放背景音乐
public void PlayBackgroundMusic(AudioClip clip, bool isLoop = true, float speed = 1)
// 暂停播放背景音乐
public void PauseBackgroundMusic(bool isGradual = true)

2.人声配音:全局只有一个,经常会用在人物对话,npc讲话等人声场景下。当播放新的声音时会把当前的声音覆盖掉。

/// 播放单通道音效
public void PlaySingleSound(AudioClip clip, bool isLoop = false, float speed = 1)
/// 暂停播放单通道音效
public void PauseSingleSound(bool isGradual = true)

3.技能ui音效:全局可以多个,在触发ui的时候或者释放技能的时候我们的配音是可以多个可重叠的。

/// 播放多通道音效
public void PlayMultipleSound(AudioClip clip, bool isLoop = false, float speed = 1)
/// 停止播放指定的多通道音效
public void StopMultipleSound(AudioClip clip)

4.世界3d音效:全局可以多个,世界音效其实就是3d音,我们一般用在固定位置范围内的音效,通过设置触发距离听到音量不一样的空间声音,比如cf的敌人脚步声。

/// 播放世界音效
public void PlayWorldSound(GameObject attachTarget, AudioClip clip, bool isLoop = false, float speed = 1)
/// 暂停播放指定的世界音效
public void PauseWorldSound(GameObject attachTarget, bool isGradual = true)

源代码:

using DG.Tweening;
using System.Collections.Generic;
using UnityEngine;

public delegate void AudAction();
/// <summary>
/// 音频管理者
/// </summary>
[DisallowMultipleComponent]
public sealed class AudioManager : MonoBehaviour
{
/// <summary>
/// 是否静音初始值【请勿在代码中修改】
/// </summary>
public bool MuteDefault = false;
/// <summary>
/// 背景音乐优先级初始值【请勿在代码中修改】
/// </summary>
public int BackgroundPriorityDefault = 0;
/// <summary>
/// 单通道音效优先级初始值【请勿在代码中修改】
/// </summary>
public int SinglePriorityDefault = 10;
/// <summary>
/// 多通道音效优先级初始值【请勿在代码中修改】
/// </summary>
public int MultiplePriorityDefault = 20;
/// <summary>
/// 世界音效优先级初始值【请勿在代码中修改】
/// </summary>
public int WorldPriorityDefault = 30;
/// <summary>
/// 背景音乐音量初始值【请勿在代码中修改】
/// </summary>
public float BackgroundVolumeDefault = 0.6f;
/// <summary>
/// 单通道音效音量初始值【请勿在代码中修改】
/// </summary>
public float SingleVolumeDefault = 1;
/// <summary>
/// 多通道音效音量初始值【请勿在代码中修改】
/// </summary>
public float MultipleVolumeDefault = 1;
/// <summary>
/// 世界音效音量初始值【请勿在代码中修改】
/// </summary>
public float WorldVolumeDefault = 1;
/// <summary>
/// 单通道音效播放结束事件
/// </summary>
public event AudAction SingleSoundEndOfPlayEvent;

private AudioSource _backgroundAudio;
private AudioSource _singleAudio;
private List<AudioSource> _multipleAudios = new List<AudioSource>();
private Dictionary<GameObject, AudioSource> _worldAudios = new Dictionary<GameObject, AudioSource>();
private bool _singleSoundPlayDetector = false;
private bool _isMute = false;
private int _backgroundPriority = 0;
private int _singlePriority = 10;
private int _multiplePriority = 20;
private int _worldPriority = 30;
private float _backgroundVolume = 0.6f;
private float _singleVolume = 1;
private float _multipleVolume = 1;
private float _worldVolume = 1;

public void Awake()
{
_backgroundAudio = CreateAudioSource("BackgroundAudio", BackgroundPriorityDefault, BackgroundVolumeDefault, 1, 0);
_singleAudio = CreateAudioSource("SingleAudio", SinglePriorityDefault, SingleVolumeDefault, 1, 0);

Mute = MuteDefault;
BackgroundPriority = BackgroundPriorityDefault;
SinglePriority = SinglePriorityDefault;
MultiplePriority = MultiplePriorityDefault;
WorldPriority = WorldPriorityDefault;
BackgroundVolume = BackgroundVolumeDefault;
SingleVolume = SingleVolumeDefault;
MultipleVolume = MultipleVolumeDefault;
WorldVolume = WorldVolumeDefault;
}

public void Start()
{
StopBackgroundMusic();
StopSingleSound();
StopAllMultipleSound();
StopAllWorldSound();
}

public void Update()
{
if (_singleSoundPlayDetector)
{
if (!_singleAudio.isPlaying)
{
_singleSoundPlayDetector = false;
SingleSoundEndOfPlayEvent?.Invoke();
}
}
}

/// <summary>
/// 静音
/// </summary>
public bool Mute
{
get
{
return _isMute;
}
set
{
if (_isMute != value)
{
_isMute = value;
_backgroundAudio.mute = _isMute;
_singleAudio.mute = _isMute;
for (int i = 0; i < _multipleAudios.Count; i++)
{
_multipleAudios[i].mute = _isMute;
}
foreach (var audio in _worldAudios)
{
audio.Value.mute = _isMute;
}
}
}
}
/// <summary>
/// 背景音乐优先级
/// </summary>
public int BackgroundPriority
{
get
{
return _backgroundPriority;
}
set
{
if (_backgroundPriority != value)
{
_backgroundPriority = value;
_backgroundAudio.priority = _backgroundPriority;
}
}
}
/// <summary>
/// 单通道音效优先级
/// </summary>
public int SinglePriority
{
get
{
return _singlePriority;
}
set
{
if (_singlePriority != value)
{
_singlePriority = value;
_singleAudio.priority = _singlePriority;
}
}
}
/// <summary>
/// 多通道音效优先级
/// </summary>
public int MultiplePriority
{
get
{
return _multiplePriority;
}
set
{
if (_multiplePriority != value)
{
_multiplePriority = value;
for (int i = 0; i < _multipleAudios.Count; i++)
{
_multipleAudios[i].priority = _multiplePriority;
}
}
}
}
/// <summary>
/// 世界音效优先级
/// </summary>
public int WorldPriority
{
get
{
return _worldPriority;
}
set
{
if (_worldPriority != value)
{
_worldPriority = value;
foreach (var audio in _worldAudios)
{
audio.Value.priority = _worldPriority;
}
}
}
}
/// <summary>
/// 背景音乐音量
/// </summary>
public float BackgroundVolume
{
get
{
return _backgroundVolume;
}
set
{
if (!Mathf.Approximately(_backgroundVolume, value))
{
_backgroundVolume = value;
_backgroundAudio.volume = _backgroundVolume;
}
}
}
/// <summary>
/// 单通道音效音量
/// </summary>
public float SingleVolume
{
get
{
return _singleVolume;
}
set
{
if (!Mathf.Approximately(_singleVolume, value))
{
_singleVolume = value;
_singleAudio.volume = _singleVolume;
}
}
}
/// <summary>
/// 多通道音效音量
/// </summary>
public float MultipleVolume
{
get
{
return _multipleVolume;
}
set
{

if (!Mathf.Approximately(_multipleVolume, value))
{
_multipleVolume = value;
for (int i = 0; i < _multipleAudios.Count; i++)
{
_multipleAudios[i].volume = _multipleVolume;
}
}
}
}
/// <summary>
/// 世界音效音量
/// </summary>
public float WorldVolume
{
get
{
return _worldVolume;
}
set
{
if (!Mathf.Approximately(_worldVolume, value))
{
_worldVolume = value;
foreach (var audio in _worldAudios)
{
audio.Value.volume = _worldVolume;
}
}
}
}

/// <summary>
/// 播放背景音乐
/// </summary>
/// <param name="clip">音乐剪辑</param>
/// <param name="isLoop">是否循环</param>
/// <param name="speed">播放速度</param>
public void PlayBackgroundMusic(AudioClip clip, bool isLoop = true, float speed = 1)
{
if (_backgroundAudio.isPlaying)
{
_backgroundAudio.Stop();
}

_backgroundAudio.clip = clip;
_backgroundAudio.loop = isLoop;
_backgroundAudio.pitch = speed;
_backgroundAudio.Play();
}
/// <summary>
/// 暂停播放背景音乐
/// </summary>
/// <param name="isGradual">是否渐进式</param>
public void PauseBackgroundMusic(bool isGradual = true)
{
if (isGradual)
{
_backgroundAudio.DOFade(0, 2).OnComplete(() =>
{
_backgroundAudio.volume = BackgroundVolume;
_backgroundAudio.Pause();
});
}
else
{
_backgroundAudio.Pause();
}
}
/// <summary>
/// 恢复播放背景音乐
/// </summary>
/// <param name="isGradual">是否渐进式</param>
public void UnPauseBackgroundMusic(bool isGradual = true)
{
if (isGradual)
{
_backgroundAudio.UnPause();
_backgroundAudio.volume = 0;
_backgroundAudio.DOFade(BackgroundVolume, 2);
}
else
{
_backgroundAudio.UnPause();
}
}
/// <summary>
/// 停止播放背景音乐
/// </summary>
public void StopBackgroundMusic()
{
if (_backgroundAudio.isPlaying)
{
_backgroundAudio.Stop();
}
}

/// <summary>
/// 播放单通道音效
/// </summary>
/// <param name="clip">音乐剪辑</param>
/// <param name="isLoop">是否循环</param>
/// <param name="speed">播放速度</param>
public void PlaySingleSound(AudioClip clip, bool isLoop = false, float speed = 1)
{
if (_singleAudio.isPlaying)
{
_singleAudio.Stop();
}

_singleAudio.clip = clip;
_singleAudio.loop = isLoop;
_singleAudio.pitch = speed;
_singleAudio.Play();
_singleSoundPlayDetector = true;
}
/// <summary>
/// 暂停播放单通道音效
/// </summary>
/// <param name="isGradual">是否渐进式</param>
public void PauseSingleSound(bool isGradual = true)
{
if (isGradual)
{
_singleAudio.DOFade(0, 2).OnComplete(() =>
{
_singleAudio.volume = SingleVolume;
_singleAudio.Pause();
});
}
else
{
_singleAudio.Pause();
}
}
/// <summary>
/// 恢复播放单通道音效
/// </summary>
/// <param name="isGradual">是否渐进式</param>
public void UnPauseSingleSound(bool isGradual = true)
{
if (isGradual)
{
_singleAudio.UnPause();
_singleAudio.volume = 0;
_singleAudio.DOFade(SingleVolume, 2);
}
else
{
_singleAudio.UnPause();
}
}
/// <summary>
/// 停止播放单通道音效
/// </summary>
public void StopSingleSound()
{
if (_singleAudio.isPlaying)
{
_singleAudio.Stop();
}
}

/// <summary>
/// 播放多通道音效
/// </summary>
/// <param name="clip">音乐剪辑</param>
/// <param name="isLoop">是否循环</param>
/// <param name="speed">播放速度</param>
public void PlayMultipleSound(AudioClip clip, bool isLoop = false, float speed = 1)
{
AudioSource audio = ExtractIdleMultipleAudioSource();
audio.clip = clip;
audio.loop = isLoop;
audio.pitch = speed;
audio.Play();
}
/// <summary>
/// 停止播放指定的多通道音效
/// </summary>
/// <param name="clip">音乐剪辑</param>
public void StopMultipleSound(AudioClip clip)
{
for (int i = 0; i < _multipleAudios.Count; i++)
{
if (_multipleAudios[i].isPlaying)
{
if (_multipleAudios[i].clip == clip)
{
_multipleAudios[i].Stop();
}
}
}
}
/// <summary>
/// 停止播放所有多通道音效
/// </summary>
public void StopAllMultipleSound()
{
for (int i = 0; i < _multipleAudios.Count; i++)
{
if (_multipleAudios[i].isPlaying)
{
_multipleAudios[i].Stop();
}
}
}
/// <summary>
/// 销毁所有闲置中的多通道音效的音源
/// </summary>
public void ClearIdleMultipleAudioSource()
{
for (int i = 0; i < _multipleAudios.Count; i++)
{
if (!_multipleAudios[i].isPlaying)
{
AudioSource audio = _multipleAudios[i];
_multipleAudios.RemoveAt(i);
i -= 1;
Destroy(audio.gameObject);
}
}
}

/// <summary>
/// 播放世界音效
/// </summary>
/// <param name="attachTarget">附加目标</param>
/// <param name="clip">音乐剪辑</param>
/// <param name="isLoop">是否循环</param>
/// <param name="speed">播放速度</param>
public void PlayWorldSound(GameObject attachTarget, AudioClip clip, bool isLoop = false, float speed = 1)
{
if (_worldAudios.ContainsKey(attachTarget))
{
AudioSource audio = _worldAudios[attachTarget];
if (audio.isPlaying)
{
audio.Stop();
}
audio.clip = clip;
audio.loop = isLoop;
audio.pitch = speed;
audio.Play();
}
else
{
AudioSource audio = AttachAudioSource(attachTarget, WorldPriority, WorldVolume, 1, 1);
_worldAudios.Add(attachTarget, audio);
audio.clip = clip;
audio.loop = isLoop;
audio.pitch = speed;
audio.Play();
}
}
/// <summary>
/// 暂停播放指定的世界音效
/// </summary>
/// <param name="attachTarget">附加目标</param>
/// <param name="isGradual">是否渐进式</param>
public void PauseWorldSound(GameObject attachTarget, bool isGradual = true)
{
if (_worldAudios.ContainsKey(attachTarget))
{
AudioSource audio = _worldAudios[attachTarget];
if (isGradual)
{
audio.DOFade(0, 2).OnComplete(() =>
{
audio.volume = WorldVolume;
audio.Pause();
});
}
else
{
audio.Pause();
}
}
}
/// <summary>
/// 恢复播放指定的世界音效
/// </summary>
/// <param name="attachTarget">附加目标</param>
/// <param name="isGradual">是否渐进式</param>
public void UnPauseWorldSound(GameObject attachTarget, bool isGradual = true)
{
if (_worldAudios.ContainsKey(attachTarget))
{
AudioSource audio = _worldAudios[attachTarget];
if (isGradual)
{
audio.UnPause();
audio.volume = 0;
audio.DOFade(WorldVolume, 2);
}
else
{
audio.UnPause();
}
}
}
/// <summary>
/// 停止播放所有的世界音效
/// </summary>
public void StopAllWorldSound()
{
foreach (var audio in _worldAudios)
{
if (audio.Value.isPlaying)
{
audio.Value.Stop();
}
}
}
/// <summary>
/// 销毁所有闲置中的世界音效的音源
/// </summary>
public void ClearIdleWorldAudioSource()
{
HashSet<GameObject> removeSet = new HashSet<GameObject>();
foreach (var audio in _worldAudios)
{
if (!audio.Value.isPlaying)
{
removeSet.Add(audio.Key);
Destroy(audio.Value);
}
}
foreach (var item in removeSet)
{
_worldAudios.Remove(item);
}
}

//创建一个音源
private AudioSource CreateAudioSource(string name, int priority, float volume, float speed, float spatialBlend)
{
GameObject audioObj = new GameObject(name);
audioObj.transform.SetParent(transform);
audioObj.transform.localPosition = Vector3.zero;
audioObj.transform.localRotation = Quaternion.identity;
audioObj.transform.localScale = Vector3.one;
AudioSource audio = audioObj.AddComponent<AudioSource>();
audio.playOnAwake = false;
audio.priority = priority;
audio.volume = volume;
audio.pitch = speed;
audio.spatialBlend = spatialBlend;
audio.mute = _isMute;
return audio;
}
//附加一个音源
private AudioSource AttachAudioSource(GameObject target, int priority, float volume, float speed, float spatialBlend)
{
AudioSource audio = target.AddComponent<AudioSource>();
audio.playOnAwake = false;
audio.priority = priority;
audio.volume = volume;
audio.pitch = speed;
audio.spatialBlend = spatialBlend;
audio.mute = _isMute;
return audio;
}
//提取闲置中的多通道音源
private AudioSource ExtractIdleMultipleAudioSource()
{
for (int i = 0; i < _multipleAudios.Count; i++)
{
if (!_multipleAudios[i].isPlaying)
{
return _multipleAudios[i];
}
}

AudioSource audio = CreateAudioSource("MultipleAudio", MultiplePriority, MultipleVolume, 1, 0);
_multipleAudios.Add(audio);
return audio;
}
}

欢迎加入Unity业内qq交流群:956187480