音效系統 1.個人思路 1.情景假設 一天,小明想聽歌。於是,他拿起手機,找到音樂播放軟體,選擇歌曲,按下播放鍵,聽到了想聽的歌 2.過程分析 1 小明想聽歌 聽歌的對象,歌曲信息接收者 2 打開音樂播放軟體 播放音樂的對象,音效源 3 選擇歌曲 選擇的數據,音效資源 3.實現思路 AudioLis ...
音效系統
音效系統
1.個人思路
1.情景假設
一天,小明想聽歌。於是,他拿起手機,找到音樂播放軟體,選擇歌曲,按下播放鍵,聽到了想聽的歌
2.過程分析
1 小明想聽歌 -> 聽歌的對象,歌曲信息接收者
2 打開音樂播放軟體 -> 播放音樂的對象,音效源
3 選擇歌曲 -> 選擇的數據,音效資源3.實現思路
AudioListener: 音效的監聽者
AudioSources:音頻控制器
AudioClip:音頻文件
2.代碼實現
2.1 簡易播放器
`using UnityEngine;
// 添加音效源
[RequireComponent(typeof(AudioSource))]
public class AudioManagerA : MonoBehaviour{
public AudioClip AudioClip;
private AudioSource _audioSource;
private void Start()
{
_audioSource = GetComponent<AudioSource>();
}
// 播放音效
public void PlayAudio(float volume = 1.0f, bool isLoop = false)
{
_audioSource.clip = AudioClip;
_audioSource.volume = volume;
_audioSource.loop = isLoop;
_audioSource.Play();
Debug.LogFormat("播放音效: {0}", AudioClip.name);
}
}`
`using UnityEngine;
public class TestA : MonoBehaviour {
public bool IsPlayAudio;
void Start () {
gameObject.AddComponent<AudioManagerA>();
// 選擇播放的音效
gameObject.GetComponent<AudioManagerA>().AudioClip = Resources.Load<AudioClip>("Audio/BackgroundMusic/BgMusic");
}
void Update () {
if (IsPlayAudio)
{
IsPlayAudio = false;
gameObject.GetComponent<AudioManagerA>().PlayAudio();
}
}
}`
2.2 如何方便的選擇音效文件
` using System;
using System.Collections.Generic;
using UnityEngine;
public interface IUploadAudio
{
// 載入音效資源
AudioClip GetAudioClip(string audioName);
}
[RequireComponent(typeof(AudioSource))]
public class AudioManagerB : MonoBehaviour, IUploadAudio {
// 保存已經載入過的音效
private Dictionary<string, AudioClip> _audioDict;
private AudioSource _audioSource;
private void Start()
{
_audioDict = new Dictionary<string, AudioClip>();
_audioSource = GetComponent<AudioSource>();
}
// 播放音效
public void PlayAudio(string audioName, float volume = 1.0f, bool isLoop = false)
{
if (!_audioDict.ContainsKey(audioName))
{
_audioDict.Add(audioName, GetAudioClip(audioName));
}
_audioSource.clip = _audioDict[audioName];
_audioSource.volume = volume;
_audioSource.loop = isLoop;
_audioSource.Play();
}
public AudioClip GetAudioClip(string audioName)
{
AudioClip audioClip = Resources.Load<AudioClip>(audioName);
if (audioClip == null)
{
throw new Exception("沒有找到相應的音效資源 請確認路徑:" + audioName);
}
return audioClip;
}
}`
`using UnityEngine;
public class TestB : MonoBehaviour {
public bool IsPlayAudio;
public string AudioName;
void Start()
{
AudioName = "Audio/BackgroundMusic/BgMusic";
gameObject.AddComponent<AudioManagerB>();
}
void Update()
{
if (IsPlayAudio)
{
IsPlayAudio = false;
gameObject.GetComponent<AudioManagerB>().PlayAudio(AudioName);
}
}
}`
2.2.1 使用一個音效路徑管理類
`public class AudioPath
{
public const string BACKGROUND_MUSIC = "Audio/BackgroundMusic/BgMusic";
public const string BACKGROUND_MUSIC_B = "Audio/BackgroundMusic/BgMusicB";
public const string BACKGROUND_MUSIC_C = "Audio/BackgroundMusic/BgMusicC";
public const string BACKGROUND_MUSIC_D = "Audio/BackgroundMusic/BgMusicD";
}`
2.2.2 使用枚舉組裝路徑
`public class AudioType {
public enum Dialogue
{
}
public enum ScreenOnClick
{
// 點擊正確
Correct,
// 點擊錯誤
Error,
}
public enum SpecialEffects
{
}
public enum BackgroundMusic
{
// 背景音樂
BgMusic,
}
public enum Other
{
}
}`
`using UnityEngine;
public class TestB : MonoBehaviour {
public bool IsPlayAudio;
void Start()
{
gameObject.AddComponent<AudioManagerB>();
}
void Update()
{
if (IsPlayAudio)
{
IsPlayAudio = false;
gameObject.GetComponent<AudioManagerB>().PlayAudio(AudioType.BackgroundMusic.BgMusic);
}
}
}`
`using System;
using System.Collections.Generic;
using UnityEngine;
public interface IUploadAudio
{
// 載入音效資源
AudioClip GetAudioClip(Enum audioName);
}
[RequireComponent(typeof(AudioSource))]
public class AudioManagerB : MonoBehaviour, IUploadAudio
{
// 保存已經載入過的音效
private Dictionary<Enum, AudioClip> _audioDict;
private AudioSource _audioSource;
private const string audioPath = "Audio/";
private void Start()
{
_audioDict = new Dictionary<Enum, AudioClip>();
_audioSource = GetComponent<AudioSource>();
}
// 播放音效
public void PlayAudio(Enum audioName, float volume = 1.0f, bool isLoop = false)
{
if (!_audioDict.ContainsKey(audioName))
{
_audioDict.Add(audioName, GetAudioClip(audioName));
}
_audioSource.clip = _audioDict[audioName];
_audioSource.volume = volume;
_audioSource.loop = isLoop;
_audioSource.Play();
}
public AudioClip GetAudioClip(Enum audioName)
{
string audioType = audioName.GetType().Name;
AudioClip audioClip = Resources.Load<AudioClip>(audioPath + audioType + "/" + audioName);
if (audioClip == null)
{
throw new Exception("沒有找到相應的音效資源 請確認路徑:" + audioName);
}
return audioClip;
}
}`
2.3 考慮多個播放源
2.3.1 介面設置
`public interface IUploadAudioClip
{
// 載入音效資源
AudioClip GetAudioClip(Enum audioName);
}
public interface IUploadAudioSource
{
// 載入音效播放源
AudioSource GetAudioSource(string audioSourceName);
}
public interface IPlayAudio
{
// 播放音效
void PlayAudio(Enum audioName, float volume, bool isLoop, string audioSourceName);
// 停止播放的音效
void StopAudio(string audioSourceName);
}`
2.3.2 播放源系統
`
public class UploadAudioSourceStrategy : IUploadAudioSource
{
// 播放的音頻源
private Dictionary<string, AudioSource> audioSourceDict;
// 音效管理器
private GameObject audioControl;
private static int count;
private readonly string currentAudioName;
public UploadAudioSourceStrategy()
{
audioSourceDict = new Dictionary<string, AudioSource>(3);
audioControl = new GameObject { name = "AudioModuleControl" };
Object.DontDestroyOnLoad(audioControl);
audioControl.AddComponent<AudioListener>();
}
public AudioSource GetAudioSource(string audioSourceName)
{
if(audioSourceName.Equals(string.Empty))
{
return GetCurrentAudioSource();
}
if (audioSourceDict.ContainsKey(audioSourceName))
{
return audioSourceDict[audioSourceName];
}
return GetCurrentAudioSource(audioSourceName);
}
private AudioSource GetCurrentAudioSource()
{
foreach (var source in audioSourceDict)
{
if (!source.Value.isPlaying)
{
return source.Value;
}
}
return GetCurrentAudioSource(currentAudioName + count++);
}
private AudioSource GetCurrentAudioSource(string audioSourceName)
{
audioSourceDict.Add(audioSourceName, audioControl.AddComponent<AudioSource>());
return audioSourceDict[audioSourceName];
}
}`
2.3.3 音效資源系統
`public class UploadAudioClipStrategy : IUploadAudioClip
{
// 音效路徑
private readonly string audioPath;
// 播放的音效
private Dictionary<Enum, AudioClip> audioClipDict;
public UploadAudioClipStrategy()
{
audioPath = "Audio/";
audioClipDict = new Dictionary<Enum, AudioClip>();
}
public AudioClip GetAudioClip(Enum audioName)
{
if (audioClipDict.ContainsKey(audioName))
{
return audioClipDict[audioName];
}
AudioClip clip = Resources.Load<AudioClip>(AudioClipPath(audioName));
audioClipDict.Add(audioName, clip);
return audioClipDict[audioName];
}
private string AudioClipPath(Enum audioName)
{
string audioType = audioName.GetType().Name;
return audioPath + audioType + "/" + audioName;
}
}
`
2.3.4 音效系統
`
public abstract class AudioManagerBase : IPlayAudio
{
public IUploadAudioSource UploadAudioSource { get; protected set; }
public IUploadAudioClip UploadAudioClip { get; protected set; }
protected AudioManagerBase() : this(new UploadAudioSourceStrategy(), new UploadAudioClipStrategy())
{
}
protected AudioManagerBase(IUploadAudioSource uploadAudioSource, IUploadAudioClip uploadAudioClip)
{
UploadAudioSource = uploadAudioSource;
UploadAudioClip = uploadAudioClip;
}
public void PlayAudio(Enum audioName, float volume, bool isLoop, string audioSourceName)
{
AudioClip clip = UploadAudioClip.GetAudioClip(audioName);
AudioSource audioSource = UploadAudioSource.GetAudioSource(audioSourceName);
audioSource.clip = clip;
audioSource.volume = volume;
audioSource.loop = isLoop;
audioSource.Play();
}
public void StopAudio(string audioSourceName)
{
AudioSource audioSource = UploadAudioSource.GetAudioSource(audioSourceName);
audioSource.loop = false;
audioSource.Stop();
}
}`
`
public class AudioSourceManager : AudioManagerBase {
public const string BgAudioName = "BgAudio";
#region 播放音樂的調用方式
public void PlayAudio(AudioType.Dialogue audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
{
base.PlayAudio(audioName, volume, isLoop, audioSourceName);
}
public void PlayAudio(AudioType.ScreenOnClick audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
{
base.PlayAudio(audioName, volume, isLoop, audioSourceName);
}
public void PlayAudio(AudioType.SpecialEffects audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
{
base.PlayAudio(audioName, volume, isLoop, audioSourceName);
}
public void PlayAudio(AudioType.Other audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
{
base.PlayAudio(audioName, volume, isLoop, audioSourceName);
}
public void PlayAudio(AudioType.BackgroundMusic audioName, string audioSourceName = BgAudioName, float volume = 1.0f, bool isLoop = true)
{
PlayAudio(audioName, volume, isLoop, audioSourceName);
}
#endregion
}
`
2.3.5 播放測試
`using UnityEngine;
public class TestC : MonoBehaviour {
private void Start()
{
AudioSourceManager audioSourceManager = new AudioSourceManager();
audioSourceManager.PlayAudio(AudioType.BackgroundMusic.BgMusic);
audioSourceManager.PlayAudio(AudioType.ScreenOnClick.Correct);
audioSourceManager.PlayAudio(AudioType.ScreenOnClick.Error);
}
}`
2.4 常用方法擴展
`public interface IUploadAudioSource
{
。。。
// 停止選擇的部分音效
void StopGroupAudio(Func<string, bool> stopGroupAudio);
}`
`public class UploadAudioSourceStrategy : IUploadAudioSource{
。。。
public void StopGroupAudio(Func<string, bool> stopGroupAudio)
{
foreach (var source in audioSourceDict)
{
if (stopGroupAudio(source.Key))
{
source.Value.loop = false;
source.Value.Stop();
}
}
}
}`
`public abstract class AudioManagerBase : IPlayAudio{
。。。
public void Reset(Func<string, bool> stopGroupAudio)
{
UploadAudioSource.StopGroupAudio(stopGroupAudio);
}
public float PlayAudioTime(Enum audioName)
{
if (UploadAudioClip.GetAudioClip(audioName) == null)
{
Debug.Log("Error: " + "The music file could not be found");
return 0.0f;
}
return UploadAudioClip.GetAudioClip(audioName).length;
}
}`
`public class AudioSourceManager : AudioManagerBase, ISingleton
{
。。。
private AudioSourceManager() { }
public const string BgAudioName = "BgAudio"; }`
`public class TestC : MonoBehaviour {
private void Start()
{
SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.BackgroundMusic.BgMusic);
SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.ScreenOnClick.Correct);
SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.ScreenOnClick.Error);
}
}`