自己实现unity的协程功能_c#实现类似unity的协程-CSDN博客
前天和同事聊天,聊起来协程,聊起原理,什么迭代器,什么MoveNext
几句话带过之后就算完了,事后再次想起,发现自己已经忘了具体细节,于是也打算写成博客,供自己以后回应
一句话概括
(yield外部的)(会运行的)代码行,会被放到MoveNext()中
(写在yield return后面的类或者参数)会变成Current,Update每帧去调Current(判断是否能MoveNext),倘若返回了false,就不做任何事,否则就MoveNext()+新的初始化
具体代码+注释
查看代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
internal class Program
{
static void Main(string[] args)
{
MyMonoBehaviour objMyMonoBehaviour = new MyMonoBehaviour();
Console.WriteLine("Create MyMonoBehaviour" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
objMyMonoBehaviour.StartCoroutine(CoroutineDetail());
while (true)
{
objMyMonoBehaviour.Update();
Thread.Sleep(100);
}
}
static IEnumerator CoroutineDetail()
{
Console.WriteLine("yield return null start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
yield return null;
Console.WriteLine("yield return null end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
Console.WriteLine("wait 1.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
yield return new MyWaitForSeconds(1.0f);
Console.WriteLine("wait 1.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
Console.WriteLine("wait 2.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
yield return new MyWaitForSeconds(2.0f);
Console.WriteLine("wait 2.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
}
}
public class MyMonoBehaviour
{
public class RoutineInfo
{
//我的迭代器
public IEnumerator routine;
//迭代器当前需要比较的对象
public MyYieldInstruction current;
public bool IsCanMoveNext()
{
return current == null || current.IsCanMoveNext();
}
}
//迭代器数据类List
List<RoutineInfo> lstRoutine = new List<RoutineInfo>();
public void StartCoroutine(IEnumerator routine)
{
//如果是空迭代器或者只能迭代一次的,直接返回
if (routine == null || !routine.MoveNext()) return;
//新建迭代数据类,管理该迭代器
RoutineInfo objRoutineInfo = new RoutineInfo();
lstRoutine.Add(objRoutineInfo);
//初始化迭代数据类
objRoutineInfo.routine = routine;
SetRoutineInfo(ref objRoutineInfo);
}
//设置目标迭代器当前的迭代参数
public void SetRoutineInfo(ref RoutineInfo objRoutineInfo)
{
//yield后面不是new了一个类嘛,存到迭代器的Current里了,要拿到类,就在这设置一下
objRoutineInfo.current = objRoutineInfo.routine.Current as MyYieldInstruction;
}
public void Update()
{
//从后往前遍历,便于lstRoutine.RemoveAt(i)
for (int i = lstRoutine.Count - 1; i >= 0; i--)
{
RoutineInfo item = lstRoutine[i];
if (item == null) continue;
if (!item.IsCanMoveNext()) continue;
if (item.routine.MoveNext()) SetRoutineInfo(ref item);
else lstRoutine.RemoveAt(i);//清除迭代完的迭代器
}
}
}
//抽象类+抽象方法,有其他类型的迭代器就继承这个,判断条件由自己去实现
public abstract class MyYieldInstruction
{
public abstract bool IsCanMoveNext();
}
public class MyWaitForSeconds : MyYieldInstruction
{
//在yield return时,记录等待时间,并用于后续的每次比较
public float seconds;
private DateTime beginTime;
public MyWaitForSeconds(float seconds)
{
this.seconds = seconds;
beginTime = DateTime.Now;
}
//MyWaitForSeconds的比较就是
//1.在初始化时记录开始时间和等待时间
//2.使用当前时间减去开始时间,得到时间差
//3.使用时间差去和等待时间比较,如果时间差>等待时间,就表示可以MoveNext
public override bool IsCanMoveNext()
{
TimeSpan deltaSeconds = DateTime.Now - beginTime;
bool res = deltaSeconds.TotalSeconds > seconds;
Console.WriteLine("MyWaitForSeconds类内部比较一次,结果为" + res);
return res;
}
}
输出:
标签:return,迭代,yield,DateTime,协程,Now,public From: https://www.cnblogs.com/LateUpdate/p/18092741