用C# 模擬實現unity里的協程


注:需要了解C#的迭代器,不然很難理解。

之前面試有被問到unity協程的原理,以及撇開unity用純C#去實現協程的方法。后來了解一下,確實可以的。趁這會有空,稍微總結一下。

還是結合代碼說事吧:

 1 /// <summary>
 2 /// 等待接口  3 /// </summary>
 4 public interface IWait  5 {  6     /// <summary>
 7     /// 每幀檢測是否等待結束  8     /// </summary>
 9     /// <returns></returns>
10     bool Tick(); 11 }
View Code

先定義一個等待接口,WaitForSeconds 和 WaitForFrames 實現接口的Tick()方法,每一幀調用Tick()方法檢測是否等待結束

 

 1 /// <summary>
 2 /// 按秒等待
 3 /// </summary>
 4 public class WaitForSeconds:IWait
 5 {
 6     float _seconds = 0f;
 7 
 8     public WaitForSeconds(float seconds)
 9     {
10         _seconds = seconds;
11     }
12 
13     public bool Tick()
14     {
15         _seconds -= Time.deltaTime;
16         return _seconds <= 0;
17     }
18 }
View Code
 1 /// <summary>
 2 /// 按幀等待
 3 /// </summary>
 4 public class WaitForFrames:IWait
 5 {
 6     private int _frames = 0;
 7     public WaitForFrames(int frames)
 8     {
 9         _frames = frames;
10     }
11 
12     public bool Tick()
13     {
14         _frames -= 1;
15         return _frames <= 0;
16     }
17 }
View Code

定義 WaitForSeconds 和 WaitForFrames ,在構造函數初始化需要等待的時間/幀數

 

 

 1 using System;  2 using System.Collections;  3 using System.Collections.Generic;  4 using System.Linq;  5 using System.Text;  6 using System.Threading;  7 using System.Threading.Tasks;  8 
 9 public class CoroutineManager 10 { 11     private static CoroutineManager _instance = null; 12     public static CoroutineManager Instance 13  { 14         get
15  { 16             if (_instance == null) 17  { 18                 _instance = new CoroutineManager(); 19  } 20             return _instance; 21  } 22  } 23 
24     private LinkedList<IEnumerator> coroutineList = new LinkedList<IEnumerator>(); 25 
26     public void StartCoroutine(IEnumerator ie) 27  { 28  coroutineList.AddLast(ie); 29  } 30 
31     public void StopCoroutine(IEnumerator ie) 32  { 33         try
34  { 35  coroutineList.Remove(ie); 36  } 37         catch (Exception e) { Console.WriteLine(e.ToString()); } 38  } 39 
40     public void UpdateCoroutine() 41  { 42         var node = coroutineList.First; 43         while (node != null) 44  { 45             IEnumerator ie = node.Value; 46             bool ret = true; 47             if (ie.Current is IWait) 48  { 49                 IWait wait = (IWait)ie.Current; 50                 //檢測等待條件,條件滿足,跳到迭代器的下一元素 (IEnumerator方法里的下一個yield)
51                 if (wait.Tick()) 52  { 53                     ret = ie.MoveNext(); 54  } 55  } 56             else
57  { 58                 ret = ie.MoveNext(); 59  } 60             //迭代器沒有下一個元素了,刪除迭代器(IEnumerator方法執行結束)
61             if (!ret) 62  { 63  coroutineList.Remove(node); 64  } 65             //下一個迭代器
66             node = node.Next; 67  } 68  } 69 }
View Code

這一段代碼是這里最重要的部分。這里用一個鏈表記錄了添加的所有“協程”,並在UpdateCoroutine()方法的每一次執行都去遍歷這些“協程”以及檢測等待是否結束。

 

1 public class Time 2 { 3     //每幀時間(秒)
4     public static float deltaTime 5     { get { return (float)deltaMilliseconds / 1000; } } 6     //每幀時間(毫秒)
7     public static int deltaMilliseconds 8     { get { return 20; }} 9 }
View Code

模擬一幀的時間。

 

運用測試:

 1 public class Program  2 {  3     static void Main(string[] args)  4  {  5         var t1 = Test01();  6         var t2 = Test02();  7  CoroutineManager.Instance.StartCoroutine(t1);  8  CoroutineManager.Instance.StartCoroutine(t2);  9 
10         while (true)// 模擬update
11  { 12  Thread.Sleep(Time.deltaMilliseconds); 13  CoroutineManager.Instance.UpdateCoroutine(); 14  } 15  } 16 
17 
18     static IEnumerator Test01() 19  { 20         Console.WriteLine("start test 01"); 21         yield return new WaitForSeconds(5); 22         Console.WriteLine("after 5 seconds"); 23         yield return new WaitForSeconds(5); 24         Console.WriteLine("after 10 seconds"); 25  } 26 
27     static IEnumerator Test02() 28  { 29         Console.WriteLine("start test 02"); 30         yield return new WaitForFrames(500); 31         Console.WriteLine("after 500 frames"); 32  } 33 }
View Code

測試結果:

用秒表掐了 一下,好像沒什么毛病。

 


免責聲明!

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



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