在unity中方法一般是在一幀之內(nèi)執(zhí)行完畢的,當(dāng)方法耗時(shí)的時(shí)候,會(huì)產(chǎn)生幀率下降的情況.
Unity中的協(xié)程:
1:一個(gè)分部執(zhí)行字逗,遇到條件(yield return 語句)會(huì)掛起,直到條件滿足才會(huì)被喚醒繼續(xù)執(zhí)行后面的代碼宅广。
2:Unity在每一幀(Frame)都會(huì)去處理對(duì)象上的協(xié)程葫掉。Unity主要是在LateUpdate()后去處理協(xié)程(檢查協(xié)程的條件是否滿足),相當(dāng)于update函數(shù)加上代碼執(zhí)行位置,上下文環(huán)境.
3:Unity在每幀做的工作就是:調(diào)用 協(xié)程(迭代器)MoveNext() 方法,如果返回 true 跟狱,就從當(dāng)前位置繼續(xù)往下執(zhí)行俭厚。
4:采用分幀概念執(zhí)行,比如一個(gè)方法需要100W幀才能執(zhí)行完畢,用了協(xié)程之后可以將其擴(kuò)展到200W幀執(zhí)行,并不影響主線程.
使用StartCoroutine()函數(shù)來調(diào)用協(xié)程函數(shù)
1: public Coroutine StartCoroutine(IEnumerator routine);??
2:public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value);
3: public Coroutine StartCoroutine(string methodName);
4: public Coroutine StartCoroutine_Auto(IEnumerator routine);
結(jié)束方法:
public void StopAllCoroutines();
public void StopCoroutine(string methodName);
public void StopCoroutine(IEnumerator routine)
public void StopCoroutine(Coroutine routine);
通過yield這個(gè)特殊的屬性可以在任何位置、任意時(shí)刻暫停,也可以在指定的時(shí)間或事件后繼續(xù)執(zhí)行驶臊,而不影響上一次執(zhí)行的就結(jié)果.例子:
協(xié)程并不會(huì)在Unity中開辟新的線程來執(zhí)行挪挤,其執(zhí)行仍然發(fā)生在主線程中叼丑。當(dāng)我們有較為耗時(shí)的操作時(shí),可以將該操作分散到幾幀或者幾秒內(nèi)完成扛门,而不用在一幀內(nèi)等這個(gè)操作完成后再執(zhí)行其他操作鸠信。例子:
協(xié)程在實(shí)現(xiàn)過程中我們需要注意yield調(diào)用的時(shí)機(jī),執(zhí)行較為復(fù)雜的計(jì)算時(shí)尖飞,如果在時(shí)間上沒有嚴(yán)格的先后順序症副,我們可以每幀執(zhí)行一次循環(huán)來完成計(jì)算,或者每幀執(zhí)行指定次數(shù)的循環(huán)來防止在程序運(yùn)行中出現(xiàn)的卡頓現(xiàn)象政基。
比如在for循環(huán)中 用一個(gè)if(i%2==0){yield return null;}進(jìn)行每幀執(zhí)行2次for循環(huán).
yield return null/0; // 下一幀再執(zhí)行后續(xù)代碼
yield return 任意數(shù)字;// 任意數(shù)字 幀后 再執(zhí)行后續(xù)代碼
yield break; //直接結(jié)束該協(xié)程的后續(xù)操作
yield return asyncOperation;//等異步操作結(jié)束后再執(zhí)行后續(xù)代碼
yield return StartCoroution(/*某個(gè)協(xié)程*/);//等待某個(gè)協(xié)程執(zhí)行完畢后再執(zhí)行后續(xù)代碼
yield return WWW();//等待WWW操作完成后再執(zhí)行后續(xù)代碼
yield return new WaitForEndOfFrame();//等待幀結(jié)束,等待直到所有的攝像機(jī)和GUI被渲染完成后贞铣,在該幀顯示在屏幕之前執(zhí)行
yield return new WaitForSeconds(0.3f);//等待0.3秒,一段指定的時(shí)間延遲之后繼續(xù)執(zhí)行沮明,在所有的Update函數(shù)完成調(diào)用的那一幀之后(這里的時(shí)間會(huì)受到Time.timeScale的影響);
yield return new WaitForSecondsRealtime(0.3f);//等待0.3秒辕坝,一段指定的時(shí)間延遲之后繼續(xù)執(zhí)行,在所有的Update函數(shù)完成調(diào)用的那一幀之后(這里的時(shí)間不受到Time.timeScale的影響);
yield return WaitForFixedUpdate();//等待下一次FixedUpdate開始時(shí)再執(zhí)行后續(xù)代碼
yield return new WaitUntil()//將協(xié)同執(zhí)行直到 當(dāng)輸入的參數(shù)(或者委托)為true的時(shí)候....如:yield return new WaitUntil(() => frame >= 10);
yield return new WaitWhile()//將協(xié)同執(zhí)行直到 當(dāng)輸入的參數(shù)(或者委托)為false的時(shí)候.... 如:yield return new WaitWhile(() => frame < 10);
yield 概念解析? ?:當(dāng)你“yield”一個(gè)方法時(shí)荐健,你相當(dāng)于說了酱畅,“現(xiàn)在停止這個(gè)方法,然后在下一幀(或者? 看return后面的條件)中從這里重新開始江场!”
IEnumerator方法 的返回值 表示這個(gè)方法的狀態(tài),StartCoroutine需要記錄,然后進(jìn)行調(diào)用.
注意:
1:當(dāng)某一個(gè)腳本中的協(xié)程在執(zhí)行過程中纺酸,如果我們將該腳本的enable設(shè)置為false,協(xié)程不會(huì)停止址否。只有將掛載該腳本的物體設(shè)置為SetActive(false)時(shí)才會(huì)停止,或者銷毀該物體餐蔬。
2:Coroutine co = StartCoroutine(...)的返回值co 在沒有yield return返回時(shí),co為null,不能使用.
3:StopAllCoroutines()方法表示停止這個(gè)物體上這個(gè)類的協(xié)程全部停止,其他物體上的類的協(xié)程不停止.
4:協(xié)程不是線程,也不是異步執(zhí)行的佑附。協(xié)程和 MonoBehaviour 的 Update函數(shù)一樣也是在MainThread中執(zhí)行的樊诺。使用協(xié)程你不用考慮同步和鎖的問題.? 延時(shí)(等待一段時(shí)間)執(zhí)行代碼,等待某個(gè)操作執(zhí)行完成之后(比如一幀之后),再執(zhí)行后面的代碼.
5:協(xié)程是每幀的LateUpdate()后去運(yùn)行,在start update?LateUpdate方法中都調(diào)用一個(gè)協(xié)程,前后都打印log日志,yield return null 等測(cè)試.
6:一個(gè)空的/最簡(jiǎn)單的協(xié)程,也至少要執(zhí)行2幀 例子:IEnumerator work(){yield return null};啟動(dòng)一次,也要執(zhí)行至少2幀.
7:一個(gè)MONO中開啟多個(gè)協(xié)程時(shí),產(chǎn)生的調(diào)用順序
結(jié)果:
PS:東西太多,無一一測(cè)試,如果錯(cuò)誤,請(qǐng)指出,我所有的文章皆站在巨人的肩膀上寫出.