Unity3d中製作Loading場景進度條所遇到的問題



  背景

  通常遊戲的主場景包含的資源較多,這會導致加載場景的時間較長。爲了避免這個問題,可以首先加載Loading場景,然後再通過Loading場景來加載主場景。因爲Loading場景包含的資源較少,所以加載速度快。在加載主場景的時候一般會在Loading界面中顯示一個進度條來告知玩家當前加載的進度。在unity中可以通過調用Application.LoadLevelAsync函數來異步加載遊戲場景,通過查詢AsyncOperation.progress的值來得到場景加載的進度。

  嘗試——遇到問題

  第一步當加載完Loading場景後,調用如下的LoadGame函數開始加載遊戲場景,使用異步加載的方式加載場景1(Loading場景爲0,主場景爲1),通過Unity提供的Coroutine機制,我們可以方便的在每一幀結束後調用SetLoadingPercentage函數來更新界面中顯示的進度條的數值。

[AppleScript] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public void LoadGame() {
 
StartCoroutine(StartLoading_1(1));
 
}
 
private IEnumerator StartLoading_1(int scene) {
 
AsyncOperation op = Application.LoadLevelAsync(scene);
 
while(!op.isDone) {
 
SetLoadingPercentage(op.progress * 100);
 
yield return new WaitForEndOfFrame();
 
}
 
}


  最後進度條的效果顯示如下:



  進度條並沒有連續的顯示加載的進度,而是停頓一下切換一個數字,再停頓一下切換一個數子,最後在沒有顯示100%就情況下就切換到主場景了。究其原因在於Application.LoadLevelAsync並不是真正的後臺加載,它在每一幀加載一些遊戲資源,並給出一個progress值,所以在加載的時候還是會造成遊戲卡頓,AsyncOperation.progress的值也不夠精確。當主場景加載完畢後Unity就自動切換場景,所以上述代碼中的while循環體內的代碼是不會被調用的,導致進度條不會顯示100%。

  修補——100%完成


  爲了讓進度條能顯示100%,取巧一點的辦法是將AsyncOperation.progress的值乘上2,這樣當加載到50%的時候界面上就顯示100%了。缺點是當界面上顯示100%的時候,用戶還要等待一段時間纔會進入遊戲。其實Unity提供了手動切換場景的方法,把AsyncOperation.allowSceneActivation設爲false就可以禁止Unity加載完畢後自動切換場景,修改後的StartLoading_2代碼如下:

[AppleScript] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
// this function is not work
 
private IEnumerator StartLoading_2(int scene) {
 
AsyncOperation op = Application.LoadLevelAsync(scene);
 
op.allowSceneActivation = false;
 
while(!op.isDone) {
 
SetLoadingPercentage(op.progress * 100);
 
yield return new WaitForEndOfFrame();
 
}
 
op.allowSceneActivation = true;
 
}


  我們首先將AsyncOperation.allowSceneActivation設爲false,當加載完成後再設爲true。代碼看上去沒有錯,但是執行的結果是進度條最後會一直停留在90%上,場景不會切換。通過打印log發現AsyncOperation.isDone一直爲false,AsyncOperation.progress的值增加到0.9後就保持不變了,也就是說場景永遠不會被加載完畢。



  在這個帖子中找到了答案,原來把allowSceneActivation設置爲false後,Unity就只會加載場景到90%,剩下的10%要等到allowSceneActivation設置爲true後才加載,這不得不說是一個坑。所以代碼改爲如下。當AsyncOperation.progress到達0.9後,就直接把進度條的數值更新爲100%,然後設置AsyncOperation.allowSceneActivation爲ture,讓Unity繼續加載未完成的場景。

[AppleScript] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
private IEnumerator StartLoading_3(int scene) {
 
AsyncOperation op = Application.LoadLevelAsync(scene);
 
op.allowSceneActivation = false;
 
while(op.progress < 0.9f) {
 
SetLoadingPercentage(op.progress * 100);
 
yield return new WaitForEndOfFrame();
 
}
 
SetLoadingPercentage(100);
 
yield return new WaitForEndOfFrame();
 
op.allowSceneActivation = true;
 
}


  最後的效果如下:



  打磨——增加動畫

  上述的進度條雖然解決了100%顯示的問題,但由於進度條的數值更新不是連續的,所以看上去不夠自然和美觀。爲了看上去像是在連續加載,可以每一次更新進度條的時候插入過渡數值。這裏我採用的策略是當獲得AsyncOperation.progress的值後,不立即更新進度條的數值,而是每一幀在原有的數值上加1,這樣就會產生數字不停滾動的動畫效果了,迅雷中顯示下載進度就用了這個方法。

[AppleScript] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
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
private IEnumerator StartLoading_4(int scene) {
 
int displayProgress = 0;
 
int toProgress = 0;
 
AsyncOperation op = Application.LoadLevelAsync(scene);
 
op.allowSceneActivation = false;
 
while(op.progress < 0.9f) {
 
toProgress = (int)op.progress * 100;
 
while(displayProgress < toProgress) {
 
++displayProgress;
 
SetLoadingPercentage(displayProgress);
 
yield return new WaitForEndOfFrame();
 
}
 
}
 
toProgress = 100;
 
while(displayProgress < toProgress){
 
++displayProgress;
 
SetLoadingPercentage(displayProgress);
 
yield return new WaitForEndOfFrame();
 
}
 
op.allowSceneActivation = true;
 
}


  displayProgress用來記錄要顯示在進度條上的數值,最後進度條的動畫如下:



  對比第一種的進度條



  總結


  如果在加載遊戲主場景之前還需要解析數據表格,生成對象池,進行網絡連接等操作,那麼可以給這些操作賦予一個權值,利用這些權值就可以計算加載的進度了。如果你的場景加載速度非常快,那麼可以使用一個假的進度條,讓玩家看上幾秒鐘的loading動畫,然後再加載場景。總之進度條雖然小,但要做好也是不容易的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章