Unity自己實現協程調度


自己實現協程調度有幾個好處:

  1. 脫離Unity獨立,拿到別的地方也可以用。
  2. 非主線程也可以啟動協程,然后在主線程執行,比如異步網絡消息等。
  3. 可以給每個協程一個id,通過id隨時啟動或關閉某個特定的協程,或者非MonoBehavior對象也可以管理屬於自己的協程。

 

Unity中,Coroutine是在LateUpdate執行的,每一個update都會執行一部分代碼,拿IEnumerator來說,就是每一次都會MoveNext一下。

IEnumerator有三個接口:

  • Current:返回一個object,可以設置當前的一個狀態。
  • MoveNext:返回true表示沒有到最后,返回false表示已經完成枚舉。
  • Reset:恢復狀態,從頭開始枚舉。

 

IEnumerator方法內部會有一個狀態機的實現 ,如果StartCoroutine一個返回IEnumerator方法,每次就會MoveNext到一個yield,遇到yield return,MoveNext會返回true,Current值就是return的對象(yield return null時Current=null, yield return obj時Current=obj),遇到yield break,MoveNext會返回false,表示已經執行完畢。但是如果直接調用IEnumerator.MoveNext,不會去對里面的另一個協程MoveNext,下次就跳過了。

 

基於以上內容,可以自己寫一個方法對IEnumerator進行MoveNext,以實現自制協程的核心代碼:

public static bool MoveNext(IEnumerator subTask)
{
  var child = subTask.Current;
  //yield return另一個協程:遞歸MoveNext
  if (child != null && child is IEnumerator && MoveNext(child as IEnumerator))
    return true;
  #if UNITY
  //yield return www:等待www完成
  if(child is UnityEngine.WWW && !(child as UnityEngine.WWW).isDone)
    return true;
  #endif
  if (subTask.MoveNext ())
    return true;
   return false;
}

 

管理協程很簡單,用一個鏈表來管理:

LinkedListNode<IEnumerator> node = m_taskList.First;
LinkedListNode<IEnumerator> tempNode = node;
while (node != null) {                
  if (!MoveNext(node.Value)) {
    tempNode
= node; node = node.Next; //此處可以寫刪除節點的后續處理 m_taskList.Remove(tempNode); } else { node = node.Next; }
}

 

自己寫IEnumerator方法時,return另一個協程不用寫yield return StartCoroutine(func()),直接寫yield return func()就可以,如:

IEnumerator a()
{
  ...
}

IEnumerator b()
{
  ...
  yield return a();
  ...
}

 

也可以自己寫一些實用的IEnumerator類,比如我們項目里用的WaitForEvent, 還有組合類如WaitForAll,WaitForAny等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM