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