1. 程式人生 > >Unity實戰問題--Loading更好的實現方式(場景進度條問題) 轉+原

Unity實戰問題--Loading更好的實現方式(場景進度條問題) 轉+原

注:前面半部分屬於轉載的文章,因為參考的文章也是轉載的,沒找到原創地址 就不貼地址了,如果有哪位朋友知道的話;請告知,尊重原創前輩!!!

背景

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

嘗試——遇到問題

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

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程式碼如下:

// 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;   
}

最後的效果如下:

打磨——增加動畫

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

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動畫,然後再載入場景。總之進度條雖然小,但要做好也是不容易的。

-----------------------華麗麗的分割線--------------------

我的實現(有點取巧的意思):

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UI_loading : MonoBehaviour {
    public string next2Load;
    public Slider slider;
    private AsyncOperation op;
    private float progress;
    private float speed = 1.5f;
    void Start()
    {
        Debug.Log(next2Load);

        op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(next2Load);
        if (op == null)
        {
            Debug.Log("weikong");
        }
        op.allowSceneActivation = false;    //控制著非同步載入是否自動跳轉
        progress = 0;
        slider.value = progress;
    }

    void Update()
    {
        if (progress < op.progress)   //當allowSceneActivation為false  這個op.progress 最多到0.9
        {
            Debug.Log("載入中");

            progress += speed * Time.deltaTime;
        }
        slider.value = progress;
        Debug.Log("載入中"+progress);
        //slider.value = op.progress*100;
        if (progress >= 0.9f )
        {
            slider.value = 100;
            op.allowSceneActivation = true;

            Debug.Log("allow to change");
        }
    }
}