異步任務相信大家應該不會陌生,那么本章內容MOMO將帶領大家學習Unity中的一些異步任務。在同步加載游戲場景的時候通常會使用方法 Application.LoadLevel(“yourScene”); ?這句代碼執行完畢后程序會干什么呢??如下圖所示,這是我隨便找了一個游戲場景, 在Hierarchy視圖中我們可以看到該場景中“天生”的所有游戲對象。天生的意思就是運行程序前該場景中就已經存在的所有游戲對象。然后這些對象就會在執行完Application.LoadLevel(“yourScene”);方法后加載至內存當中。如果該場景中的游戲對象過多那么瞬間將會出現卡一下的情況,因為LoadLevel()方法是同步進行的。MOMO把這種加載起個名字叫A形式加載
下面我說說“后天“加載的游戲對象。意思是這些游戲對象是通過腳本動態的創建出來的。比如常用方法 :
1GameObject Obj = (GameObject)Instantiate(prefab);
這句代碼執行完畢后同樣會在Hierarchy視圖中添加對應的游戲對象。MOMO把這種加載起個名字叫B形式加載。
下面我們學習異步加載游戲場景,異步異步顧名思義就是不影響當前游戲場景的前提下加載新場景。通常異步加載的方式分為兩種:第一種是異步加載新游戲場景,當新場景加載完成后進入新場景并且銷毀之前的場景。第二種:同樣異步加載新場景,新場景加載完畢后,保留舊場景的游戲對象并且進入新場景。 這里加載的內容就是上面提到的A形式加載。然后B形式加載不會記入這里的加載。
第一種異步加載游戲場景對應的方法是:
1Application.LoadLevelAsync("yourScene");
第二種異步家在游戲場景對應的方法是:
1Application.LoadLevelAdditiveAsync ("yourScene");
這兩種方法加載的方式?完全一樣。異步加載其實重要還是應用于游戲LOADING界面,畢竟LOADING如果采用同步的機制會影響用戶體驗,說到這里MOMO告訴大家如何在Unity中制作游戲進度條。我們應當在Unity中創建一個專門用于讀取進度的場景,假設A場景到C場景,我們應當讓A場景先到讀取進度的場景B場景,當異步任務完成后在進入C場景。 A – 》B -》 C ,在B場景中繪制游戲進度條或讀取動畫。因為B場景僅僅是個顯示LOADING動畫的場景,所以讀取該場景是瞬間就完成的。
程序在切換場景時應當有一個全全局的靜態變量來記錄簡要讀取的場景名稱。這里簡單的寫一下。
1usingUnityEngine;
2usingSystem.Collections;
3
4publicclassGlobe
5{
6//在這里記錄當前切換場景的名稱
7publicstaticstringloadName;
8}
在A場景中通過某些觸發條件 調用LoadLevel進入B場景。
1//記錄LOADING場景中需要讀取的C場景名稱
2Globe.loadName ="C";
3//先進入B場景
4Application.LoadLevel ("B");
OK我們在B場景中異步讀取C場景與 播放讀取動畫,Loading.cs 綁定在B場景的攝像機對象身上。當C場景異步讀取完畢后即可直接進入C場景。
01usingUnityEngine;
02usingSystem.Collections;
03
04publicclassLoading : MonoBehaviour {
05
06privatefloatfps = 10.0f;
07privatefloattime;
08//一組動畫的貼圖,在編輯器中賦值。
09publicTexture2D[] animations;
10privateintnowFram;
11//異步對象
12AsyncOperation async;
13
14//讀取場景的進度,它的取值范圍在0 - 1 之間。
15intprogress = 0;
16
17voidStart()
18{
19//在這里開啟一個異步任務,
20//進入loadScene方法。
21StartCoroutine(loadScene());
22}
23
24//注意這里返回值一定是 IEnumerator
25IEnumerator loadScene()
26{
27//異步讀取場景。
28//Globe.loadName 就是A場景中需要讀取的C場景名稱。
29async = Application.LoadLevelAsync(Globe.loadName);
30
31//讀取完畢后返回, 系統會自動進入C場景
32yieldreturnasync;
33
34}
35
36voidOnGUI()
37{
38//因為在異步讀取場景,
39//所以這里我們可以刷新UI
40DrawAnimation(animations);
41
42}
43
44voidUpdate()
45{
46
47//?在這里計算讀取的進度,
48//progress 的取值范圍在0.1 - 1之間, 但是它不會等于1
49//也就是說progress可能是0.9的時候就直接進入新場景了
50//所以在寫進度條的時候需要注意一下。
51//為了計算百分比 所以直接乘以100即可
52progress = ?(int)(async.progress *100);
53
54//有了讀取進度的數值,大家可以自行制作進度條啦。
55Debug.Log("xuanyusong"+progress);
56
57}
58//這是一個簡單繪制2D動畫?的方法,沒什么好說的。
59voidDrawAnimation(Texture2D[] tex)
60{
61
62time += Time.deltaTime;
63
64if(time >= 1.0 / fps){
65
66nowFram++;
67
68time = 0;
69
70if(nowFram >= tex.Length)
71{
72nowFram = 0;
73}
74}
75GUI.DrawTexture(newRect( 100,100,40,60) ,tex[nowFram] );
76
77//在這里顯示讀取的進度。
78GUI.Label(newRect( 100,180,300,60),"lOADING!!!!!"+ progress);
79
80}
81
82}
OK 下面我們繼續學習在游戲場景中加載對象,文章的開始MOMO已經告訴大家,游戲場景中Hierarchy視圖中的所有的對象在切換場景的時候都會加載。其實有一種方法可以讓某些游戲對象不會被加載,如下圖所示,首先在Hierarchy視圖中選擇一個游戲對象,在右側監測面板視圖中我們可以看到一個 “小對勾”默認情況下是勾選狀態,說明該游戲對象處于激活狀態,如果點掉的話該對象將被隱藏。這個小功能在開發中其實用處非常大,請大家務必記住哈。
此時此刻大家相像一個游戲場景,默認進入的時候是沒有任何游戲對象的,然后運行游戲時開啟一個異步任務將它們一個一個的加載顯示出來,這種方式適合異步的加載一個比較大的游戲場景。
Test.cs 把它掛在攝像機對象中。
01usingUnityEngine;
02usingSystem.Collections;
03
04publicclassTest : MonoBehaviour {
05
06//這里是需要加載激活的游戲對象
07publicGameObject ?[] Objects;
08
09//當前加載的進度
10intload_index =0;
11voidStart ()
12{
13//開啟一個異步任務,加載模型。
14StartCoroutine(loadObject());
15}
16
17IEnumerator loadObject()
18{
19//便利所有游戲對象
20foreach(GameObject objinObjects)
21{
22//激活游戲對象
23obj.active =true;
24//記錄當前加載的對象
25load_index ++;
26
27//這里可以理解為通知主線程刷新UI
28yieldreturn0;
29}
30//全部便利完畢返回
31yieldreturn0;
32}
33
34voidOnGUI ()
35{
36//顯示加載的進度
37GUILayout.Box("當前加載的對象ID是: "+ load_index);
38}
39}
如下圖所示,我們把需要加載的游戲對象以數組的形式放在Objects數組中,因為這些對象屬于未激活狀態,所以不能通過Find 等方法在?腳步那種中找到他們。講到這里我們在說說 編輯器賦值與代碼中賦值的區別,編輯器中賦值所消耗的時間都會記在loadlevel ()讀取場景中。而代碼中使用Resource.load()這類方法所消耗的時間會記在腳本中。開發中還得自行的把握一下把loading加在那里。
當然我們還可以使用Instantiate(prefab);方法來動態的創建游戲對象。
Main.cs 把它掛在攝像機中。
01usingUnityEngine;
02usingSystem.Collections;
03
04publicclassMain : MonoBehaviour
05{
06
07publicintcount;
08//在編輯器中預設一個游戲對象
09publicGameObject prefab;
10
11voidStart ()
12{
13StartCoroutine(loaditem());
14}
15
16voidOnGUI()
17{
18GUILayout.Box("游戲對象已經加載到 : "+ count);
19}
20
21IEnumerator loaditem()
22{
23//開始加載游戲對象
24for(inti =0; i< 1000; i++)
25{
26
27Instantiate(prefab);
28count = i;
29//可以理解為刷新UI,顯示新加載的游戲對象
30yieldreturn0;
31}
32//結束
33yieldreturn0;
34}
35}
運行游戲后該游戲對象會循環1000遍逐個創建,不影響主線程。那么今天我們其實學習最多的就是StartCoroutine(),其實就是開啟一個異步線程,這里可能有朋友會問Thread可以代替它嗎? 答案是不行, 比如查詢數據庫的時候如果用Thread的話Unity就會報錯說不能在線程中查詢,但是在StartCoroutine()中就可以完成,所以開發中大家可以嘗試著使用它,我們還可以使用StopCoroutine(“name”)來關閉一個正在執行的異步線程。不早了晚安,MOMO祝大家學習愉快。