關于Unity中的聲音管理模塊(專題七)

聲音的要素

1: 音頻文件AudioClip
2: 音源AudioSource;
3: 耳朵AudioListener;//全局只能有一個
4: 2D/3D音頻;//2D只是簡單地播放聲音,3D可以根據距離衰減音量

怎樣聽到聲音:

創建一個節點,掛載AudioSource組件,AudioSource組件關聯AudioClip屬性,設置聲音是否一開始就加載播放play on awake,是否循環播放,2D還是3D

場景中有一個節點有AudioListener組件,掛載AudioListener組件的節點在掛載AudioSource組件節點的聲音范圍內。運行,可以聽到聲音。

?

?

音樂與音效管理

1: 游戲里面一般分為音樂與音效;
2: 音樂指的是游戲的背景音樂;
3: 音效是游戲中的較短的音樂,來配合游戲的動作等;
4: Unity游戲沒有音樂和音效之分,都是AudioSource + AudioClip;
5: 2D音效沒有衰減,所以與位置沒有關系;
6: 3D音效需要有聲音所在節點的位置;
7: 游戲需求需要音樂和音效分開設置,開啟和關閉;

?

?

sound_manager腳本

首先,聲音包括音樂和音效,我們分兩大塊來管理,音樂為一塊,音效為一塊,這個塊實際上Unity內部是不分的,但是我們來分,

用字典數據類型保存URL和音源AudioSource之間的對應關系,兩個表,一個是音樂的,一個是音效的。

有了這兩個表,這樣如果我們要禁止背景音樂就去遍歷音樂表,如果我們要禁止音效就去遍歷音效表。

播放一個音效,需要new一個物體,在這個物體上加音源AudioSource組件,關聯好音頻文件AudioClip,這樣就會播放出一個音效,

播放出來的音效會有分2D和3D,2D隨便放在哪里,3D需要管理,有一個位置,所以加一個播放3D音效的接口。

1: 全局唯一的sound_manager;
2: 在場景里面創建一個物體(做為聲音的根節點),而且設置這個物體場景切換也不會刪除;
3: 編寫接口播放背景音樂play_music;
4: 編寫接口播放背景音效play_effect; // 2D聲音
5: 音樂和音效內部實現都是一樣的, 只不過要把url分組管理, 音效為一組,音樂為一組;
6: 提供開關音效接口set_mute(),并將值寫入本地,下一次打開游戲的時候會讀取這個值,維持上一次的設置。
7: 提供開關背景音樂接口switch_music(),并將值寫入本地,下一次打開游戲的時候會讀取這個值,維持上一次的設置。
8: 添加一個play_effect接口在指定的坐標出訪一個聲音, 可以用于3D音效;
9: 添加一個接口停止掉背景音樂stop_music(url);
10: 添加一個接口刪除掉播放的背景音樂clear_music(url), clear_effect(url);
11: 聲音文件來自Resouce還是assetBundle,可以通過資源管理來封裝,目前從Resource里面加載;
12: 加一個腳本,每隔0.5秒掃描一次已經播放完的聲音組件,將它disable;

?

?

聲音管理實例

1.創建Unity項目工程和文件目錄,保存場景

2.在Resources文件夾下創建一個sounds文件夾,把背景音樂Login.mp3和音效Close.mp3(第70)放進去

3.為了統一管理游戲中的聲音,寫一個腳本sound_manager來管理

 打開sound_manager.cs,初始化sound_manager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class sound_manager {// (1) 聲音根節點的物體;// (2) 保證這個節點在場景切換的時候不會刪除,這樣就不用再初始化一次;// (3) 所有播放聲音的生源節點,都是在這個節點下static GameObject sound_play_object;//這個就是根節點// url --> AudioSource 映射, 區分音樂,音效static Dictionary<string, AudioSource> musics=null;//音樂表static Dictionary<string, AudioSource> effects = null;//音效表public static void init(){sound_play_object = new GameObject("sound_play_object");//初始化根節點GameObject.DontDestroyOnLoad(sound_play_object);//場景切換的時候不會刪除根節點//初始化音樂表和音效表musics = new Dictionary<string, AudioSource>();effects = new Dictionary<string, AudioSource>();}
}

?

4.創建一個空節點,下面掛載一個腳本game_scene來測試音樂和音效

 打開game_scene.cs,寫一個語句測試初始化

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class game_scene : MonoBehaviour {// Use this for initializationvoid Start () {sound_manager.init();//初始化音樂音效管理
    }// Update is called once per framevoid Update () {}
}

