用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