協程概述
不用急着給它去下個定義,我們隻需要知道協程能做什麼,我們在什麼時候需要使用它就可以了。
在我們需要控制函數的執行順序的時候,我們就需要使用它了,下面我簡單的列舉幾個書上看到的以及我日常中碰到的問題。
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的時候暫停,和上面的差別僅僅就在于表達式的真假了
執行個體
把一個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幀進行計算。