?

5.運行,初始化,節點如下

?

6.接下來開始寫背景音樂和音效的接口

 打開sound_manager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class sound_manager {// (1) 聲音根節點的物體;// (2) 保證這個節點在場景切換的時候不會刪除,這樣就不用再初始化一次;// (3) 所有播放聲音的生源節點,都是在這個節點下static GameObject sound_play_object;//這個就是根節點static bool is_music_mute = false;//存放當前全局背景音樂是否靜音的變量static bool is_effect_mute = false;//存放當前音效是否靜音的變量// url --> AudioSource 映射, 區分音樂,音效static Dictionary<string, AudioSource> musics=null;//音樂表static Dictionary<string, AudioSource> effects = null;//音效表//初始化public static void init(){sound_play_object = new GameObject("sound_play_object");//初始化根節點sound_play_object.AddComponent<sound_scan>();//把聲音檢測組件掛載到根節點下GameObject.DontDestroyOnLoad(sound_play_object);//場景切換的時候不會刪除根節點//初始化音樂表和音效表musics = new Dictionary<string, AudioSource>();effects = new Dictionary<string, AudioSource>();// 從本地來加載這個開關if (PlayerPrefs.HasKey("music_mute"))//判斷is_music_mute有沒有保存在本地
        {int value = PlayerPrefs.GetInt("music_mute");is_music_mute = (value == 1);//int轉換bool,如果value==1,返回true,否則就是false
        }// 從本地來加載這個開關if (PlayerPrefs.HasKey("effect_mute"))//判斷is_effect_mute有沒有保存在本地
        {int value = PlayerPrefs.GetInt("effect_mute");is_effect_mute = (value == 1);//int轉換bool,如果value==1,返回true,否則就是false
        }}//播放指定背景音樂的接口public static void play_music(string url, bool is_loop = true){AudioSource audio_source = null;if (musics.ContainsKey(url))//判斷是否已經在背景音樂表里面了
        {audio_source = musics[url];//是就直接賦值過去
        }else//不是就新建一個空節點,節點下再新建一個AudioSource組件
        {GameObject s = new GameObject(url);//創建一個空節點s.transform.parent = sound_play_object.transform;//加入節點到場景中
            audio_source = s.AddComponent<AudioSource>();//空節點添加組件AudioSourceAudioClip clip = Resources.Load<AudioClip>(url);//代碼加載一個AudioClip資源文件audio_source.clip = clip;//設置組件的clip屬性為clipaudio_source.loop = is_loop;//設置組件循環播放audio_source.playOnAwake = true;//再次喚醒時播放聲音audio_source.spatialBlend = 0.0f;//設置為2D聲音
musics.Add(url, audio_source);//加入到背景音樂字典中,下次就可以直接賦值了
        }audio_source.mute = is_music_mute;audio_source.enabled = true;audio_source.Play();//開始播放
    }//停止播放指定背景音樂的接口public static void stop_music(string url){AudioSource audio_source = null;if (!musics.ContainsKey(url))//判斷是否已經在背景音樂表里面了
        {return;//沒有這個背景音樂就直接返回
        }audio_source = musics[url];//有就把audio_source直接賦值過去audio_source.Stop();//停止播放
    }//停止播放所有背景音樂的接口public static void stop_all_music(){foreach (AudioSource s in musics.Values){s.Stop();}}//刪除指定背景音樂和它的節點public static void clear_music(string url){AudioSource audio_source = null;if (!musics.ContainsKey(url))//判斷是否已經在背景音樂表里面了
        {return;//沒有這個背景音樂就直接返回
        }audio_source = musics[url];//有就把audio_source直接賦值過去musics[url] = null;//指定audio_source組件清空GameObject.Destroy(audio_source.gameObject);//刪除掉掛載指定audio_source組件的節點
    }//切換背景音樂靜音開關public static void switch_music(){// 切換靜音和有聲音的狀態is_music_mute = !is_music_mute;//把當前是否靜音寫入本地int value = (is_music_mute) ? 1 : 0;//bool轉換intPlayerPrefs.SetInt("music_mute", value);// 遍歷所有背景音樂的AudioSource元素foreach (AudioSource s in musics.Values){s.mute = is_music_mute;//設置為當前的狀態
        }}//當我的界面的靜音按鈕要顯示的時候,到底是顯示關閉,還是開始狀態;public static bool music_is_off(){return is_music_mute;}//接下來開始是音效的接口//播放指定音效的接口public static void play_effect(string url, bool is_loop = false){AudioSource audio_source = null;if (effects.ContainsKey(url))//判斷是否已經在音效表里面了
        {audio_source = effects[url];//是就直接賦值過去
        }else//不是就新建一個空節點,節點下再新建一個AudioSource組件
        {GameObject s = new GameObject(url);//創建一個空節點s.transform.parent = sound_play_object.transform;//加入節點到場景中
audio_source = s.AddComponent<AudioSource>();//空節點添加組件AudioSourceAudioClip clip = Resources.Load<AudioClip>(url);//代碼加載一個AudioClip資源文件audio_source.clip = clip;//設置組件的clip屬性為clipaudio_source.loop = is_loop;//設置組件循環播放audio_source.playOnAwake = true;//再次喚醒時播放聲音audio_source.spatialBlend = 0.0f;//設置為2D聲音
effects.Add(url, audio_source);//加入到音效字典中,下次就可以直接賦值了
        }audio_source.mute = is_effect_mute;audio_source.enabled = true;audio_source.Play();//開始播放
    }//停止播放指定音效的接口public static void stop_effect(string url){AudioSource audio_source = null;if (!effects.ContainsKey(url))//判斷是否已經在音效表里面了
        {return;//沒有這個背景音樂就直接返回
        }audio_source = effects[url];//有就把audio_source直接賦值過去audio_source.Stop();//停止播放
    }//停止播放所有音效的接口public static void stop_all_effect(){foreach (AudioSource s in effects.Values){s.Stop();}}//刪除指定音效和它的節點public static void clear_effect(string url){AudioSource audio_source = null;if (!effects.ContainsKey(url))//判斷是否已經在音效表里面了
        {return;//沒有這個音效就直接返回
        }audio_source = effects[url];//有就把audio_source直接賦值過去effects[url] = null;//指定audio_source組件清空GameObject.Destroy(audio_source.gameObject);//刪除掉掛載指定audio_source組件的節點
    }//切換音效靜音開關public static void switch_effect(){// 切換靜音和有聲音的狀態is_effect_mute = !is_effect_mute;//把當前是否靜音寫入本地int value = (is_effect_mute) ? 1 : 0;//bool轉換intPlayerPrefs.SetInt("effect_mute", value);// 遍歷所有音效的AudioSource元素foreach (AudioSource s in effects.Values){s.mute = is_effect_mute;//設置為當前的狀態
        }}//當我的界面的靜音按鈕要顯示的時候,到底是顯示關閉,還是開始狀態;public static bool effect_is_off(){return is_effect_mute;}//播放3D的音效public static void play_effect3D(string url, Vector3 pos, bool is_loop = false){AudioSource audio_source = null;if (effects.ContainsKey(url)){audio_source = effects[url];}else{GameObject s = new GameObject(url);s.transform.parent = sound_play_object.transform;s.transform.position = pos;//3D音效的位置
