1.实现协程功能需要对C#关键词Yield进行理解。(1)yield迭代器会暂停,直到下次调用MoveNext。此处可以做一些处理,来决定是暂停一帧还是暂停多少秒 (2)当MoveNext返回False时该迭代模块会结束。
实现代码如下:
1.当我们在Unity中随便写个协程方法比如:yield return myTest() 和yield return null 效果一样都是暂停一帧。
这是由于c#关键字yield。当执行到yield的时候会暂停,直到下一次调用MoveNext,才会继续往下执行。
private IEnumerator Test()
{
Debug.Log("------Time1:" + Time.realtimeSinceStartup);
Debug.Log("------Time2:" + Time.realtimeSinceStartup);
yield return new Mytest();
Debug.Log("------Time3:"+Time.realtimeSinceStartup);
}
class Mytest
{
}
因此从yield return new myTest() 也是暂停一帧来看,可以判断出正常情况下Unity每一帧都回调用MoveNext。
2.于是写了第二个类测试:当moveNext返回时true 时,一直回调用Unity会一直处理该IEnumator当MoveNext=false时移除
public class MyTest2 : IEnumerator
{
private Action callBack = null;
private float endTime;
public MyTest2 (float time, Action callBack)
{
this.callBack = callBack;
endTime = Time.realtimeSinceStartup + time;
}
public bool MoveNext()
{
return Time.realtimeSinceStartup < endTime;
}
public void Reset()
{
throw new System.NotImplementedException();
}
public object Current
{
get
{
if (callBack != null)
{
callBack();
}
return 1;
}
}
3.自己实现一个简单的协程计时
//C#中的迭代器
class Program
{
static void Main(string[] args)
{
MyCoroutineManager co = new MyCoroutineManager();
co.StartCoroutine(Test());
while (true)
{
co.Update();
Thread.Sleep(1);
}
}
private static IEnumerator Test()
{
yield return null;
Console.WriteLine("-----------");
yield return new MyCoroutineWaitForSecond(5f);
Console.WriteLine(DateTime.Now.ToString());
}
}
class MyCoroutineManager
{
List<RoutineInfo> coroutineList = new List<RoutineInfo>();
private void SetRoutineInfo(ref RoutineInfo info)
{
//info.iteror.Current 是在变动的 当暂停到 yield return null 时 currnet为null
//当执行到 yield return new MyCoroutineWaitForSecond(5f); 此时不为空
if (info.iteror.Current is MyCoroutineWaitForSecond)
{
info.yiel = info.iteror.Current as MyCoroutineWaitForSecond;
}
}
public void Update()
{
List<RoutineInfo> keyToRemove = new List<RoutineInfo>();
for (int i = 0; i < coroutineList.Count; i++)
{
RoutineInfo info = coroutineList[i];
bool canMoveNext = false;
if (info.yiel == null)
{
canMoveNext = true;
}
else
{
canMoveNext = info.yiel.DealWithYield();
}
if (!canMoveNext)
{
continue;
}
//第一步执行yield return null 其MoveNext返回 true
//第二步计时五秒后执行yield rturn wait。。。其返回false 这时候移除
if (info.iteror.MoveNext())
{
SetRoutineInfo(ref info);
}
else
{
keyToRemove.Add(info);
}
}
for (int i = 0; i < keyToRemove.Count; i++)
{
coroutineList.Remove(keyToRemove[i]);
}
}
public void StartCoroutine(IEnumerator co)
{
if (co == null)
return;
RoutineInfo info = new RoutineInfo();
info.iteror = co;
SetRoutineInfo(ref info);
coroutineList.Add(info);
}
}
class RoutineInfo
{
public YieldFather yiel;
public IEnumerator iteror;
}
abstract class YieldFather
{
public abstract bool DealWithYield();
}
class MyCoroutineWaitForSecond : YieldFather
{
public MyCoroutineWaitForSecond(float waitTime)
{
this.waitTime = waitTime;
beginTime = DateTime.Now;
}
private float waitTime = 0;
private DateTime beginTime;
public override bool DealWithYield()
{
return (DateTime.Now - beginTime).TotalSeconds >= waitTime;
}
}