?前言
本文將會(huì)介紹如何使用audiomixer實(shí)現(xiàn)全局音量控制,并且會(huì)介紹如何實(shí)現(xiàn)游戲內(nèi)的含靜音功能的音量設(shè)置界面。
本人也是個(gè)初學(xué)者,在看過一些關(guān)于音量管理的教程后,發(fā)現(xiàn)使用audiomixer實(shí)現(xiàn)全局音量控制可能是最方便、功能最完備、強(qiáng)大的,因此在這里分享一下自己的實(shí)現(xiàn)方法。如果有錯(cuò)誤,還請(qǐng)指出捏
基礎(chǔ)
音效成功播放需要兩個(gè)先決條件:音頻源 (Audio Source) 和 音頻監(jiān)聽器 (Audio Listener)。
音頻源 (Audio Source)?在場(chǎng)景中播放音頻,而音頻監(jiān)聽器 (Audio Listener)?充當(dāng)類似于麥克風(fēng)的設(shè)備。它接收來自場(chǎng)景中任何給定音頻源的輸入,并通過計(jì)算機(jī)揚(yáng)聲器播放聲音。
AudioListener和AudioSource
?其中,Audio Listener 會(huì)在相機(jī)創(chuàng)建時(shí)自動(dòng)創(chuàng)建,當(dāng)同一場(chǎng)景中的Audio Listener數(shù)量大于1時(shí),unity編輯器會(huì)報(bào)錯(cuò)?
而混音器 (Audio Mixer) 允許混合各種音頻源,對(duì)音頻源應(yīng)用效果。在音頻源腳本(Audio Source)的Output掛載AudioMixer的Group Controller文件后,這個(gè)音頻源就會(huì)放出應(yīng)用了AudioMixer效果的音頻?;诖?,通過使用代碼對(duì)AudioMixer的音量進(jìn)行動(dòng)態(tài)調(diào)整,我們就可以實(shí)現(xiàn)游戲內(nèi)動(dòng)態(tài)調(diào)整這一個(gè)音頻源的音量,進(jìn)而調(diào)整全局音量了。
邏輯:
游戲中的音頻大致可分為 音效(Sound) 和音樂(Music)兩種,因此我們這里就只實(shí)現(xiàn)對(duì)音效和音樂的設(shè)置,同時(shí)實(shí)現(xiàn)對(duì)主音量(Master)的設(shè)置
邏輯關(guān)系
?文章來源地址http://www.zghlxwxcb.cn/news/detail-479429.html
?AudioMixer制作
1.create->AudioMixer
?2.打開AudioMixer
這個(gè)NewAudioMixer就是新建的AudioMixer
?3.點(diǎn)擊Group的加號(hào)創(chuàng)建Music、Sound,并設(shè)置好層級(jí)關(guān)系
需要拖動(dòng),將三個(gè)group的層級(jí)關(guān)系設(shè)置為如圖所示
?4.在每個(gè)group的inspector中右鍵Volume,并將volume屬性暴露出去
5.如圖所示,重命名暴露出去的volume屬性
至此,AudioMixer就基本完成了。將AudioMixer文件夾下的Audio Mixer Group Controller文件拖動(dòng)到AudioSource的Output中,這個(gè)AudioSource放出的音頻就都將會(huì)應(yīng)用對(duì)應(yīng)Group的效果。
下面,我們就可以通過動(dòng)態(tài)設(shè)置剛才暴露出的volume屬性來實(shí)現(xiàn)音量設(shè)置了。開始愉快的寫代碼吧~
?文章來源:http://www.zghlxwxcb.cn/news/detail-479429.html
音量設(shè)置面板實(shí)現(xiàn)
在這里,我簡單地假設(shè)開發(fā)情形如下:有兩個(gè)場(chǎng)景,每個(gè)場(chǎng)景播放不同的背景音樂。那么,就只需要在兩個(gè)場(chǎng)景中創(chuàng)建兩個(gè)搭載了AudioSource,并循環(huán)播放bgm的空物體,即可實(shí)現(xiàn)播放背景音樂的需求
如圖所示
?而音效的播放,則是在所有場(chǎng)景中都會(huì)頻繁地使用到,并且播放的音效各不相同,因此需要?jiǎng)?chuàng)建一個(gè)用于播放音效的持續(xù)單例腳本,使其在場(chǎng)景切換時(shí)不被摧毀,并且便于其他腳本調(diào)用播放音效的腳本,滿足整個(gè)游戲的音效播放需求。
至于音量設(shè)置,由常理可知音量是全局均可設(shè)置的,因此也使用持續(xù)單例模式開發(fā),并且用滑動(dòng)條(sliider)來調(diào)節(jié)音量。
同時(shí):我們需要實(shí)現(xiàn)音量設(shè)置面板的如下功能:
1.靜音按鈕
2.取消靜音時(shí)回調(diào)滑動(dòng)條到未靜音時(shí)的值
那么,我們將這一個(gè)功能的實(shí)現(xiàn)分為兩個(gè)部分:持續(xù)單例AudioManager,以及一個(gè)繼承了monobehavior的腳本,用于控制其所處場(chǎng)景的音量ui。
?
AudioManager腳本
(我偷懶,就把播放音效功能和AudioManager腳本寫到一起了,雖然這樣不會(huì)有什么大問題,但二者終究不是同一個(gè)功能,可能會(huì)導(dǎo)致代碼比較混亂)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Audio;
//使用單例模式開發(fā),繼承單例父類,使其在場(chǎng)景切換時(shí)不銷毀
//同時(shí)包括音量設(shè)置功能和播放音效功能
public class AudioManager : PersistentSingleton<AudioManager>
{
[SerializeField] AudioMixer audioMixer;
//改變音調(diào)
const float pitchMin = 0.9f;
const float pitchMax = 1.1f;
//用于判斷靜音與否
private bool IsMuteMaster = false;
private bool IsMuteMusic = false;
private bool IsMuteSound = false;
//用于儲(chǔ)存靜音前的音量
private float LastMaster;
private float LastMusic;
private float LastSound;
//音量設(shè)置
//Slider on click:調(diào)節(jié)音量,若靜音則取消靜音
public void MasterSldOnClick(GameObject image, Slider slider)
{
audioMixer.SetFloat("vMaster", slider.value);
if (IsMuteMaster == false) return;
else
{
image.SetActive(false);
IsMuteMaster = false;
}
}
public void MusicSldOnClick(GameObject image, Slider slider)
{
audioMixer.SetFloat("vMusic", slider.value);
if (IsMuteMusic == false) return;
else
{
image.SetActive(false);
IsMuteMusic = false;
}
}
public void SoundSldOnClick(GameObject image, Slider slider)
{
audioMixer.SetFloat("vSound", slider.value);
if (IsMuteSound == false) return;
else
{
image.SetActive(false);
IsMuteSound = false;
};
}
//Button on click:若靜音則取消靜音并回調(diào)音量;若未靜音則靜音并儲(chǔ)存音量
public void MasterBtnOnClick(GameObject image, Slider Master)
{
if (IsMuteMaster)
{
image.SetActive(false);
IsMuteMaster = false;
Master.value = LastMaster;
}
else
{
image.SetActive(true);
LastMaster = Master.value;
Master.value = Master.minValue;
IsMuteMaster = true;
}
}
public void SoundBtnOnClick(GameObject image, Slider Sound)
{
if (IsMuteSound)
{
image.SetActive(false);
IsMuteSound = false;
Sound.value = Instance.LastSound;
}
else
{
image.SetActive(true);
LastSound = Sound.value;
Sound.value = Sound.minValue;
IsMuteSound = true;
}
}
public void MusicBtnOnClick(GameObject image, Slider Music)
{
if (IsMuteMusic)
{
image.SetActive(false);
IsMuteMusic = false;
Music.value = LastMusic;
}
else
{
image.SetActive(true);
LastMusic = Music.value;
Music.value = Music.minValue;
IsMuteMusic = true;
}
}
[SerializeField] AudioSource SoundPlayer;
//播放音效
public void PlaySound(AudioClip audioClip)
{
SoundPlayer.pitch = 1;
SoundPlayer.PlayOneShot(audioClip);
}
// 改變音調(diào),主要用于重復(fù)播放的音效
public void PlayRandomSound(AudioClip audioClip)
{
SoundPlayer.pitch = Random.Range(pitchMin , pitchMax );
SoundPlayer.PlayOneShot(audioClip);
}
public void PlayRandomSound(AudioClip[] audioClip)
{
PlayRandomSound(audioClip[Random.Range(0, audioClip.Length)]);
}
}
其中 ,PersistentSingleton為持續(xù)泛型單例父類,使腳本掛載的物體不隨場(chǎng)景改變而銷毀,并且使其他腳本更容易調(diào)用本腳本內(nèi)容。代碼見下,詳情可見unity單例,實(shí)現(xiàn)全局保存/跨場(chǎng)景傳輸數(shù)據(jù)
using UnityEngine;
public class PersistentSingleton<T> : MonoBehaviour where T : Component
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance == null)
{
Instance = this as T;
}
else if (Instance != this)
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
}
}
?寫完AudioManager腳本后,將AudioManager掛載到一個(gè)第一個(gè)場(chǎng)景的空物體上,以便生效(或是掛載到可以調(diào)節(jié)音量的第一個(gè)場(chǎng)景也行)。然后再將剛做好的AudioMixer和用于播放音效的AudioSource拖進(jìn)腳本里面就行了~
AudioSource和AudioManager如上圖所示
在這種實(shí)現(xiàn)方式下,需要把AudioSource放在AudioManager下,防止跨場(chǎng)景銷毀。但這是基于只用這一個(gè)音源就可滿足整個(gè)游戲音效需求的大前提下的,可能會(huì)有更好的實(shí)現(xiàn)方法。
?
AudioManager是全局起作用的,只需要在調(diào)節(jié)滑動(dòng)條(slider)時(shí)調(diào)用三個(gè)SldOnClick函數(shù)/點(diǎn)擊按鈕時(shí)調(diào)用三個(gè)BtnOnClick函數(shù),即可以實(shí)現(xiàn)全局調(diào)節(jié)音量的功能。
不過值得注意的是,三個(gè)BtnOnClick函數(shù)中有一條命令:Sound.value = Instance.LastSound。這條命令不會(huì)導(dǎo)致bug,會(huì)正常觸發(fā)SldOnClick,因?yàn)镾ldOnClick的觸發(fā)條件實(shí)際上是On Value Change(所有slider都是),只要值變化就可以觸發(fā),而并非一定要click。
?
各場(chǎng)景音量設(shè)置界面,以及設(shè)置界面腳本
下面,我們需要為每個(gè)場(chǎng)景創(chuàng)建音量設(shè)置界面,這里只創(chuàng)建一個(gè)場(chǎng)景的,因?yàn)槠渌麍?chǎng)景也是一樣的,實(shí)際開發(fā)時(shí)復(fù)制粘貼就行。
1.滑動(dòng)條(slider)
slider組件比較復(fù)雜,雖然不難,但是創(chuàng)建一個(gè)功能完備的slider也不是一兩句就能說完的,這里時(shí)跳過,不懂的小伙伴可以去找些教程,先創(chuàng)建一個(gè)能用的滑動(dòng)條。
?
2.音量設(shè)置界面
按照上圖思路,繼續(xù)創(chuàng)建音效和音樂的設(shè)置界面。
?3.設(shè)置界面腳本
using UnityEngine;
using UnityEngine.UI;
public class TestScene : MonoBehaviour
{
[Header("-----音量設(shè)置條-----")]
[SerializeField] Slider Master;
[SerializeField] Slider Music;
[SerializeField] Slider Sound;
//SldOnClick:傳遞參數(shù)以觸發(fā)AudioManager的SldOnClick
public void MasterSldOnClick(GameObject image)
{
AudioManager.Instance.MasterSldOnClick(image, Master);
}
public void MusicSldOnClick(GameObject image)
{
AudioManager.Instance.MusicSldOnClick(image, Music);
}
public void SoundSldOnClick(GameObject image)
{
AudioManager.Instance.SoundSldOnClick(image, Sound);
}
//BtnOnClick:傳遞參數(shù)以觸發(fā)AudioManager的BtnOnClick
public void MasterBtnOnClick(GameObject image)
{
AudioManager.Instance.MasterBtnOnClick(image, Master);
}
public void SoundBtnOnClick(GameObject image)
{
AudioManager.Instance.SoundBtnOnClick(image, Sound);
}
public void MusicBtnOnClick(GameObject image)
{
AudioManager.Instance.MusicBtnOnClick(image, Music);
}
}
這個(gè)腳本實(shí)際上只是起到了傳遞參數(shù)的作用,這么做一方面時(shí)因?yàn)?,多個(gè)參數(shù)的函數(shù)不能掛載到button、slider等組件上,另一方面是因?yàn)椋?AudioManager是持續(xù)單例,在某些場(chǎng)景中不是初始存在,無法直接掛載到組件上,需要使用代碼動(dòng)態(tài)調(diào)用。
將這個(gè)腳本掛載到場(chǎng)景中(隨便哪都行),并將三個(gè)slider掛載到腳本上即可。
?3.配置按鍵與滑動(dòng)條
以Master按鍵和滑動(dòng)條為例:
將剛才設(shè)置好的腳本掛到button組件下,并選擇MasterBtnOnClick函數(shù),將按鍵的子物體image掛到這個(gè)函數(shù)下面
Sound、Music同上
同樣的,給Master的slider掛上?MasterSldOnClick函數(shù),同樣的把Master的叉號(hào)掛到函數(shù)下即可。
至此,整個(gè)音量設(shè)置界面就做完了
?
?
?
?
到了這里,關(guān)于unity全局音量管理/全局音量設(shè)置與音量設(shè)置界面(含靜音功能)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!