首頁 > 軟體

Unity中協程IEnumerator的使用方法介紹詳解

2022-06-12 14:01:16

在Unity中,一般的方法都是順序執行的,一般的方法也都是在一幀中執行完畢的,當我們所寫的方法需要耗費一定時間時,便會出現影格率下降,畫面卡頓的現象。當我們呼叫一個方法想要讓一個物體緩慢消失時,除了在Update中執行相關操作外,Unity還提供了更加便利的方法,這便是協程。

在通常情況下,如果我們想要讓一個物體逐漸消失,我們希望方法可以一次呼叫便可在程式後續執行中實現我們想要的效果。

我們希望程式碼可以寫成如下所示:

void Fade() 
{
    for (float f = 1f; f >= 0; f -= 0.1f) 
    {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
    }
}

然而該方法在呼叫時將在一幀中執行完畢,無法實現預期的效果。如果將該方法改寫並放到Update函數中可實現我們預期的效果,但是還不夠優雅。

float time = 0f;
float fadeTime = 2f;
void Fade() 
{
    time += Time.dealttime;
    Color c = renderer.material.color;
    c.a = 1f - time/fadeTime;
    renderer.material.color = c;
}

Unity中的協程方法通過yield這個特殊的屬性可以在任何位置、任意時刻暫停。也可以在指定的時間或事件後繼續執行,而不影響上一次執行的就結果,提供了極大地便利性和實用性。
協程在每次執行時都會新建一個(偽)新執行緒來執行,而不會影響主執行緒的執行情況。

正如上邊的方法,我們使用協程可以更加方便的實現我們想要的效果。

void Fade() 
{
    for (float f = 1f; f >= 0; f -= 0.1f) 
    {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield return null;//下一幀繼續執行for迴圈
        yield return new WaitForSeconds(0.1f);//0.1秒後繼續執行for迴圈
    }
}

我們通過StartCoroutine()函數來呼叫協程函數。

值得注意的是,協程並不會在Unity中開闢新的執行緒來執行,其執行仍然發生在主執行緒中。當我們有較為耗時的操作時,可以將該操作分散到幾幀或者幾秒內完成,而不用在一幀內等這個操作完成後再執行其他操作。
如我們需要執行一個迴圈:

IEnumerator CaculateResult()
{
    for (int i = 0; i < 10000; i++)
    {
        //內部迴圈計算
        //在這裡的yield會讓改內部迴圈計算每幀執行一次,而不會等待10000次迴圈結束後再跳出
        //yield return null;
    }
    //如果取消內部的yield操作,僅在for迴圈外邊寫yield操作,則會執行完10000次迴圈後再結束,相當於直接呼叫了一個函數,而非協程。
    //yield return null;
}

呼叫協程的方法有兩種,分別是StartCoroutine(/這裡直接呼叫方法,新增引數/),另一種是StartCoroutine(/這裡填寫”字串的方法名字”,方法引數/)。第一種方法的優勢在於可以呼叫多個引數的方法,後一種方法只能呼叫不含引數或只包含一個引數的協程方法。但是第一種方法不能通過StopCoroutine(/這裡填寫”字串的方法名”/)來結束協程,只能通過StopAllCoroutines來結束。後一種則可以通過StopCoroutine來結束對正在執行的協程的呼叫。

協程在實現過程中我們需要注意yield呼叫的時機,執行較為複雜的計算時,如果在時間上沒有嚴格的先後順序,我們可以每幀執行一次迴圈來完成計算,或者每幀執行指定次數的迴圈來防止在程式執行中出現的卡頓現象。

yield return的介紹:

yield return null; // 下一幀再執行後續程式碼
yield return 0; //下一幀再執行後續程式碼
yield return 6;//(任意數位) 下一幀再執行後續程式碼
yield break; //直接結束該協程的後續操作
yield return asyncOperation;//等非同步操作結束後再執行後續程式碼
yield return StartCoroution(/*某個協程*/);//等待某個協程執行完畢後再執行後續程式碼
yield return WWW();//等待WWW操作完成後再執行後續程式碼
yield return new WaitForEndOfFrame();//等待幀結束,等待直到所有的攝像機和GUI被渲染完成後,在該幀顯示在螢幕之前執行
yield return new WaitForSeconds(0.3f);//等待0.3秒,一段指定的時間延遲之後繼續執行,在所有的Update函數完成呼叫的那一幀之後(這裡的時間會受到Time.timeScale的影響);
yield return new WaitForSecondsRealtime(0.3f);//等待0.3秒,一段指定的時間延遲之後繼續執行,在所有的Update函數完成呼叫的那一幀之後(這裡的時間不受到Time.timeScale的影響);
yield return WaitForFixedUpdate();//等待下一次FixedUpdate開始時再執行後續程式碼
yield return new WaitUntil()//將協同執行直到 當輸入的引數(或者委託)為true的時候....如:yield return new WaitUntil(() => frame >= 10);
yield return new WaitWhile()//將協同執行直到 當輸入的引數(或者委託)為false的時候.... 如:yield return new WaitWhile(() => frame < 10);

當某一個指令碼中的協程在執行過程中,如果我們將該指令碼的enable設定為false,協程不會停止。只有將掛載該指令碼的物體設定為SetActive(false)時才會停止。

Unity在呼叫StartCoroutine()後不會等待協程中的內容返回,會立即執行後續程式碼。

雖然協程十分方便和靈活,但不當的使用會使程式產生無法預想的後果,請使用前慎重考慮。

到此這篇關於Unity中協程IEnumerator的使用方法介紹詳解的文章就介紹到這了,更多相關Unity 協程IEnumerator內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com