非同步載入遊戲場景與非同步載入遊戲資源進度條
在Hierarchy檢視中我們可以看到該場景中“天生”的所有遊戲物件。天生的意思就是執行程式前該場景中就已經存在的所有遊戲物件。然後這些物件就會在執行完Application.LoadLevel(“yourScene”);方法後加載至記憶體當中。如果該場景中的遊戲物件過多那麼瞬間將會出現卡一下的情況,因為LoadLevel()方法是同步進行的。MOMO把這種載入起個名字叫A形式載入。
下面我說說“後天“載入的遊戲物件。意思是這些遊戲物件是通過指令碼動態的創建出來的。比如常用方法 :
C#
1 |
GameObject Obj = (GameObject)Instantiate(prefab); |
這句程式碼執行完畢後同樣會在Hierarchy檢視中新增對應的遊戲物件。MOMO把這種載入起個名字叫B形式載入。
下面我們學習非同步載入遊戲場景,非同步非同步顧名思義就是不影響當前遊戲場景的前提下載入新場景。通常非同步載入的方式分為兩種:第一種是非同步載入新遊戲場景,當新場景載入完成後進入新場景並且銷燬之前的場景。第二種:同樣非同步載入新場景,新場景載入完畢後,保留舊場景的遊戲物件並且進入新場景。 這裡載入的內容就是上面提到的A形式載入。然後B形式載入不會記入這裡的載入。
第一種非同步載入遊戲場景對應的方法是:
C#
1 |
Application.LoadLevelAsync("yourScene"); |
第二種非同步家在遊戲場景對應的方法是:
C#
1 |
Application.LoadLevelAdditiveAsync ("yourScene"); |
這兩種方法載入的方式完全一樣。非同步載入其實重要還是應用於遊戲LOADING介面,畢竟LOADING如果採用同步的機制會影響使用者體驗,說到這裡MOMO告訴大家如何在Unity中製作遊戲進度條。我們應當在Unity中建立一個專門用於讀取進度的場景,假設A場景到C場景,我們應當讓A場景先到讀取進度的場景B場景,當非同步任務完成後在進入C場景。 A – 》B -》 C ,在B場景中繪製遊戲進度條或讀取動畫
程式在切換場景時應當有一個全全域性的靜態變數來記錄簡要讀取的場景名稱。這裡簡單的寫一下。
C#
1 2 3 4 5 6 7 8 |
using UnityEngine; using System.Collections;
public class Globe { //在這裡記錄當前切換場景的名稱 public static string loadName; } |
在A場景中通過某些觸發條件 呼叫LoadLevel進入B場景。
C#
1 2 3 4 |
//記錄LOADING場景中需要讀取的C場景名稱 Globe.loadName = "C"; //先進入B場景 Application.LoadLevel ("B"); |
OK我們在B場景中非同步讀取C場景與 播放讀取動畫,Loading.cs 繫結在B場景的攝像機物件身上。當C場景非同步讀取完畢後即可直接進入C場景。
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
using UnityEngine; using System.Collections;
public class Loading : MonoBehaviour {
private float fps = 10.0f; private float time; //一組動畫的貼圖,在編輯器中賦值。 public Texture2D[] animations; private int nowFram; //非同步物件 AsyncOperation async;
//讀取場景的進度,它的取值範圍在0 - 1 之間。 int progress = 0;
void Start() { //在這裡開啟一個非同步任務, //進入loadScene方法。 StartCoroutine(loadScene()); }
//注意這裡返回值一定是 IEnumerator IEnumerator loadScene() { //非同步讀取場景。 //Globe.loadName 就是A場景中需要讀取的C場景名稱。 async = Application.LoadLevelAsync(Globe.loadName);
//讀取完畢後返回, 系統會自動進入C場景 yield return async;
}
void OnGUI() { //因為在非同步讀取場景, //所以這裡我們可以重新整理UI DrawAnimation(animations);
}
void Update() {
//在這裡計算讀取的進度, //progress 的取值範圍在0.1 - 1之間, 但是它不會等於1 //也就是說progress可能是0.9的時候就直接進入新場景了 //所以在寫進度條的時候需要注意一下。 //為了計算百分比 所以直接乘以100即可 progress = (int)(async.progress *100);
//有了讀取進度的數值,大家可以自行製作進度條啦。 Debug.Log("xuanyusong" +progress);
} //這是一個簡單繪製2D動畫的方法,沒什麼好說的。 void DrawAnimation(Texture2D[] tex) {
time += Time.deltaTime;
if(time >= 1.0 / fps){
nowFram++;
time = 0;
if(nowFram >= tex.Length) { nowFram = 0; } } GUI.DrawTexture(new Rect( 100,100,40,60) ,tex[nowFram] );
//在這裡顯示讀取的進度。 GUI.Label(new Rect( 100,180,300,60), "lOADING!!!!!" + progress);
}
} |
OK 下面我們繼續學習在遊戲場景中載入物件,文章的開始MOMO已經告訴大家,遊戲場景中Hierarchy檢視中的所有的物件在切換場景的時候都會載入。其實有一種方法可以讓某些遊戲物件不會被載入,如下圖所示,首先在Hierarchy檢視中選擇一個遊戲物件,在右側監測面板檢視中我們可以看到一個 “小對勾”預設情況下是勾選狀態,說明該遊戲物件處於啟用狀態,如果點掉的話該物件將被隱藏。這個小功能在開發中其實用處非常大,請大家務必記住哈。
此時此刻大家相像一個遊戲場景,預設進入的時候是沒有任何遊戲物件的,然後運行遊戲時開啟一個非同步任務將它們一個一個的載入顯示出來,這種方式適合非同步的載入一個比較大的遊戲場景。
Test.cs 把它掛在攝像機物件中。
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using UnityEngine; using System.Collections;
public class Test : MonoBehaviour {
//這裡是需要載入啟用的遊戲物件 public GameObject [] Objects;
//當前載入的進度 int load_index =0; void Start () { //開啟一個非同步任務,載入模型。 StartCoroutine(loadObject()); }
IEnumerator loadObject() { //便利所有遊戲物件 foreach(GameObject obj in Objects) { //啟用遊戲物件 obj.active = true; //記錄當前載入的物件 load_index ++;
//這裡可以理解為通知主執行緒重新整理UI yield return 0; } //全部便利完畢返回 yield return 0; }
void OnGUI () { //顯示載入的進度 GUILayout.Box("當前載入的物件ID是: " + load_index); } } |
如下圖所示,我們把需要載入的遊戲物件以陣列的形式放在Objects陣列中,因為這些物件屬於未啟用狀態,所以不能通過Find 等方法在腳步那種中找到他們。講到這裡我們在說說 編輯器賦值與程式碼中賦值的區別,編輯器中賦值所消耗的時間都會記在loadlevel ()讀取場景中。而程式碼中使用Resource.load()這類方法所消耗的時間會記在指令碼中。開發中還得自行的把握一下把loading加在那裡。
當然我們還可以使用Instantiate(prefab);方法來動態的建立遊戲物件。
Main.cs 把它掛在攝像機中。
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using UnityEngine; using System.Collections;
public class Main : MonoBehaviour {
public int count; //在編輯器中預設一個遊戲物件 public GameObject prefab;
void Start () { StartCoroutine(loaditem()); }
void OnGUI() { GUILayout.Box("遊戲物件已經載入到 : " + count); }
IEnumerator loaditem() { //開始載入遊戲物件 for(int i =0; i< 1000; i++) {
Instantiate(prefab); count = i; //可以理解為重新整理UI,顯示新載入的遊戲物件 yield return 0; } //結束 yield return 0; } } |
運行遊戲後該遊戲物件會迴圈1000遍逐個建立,不影響主執行緒。那麼今天我們其實學習最多的就是StartCoroutine(),其實就是開啟一個非同步執行緒