1. 程式人生 > >Unity3D之協程(Coroutines & Yield )

Unity3D之協程(Coroutines & Yield )

寫遊戲程式碼,往往最終需要程式碼為連續的事件.結果會像這樣:
[它可以實現將一段程式延遲執行或者將其各個部分分佈在一個時間段內連續執行。]

[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">privateint state = 0;  
  2. void Update()  
  3. {  
  4.         if (state == 0)   
  5.         {  
  6.                 //做步驟0
  7.                 state = 1;  
  8.                 return;  
  9.         }  
  10.         if (state == 1)   
  11.         {  
  12.                 // 做步驟1
  13.                 state = 2;  
  14.                 return;  
  15.         }  
  16.         // ...
  17. } </span>  


往往使用yield語句更為方便.yield語句是一個特殊的返回型別,它確保函式從yield語句的下一行繼續執行.


[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">while(true
    ) {  
  2.         // 做步驟0
  3.         yield return 0;  
  4.          // 等待一幀
  5.         // 做步驟1
  6.         yield return 2;  
  7.          // 等待兩幀
  8.         // ...
  9. } </span>  


你也可以傳遞時間值到yield語句,Update函式會在yield結束後執行下一語句.

[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">  // do something
  2.   yield return WaitForSeconds  (5.0);  
  3.   //等待5秒
  4.   // do something more...  </span>

你可以入棧並連線協程.


這個例子將執行Do,但是do函式之後的print指令會立刻執行.


[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">Do ();  
  2. Console.WriteLine("This is printed immediately");  
  3. IEnumerator  Do ()  
  4. {  
  5.     Console.WriteLine("Do now");  
  6.     yield returnnew WaitForSeconds  (2);        
  7.     Console.WriteLine("Do 2 seconds later");  
  8. } </span>  


這個例子將執行Do,並等待,直到Do完成再執行其他語句.【注:這裡的等待是把執行緒時間交給其他任務,而不是阻塞式等待】


[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">// 啟動協程
  2. yield return StartCoroutine("Do");  
  3. Console.WriteLine("Also after 2 seconds");  
  4. Console.WriteLine ("這個print將在Do協程執行完以後顯示。");  
  5. IEnumerator  Do ()  
  6. {        
  7. Console.WriteLine("Do now");  
  8. yield returnnew WaitForSeconds  (2);  
  9. Console.WriteLine("Do 2 seconds later");  
  10. }  
  11. </span>  


任何事件處理程式都可以是協同程式 。


注意你不能在Update或FixedUpdate函式內使用yield,但是你能使用 StartCoroutine  開始一個函式.


檢視 YieldInstruction , WaitForSeconds , WaitForFixedUpdate , Coroutine  and MonoBehaviour.StartCoroutine  可以獲得更多使用yield的資訊.
yield return可以看做是一種特殊的return,會返回到父類繼續執行,但是yield return後面的型別或方法會有一個執行條件,當條件滿足時會回撥包含yield的子函式,例如下面程式碼
例1:


[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">void Start () {  
  2.         print("Starting:" + Time.time);  
  3.         StartCoroutine(WaitAnPrint(2.0F));  
  4.         print("Before WaiAndPrint:" + Time.time);  
  5.     }  
  6. IEnumerator WaitAndPrint(float waitTime)  
  7.     {  
  8.         yield returnnew WaitForSeconds(waitTime);  
  9.         print("WaitAndPrint:" + Time.time);      
  10.     }  
  11. </span>  


在執行yield return new WaitForSeconds(waitTime)時暫停的條件沒有滿足,故返回到start函式中繼續執行,直到滿足條件後再回調WaitAndPrint,所以輸出為:


Starting:0


Before WaiAndPrint:0


WaitAndPrint:2.12291


例2:


[csharp] view plaincopyprint?
  1. <span style="font-size:18px;">IEnumerator Start()  
  2.     {  
  3.         print("starting:" + Time.time);  
  4.         yield return StartCoroutine(WaitAndPrint(2.0F));  
  5.         print("done:" + Time.time);  
  6.     }  
  7. IEnumerator WaitAndPrint(float waitTime)  
  8.     {  
  9.         yield returnnew WaitForSeconds(waitTime);  
  10.         print("WaitAndPrint:" + Time.time);      
  11.     }</span>  



因為start為頂級函式,所以會阻塞在這裡,直到StartCoroutine(WaitAndPrint(2.0F))執行完畢,輸出為:


starting:0

WaitAndPrint:2.00315

done:2.00315

http://blog.csdn.net/jjiss318/article/details/7447421

yiled return 本質上和return作用一樣,將當前函式返回。只不過下一次再呼叫這個函式,可以從yiled return的下一句開始執行,函式本身的變數也都會一直儲存上一次呼叫的狀態。
摘自 http://zhidao.baidu.com/link?url=04ZkySxpaIeAHUvL8ZR68LPvAh55qIX0AFIz-CV-uJDZQ2NjbOdl8PrDDFIexpS_2G-Xuordc5Vwfp1-mtV_6-WhehXk_ueqEHzmgXhj1f3