天天看點

unity協程

協程概述

不用急着給它去下個定義,我們隻需要知道協程能做什麼,我們在什麼時候需要使用它就可以了。

在我們需要控制函數的執行順序的時候,我們就需要使用它了,下面我簡單的列舉幾個書上看到的以及我日常中碰到的問題。

1.如何讓一個物體漸變

我們通過寫一個for循環循環它的透明度顯然是不可行的,因為一幀以内會執行完整個for循環,我們隻能看得到開頭和結尾的部分。

2.如何截取螢幕的圖檔

當然,這不是一般的截取,我的工程中需要某一個物體出現在場景中,然後截取該物體,最後再隐藏該物體,如果你在函數裡寫

出現;

截圖;

隐藏;

抱歉,這樣做最後是無法得到該圖檔的

3.大規模的計算

如果在unity腳本裡面執行大規模的計算的時候,我們的程式會卡住一段時間,非常影響使用者體驗,可以利用協程來控制計算的執行速度,把計算分散到每一幀,而不是一幀計算完。

協程用法

void Start()
{
    StartCoroutine("fun");
}
IEnumerator fun()
{
    Debug.Log(Time.time);
    yield return StartCoroutine(WaitAndPrint(2.0f));
    Debug.Log("Done" + Time.time);
}
IEnumerator WaitAndPrint(float waitTime)
{
    yield return new WaitForSeconds(waitTime);
    Debug.Log("waitAndPrint"+Time.time);
}
           

用簡單的方式來了解它,我們可以把協程當做一個函數,調用函數的方法是StartCoroutine,參數是函數的名字,然後協程這個特殊的函數傳回值是IEnumerator,這東西相當于一個暫停,在yield return 的位置會暫停一段時間,暫停的時間完全由自己設定的參數決定,這樣了解應該是簡單多了。

上面的函數通俗一點,我們在start裡面調用fun,然後fun裡面log一下目前時間,然後調用WaitAndPrint函數,WaitAndPrint函數暫停2s,然後傳回,最後再log一下2s之後的時間。

yield return的傳回值

能用的傳回值大緻如下所示:

null 暫停協程的執行,把協程的内容放到下一幀的update執行後再執行

WWW 協程在WWW資源下載下傳完成後再繼續執行

StartCoroutine 協程在指定協程完成後再繼續執行

WaitForEndOfFrame 在一幀結束之後調用,具體的參考順序可以看下面的圖

WaitForFixedUpdate 在fixedUpdate之後執行

WaitForSeconds 等待幾秒後執行

WaitForSecondsRealtime 這個不受幀率影響

WaitUntil 當表達式為false的時候暫停

WaitWhile 當表達式為true的時候暫停,和上面的差別僅僅就在于表達式的真假了

unity協程

執行個體

把一個10000 * 10000 * 10000的三層循環放到協程裡面去做,使得計算沒有卡頓。

IEnumerator calculate()
{
    for (int i = 0; i < 10000; i++)
        for (int j = 0; j < 10000; j++)
            for (int k = 0; k < 10000; k++)
            {
                ans++;                   
                yield return null;
            }
}
           

這樣寫當然很慢,一幀加一點得跑一年,我們可以一幀跑1000次,這樣會快一點。

IEnumerator calculate()
{
    for (int i = 0; i < 10000; i++)
    {            
        for (int j = 0; j < 10000; j++)
        {
            if(j%1000==0)
                yield return null;
            for (int k = 0; k < 10000; k++)
            {
                ans++;
            }
        }
    }
}
           

這樣改法能穩定30幀進行計算。