您好,登錄后才能下訂單哦!
這篇文章主要介紹了Unity中coroutine問題的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
一個最簡單的協程函數:
IEnumerator Test() { yield return new WaitForSeconds(1); Debug.Log("End"); } // 在其它地方StartCoroutine(Test());
作用:當你在其它地方執行了StartCoroutine(Test());之后,1秒之后打印“End”。
在開啟協程之后,Test何時被調用?答案其實是每幀都要調用一次。(對迭代器函數來說,意思是每幀繼續執行一次)。
如果每幀都繼續,那么Test為什么最終在一秒后繼續執行呢?答案在WaitForSeconds里面。
流程是這樣的:
1、在StartCoroutine(Test())里,Test第一次被執行,yield中止并返回一個“WaitForSeconds(1)”對象。
2、執行StartCoroutine時,Unity內部注冊這個Test函數。因為之后每幀都要調用,Unity內部先記下來。
3、這里,返回的WaitForSeconds(1)其實是一個小花招,它的設計思路是:
如果(Time.time小于之前說好的時間) { 返回:沒結束; } 返回:結束了,繼續。 // 這里用偽碼表示,想知道原理可以看后面的Unity官方說明文檔
4、記住:協程函數每幀都要調用一次。于是Unity引擎層在這一秒,每幀都調用Test函數,重復了幾十次,每次都被WaitForSeconds擋住,無法往下執行。
5、直到某一次調用,時隔1秒后了,WaitForSeconds終于放行了,Test才有機會繼續執行,打印“End”。
這就是以WaitForSeconds為例解釋的,協程的執行流程,以及等待1秒的原理。
現在可以回到題主問題了,其實yield return www 和 yield return new WaitForSeconds(1)是完全一樣的道理,WWW的設計是:
如果(網絡請求還在進行中) { 返回:沒結束; } 返回:結束了
同樣的方式,如果網絡請求沒完成,那么你的協程函數就會被www阻攔住。這樣就巧妙實現了一種異步機制,整個游戲不會因為www而卡住。
eldereal 的回答很詳細,其實C#根本就不支持真正的協程,而只支持迭代器。
由于游戲引擎的特殊性(每幀更新),Unity很巧妙的把迭代器改裝成了一個似乎能并行執行的東西,也確實很好用。
別忘了,WWW和WaitForSeconds都是Unity提供的類,并不是C#原本就支持的。如果你很好奇,想擴展出自己的類似WWW的類,參考官方文檔自定義Yield對象:
CustomYieldInstruction
https://docs.unity3d.com/ScriptReference/CustomYieldInstruction.html
由于Unity的這種“偽”協程屬于自己制定的方案,未來引擎更新時候甚至會修改設計,所以理解調用順序和大致原理更重要,不要拘泥于代碼本身。
Unity的Coroutine機制設計的很好,就是這個名字起的太有問題了,無論英文的Coroutine和中文的協程,都很不合適。
有一定golang、python gevent、skynet開發經驗的人(主要是服務器端的),都對協程有較好的理解,而Unity的協程與真正的協程差異太大了。起同樣的名字帶來很大的誤導作用,交流也很困難。
一句話解釋Unity協程:其實Unity的Coroutine在我看來,更像是“注冊一個 每幀都調用的函數”,只不過這個函數支持yield中止,僅此而已。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“Unity中coroutine問題的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。