audio_source = s.AddComponent<AudioSource>();AudioClip clip = Resources.Load<AudioClip>(url);audio_source.clip = clip;audio_source.loop = is_loop;audio_source.playOnAwake = true;audio_source.spatialBlend = 1.0f; // 3D音效
effects.Add(url, audio_source);}audio_source.mute = is_effect_mute;audio_source.enabled = true;audio_source.Play();}//優化策略接口public static void disable_over_audio(){//遍歷背景音樂表foreach(AudioSource s in musics.Values){if (!s.isPlaying)//判斷是否在播放
            {s.enabled = false;//不在播放就直接隱藏
            }}//遍歷音效表foreach (AudioSource s in effects.Values){if (!s.isPlaying)//判斷是否在播放
            {s.enabled = false;//不在播放就直接隱藏
            }}}}

?

7.在game_scene腳本里面寫測試語句,測試接口是否可以使用

 打開game_scene.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class game_scene : MonoBehaviour {// Use this for initializationvoid Start () {sound_manager.init();//初始化音樂音效管理//sound_manager.play_music("sounds/Login");//播放背景音樂//this.InvokeRepeating("test_music_mute", 1, 3);
sound_manager.play_effect("sounds/Close");//播放音效if (sound_manager.effect_is_off())//如果當前是靜音,就切換成有聲音的狀態
        {sound_manager.switch_effect();}this.InvokeRepeating("again", 3, 3);//每隔3秒調用一次//this.InvokeRepeating("test_effect_mute", 1, 3);
    }//背景音樂靜音切換測試函數void test_music_mute(){Debug.Log("test_music_mute");sound_manager.switch_music();}//音效靜音切換測試函數void test_effect_mute(){Debug.Log("test_effect_mute");sound_manager.switch_effect();}//隱藏AudioSource組件優化測試函數void again(){sound_manager.play_effect("sounds/Close");}// Update is called once per framevoid Update () {}
}

?

8.還有一個問題就是,在某個聲音播放完成的時候,可以隱藏AudioSource組件,這樣就不會去調用組件的相關接口,游戲性能就能有所提升,這個接口在第6步已經寫好了,測試語句也在第7步顯現出來了,現在就寫一個掃描的腳本

 可以創建一個腳本sound_scan來檢測哪些聲音已經播放完成,播完的節點就把它的AudioSource組件隱藏,這個腳本0.5s啟動一次去檢測聲音節點。  

 打開sound_scan.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class sound_scan : MonoBehaviour {// Use this for initializationvoid Start () {//固定一個節奏去掃描,每隔0.5s掃描一次this.InvokeRepeating("scan",0, 0.5f);}// Update is called once per framevoid Update () {}//定時器函數void scan(){sound_manager.disable_over_audio();//調用隱藏AudioSource組件接口
    }
}

9.運行時的節點

播放背景音樂時

?

播放音效時

?

?

?

注意:

Unity代碼加載資源文件的時候是沒有文件后綴名的,看到什么名字就是什么名字

轉載于:https://www.cnblogs.com/HangZhe/p/7326308.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252145.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252145.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252145.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

重啟唯一的窗體實例,以及調用系統重啟函數失敗解決辦法

1、修改Program.cs內的程序啟動函數 static class Program{public static System.Threading.Mutex Instance;/// <summary>/// 應用程序的主入口點。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTe…

ThreadLocal可能引起的內存泄露

threadlocal里面使用了一個存在弱引用的map,當釋放掉threadlocal的強引用以后,map里面的value卻沒有被回收.而這塊value永遠不會被訪問到了. 所以存在著內存泄露. 最好的做法是將調用threadlocal的remove方法. 在threadlocal的生命周期中,都存在這些引用. 看下圖: 實線代表強引…

codevs 1576 最長嚴格上升子序列

題目鏈接&#xff1a;http://codevs.cn/problem/1576/題目描述 Description給一個數組a1, a2 ... an&#xff0c;找到最長的上升降子序列ab1<ab2< .. <abk&#xff0c;其中b1<b2<..bk。 輸出長度即可。 輸入描述 Input Description第一行&#xff0c;一個整數N。…

nginx服務器開啟緩存、反向代理

一、反向代理配置 1、反向代理服務器配置如下 反向代理就是需要這一行proxy_pass來完成。當我們要訪問后端web服務器的時候&#xff0c;我們只需要訪問代理服務器就可以了&#xff0c;此時代理服務器就充當后端web服務器的角色。proxy_pass依賴的模塊是&#xff1a; 至于后兩行…

Halcon:區域特征:select_shape(Regions : SelectedRegions : Features, Operation, Min, Max : )

Region特征一覽&#xff1a; 特征 英 譯 備注 area Area of the object 對象的面積 row Row index of the center 中心點的行坐標 column Column index of the center 中心點的列坐標 width Width of the region 區域的寬度 height Height of the…

Web應用主動偵測工具Skipfish

Web應用主動偵測工具SkipfishSkipfish是Kali Linux附帶的一個主動Web應用偵測工具。該工具會首先盡可能獲取所有網站路徑&#xff0c;進行訪問&#xff0c;然后根據返回的內容&#xff0c;檢測是否存在漏洞。該工具采用字典爆破和網頁爬行兩種方式獲取網站。一旦獲取網頁內容&a…

7步讓你get首個數據科學實習

由于數據科學的龐大和復雜&#xff0c;如果你沒有相關的實習經歷的話&#xff0c;成為數據科學家的道路將會更加艱巨和困難。即使是經驗豐富的人&#xff0c;實習也是轉型進入數據科學領域的一種有效方式。 那么&#xff0c;尋找數據科學實習有哪些技巧&#xff1f;本文總結了數…

Halcon:Image、region、xld常用的處理

一、讀取文件夾中的所有圖片 list_files (C:/Users/fuping.liu/Desktop/檳榔有無頭/有頭, [files,follow_links], ImageFiles) tuple_regexp_select (ImageFiles, [\(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$,ignore_case], ImageFiles)for Index :…

賽碼網算法: 上臺階 ( python3實現 、c實現)

上臺階 題目描述 有一樓梯共m級&#xff0c;剛開始時你在第一級&#xff0c;若每次只能跨上一級或二級&#xff0c;要走上第m級&#xff0c;共有多少走法&#xff1f;注&#xff1a;規定從一級到一級有0種走法。 輸入…

Halcon: 畸變矯正與標定(1)

1、 Halcon相機標定和圖像矯正 對于相機采集的圖片&#xff0c;會由于相機本身和透鏡的影響產生形變&#xff0c;通常需要對相機進行標定&#xff0c;獲取相機的內參或內外參&#xff0c;然后矯正其畸變。相機畸變主要分為徑向畸變和切向畸變&#xff0c;其中徑向畸變是由透…

conda install 出錯

在下載包時出現下面的錯誤&#xff1a; userdeMBP:pytorch user$ conda install -n deeplearning matplotlib Solving environment: failedCondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/main/osx-64/repodata.json.bz2> Elapsed…

算法入門經典 第三章

scanf 遇到tab或空格或換行符停下來1.例題2-1 7744問題 從數本身看 從個位數的數字看#include <iostream>#include<math.h>using namespace std; int main(){ for(int a1;a<9;a) { for(int b1;b<9;b) { int n1100*a11*b;//floor x 等于1的區間為[1,2),florr(…

Halcon :畸變矯正與標定(2)

相機標定1.相機標定是什么2.怎么使用halcon進行相機內外參標定&#xff1f; &#xff08;1&#xff09;搭建硬件1.**相機連好電腦&#xff0c;用相機廠家軟件打開相機&#xff0c;檢查一下相機是否正常。**2.**接下來使用halcon連接相機**&#xff08;2&#xff09;開始標定1.*…

jQuery2

一、層次選擇器 1、后代選擇器$("div p"):div中所有的p標簽元素 2、自帶選擇器$("div>p")&#xff1a;div中的子代是p的第一層元素 3、兄弟選擇器$("divp")和div是兄弟的p標簽 4、相鄰兄弟選擇器$("div~p")與div相鄰的p標簽 二、jQ…

HTTP協議詳解(轉載)

http://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html 轉載于:https://www.cnblogs.com/youmei11/p/8608007.html

bzoj1016 [JSOI2008]最小生成樹計數

1016: [JSOI2008]最小生成樹計數 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6032 Solved: 2452[Submit][Status][Discuss]Description 現在給出了一個簡單無向加權圖。你不滿足于求出這個圖的最小生成樹&#xff0c;而希望知道這個圖中有多少個不同的最小生成樹。&…

http請求概述

當瀏覽器輸入網址后 瀏覽器首先向DNS域名解析服務器發送請求。DNS反解析&#xff1a;根據瀏覽器請求地址中的域名&#xff0c;到DNS服務器中找到對應的服務器外網IP地址通過找到外網IP&#xff0c;向對應的服務器發請求&#xff08;首先訪問服務器的WEB站點管理工具&#xff1a…

Halcon:二維仿射變換實例探究

二維仿射變換&#xff0c;顧名思義就是在二維平面內&#xff0c;對對象進行平移、旋轉、縮放等變換的行為&#xff08;當然還有其他的變換&#xff0c;這里僅論述這三種最常見的&#xff09;。 Halcon中進行仿射變換的常見步驟如下&#xff1a; ① 通過hom_mat2d_identity算子…

劍指Offer-數組中重復的數字

題目描述 在一個長度為n的數組里的所有數字都在0到n-1的范圍內。 數組中某些數字是重復的&#xff0c;但不知道有幾個數字是重復的。也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如&#xff0c;如果輸入長度為7的數組{2,3,1,0,2,5,3}&#xff0c;那么對應的…

CSS2--字體樣式

## CSS2 字體樣式 ##### font-family 字體族 - 規定元素的字體系列 - 把多個字體作為一個"回退"系統保存.保證瀏覽器的支持 - Microsoft YaHei, tahoma, arial, Hiragino Sans GB, sans-serif ##### font 字體類型 - 襯線字體(serif)&#xff1a;在字的筆劃開始及結束…