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

之前面试有被问到unity协程的原理,以及撇开unity用纯C#去实现协程的方法。后来了解一下,确实可以的。趁这会有空,稍微总结一下。

还是结合代码说事吧:

 /// <summary>
/// 等待接口
/// </summary>
public interface IWait
{
/// <summary>
/// 每帧检测是否等待结束
/// </summary>
/// <returns></returns>
bool Tick();
}

先定义一个等待接口,WaitForSeconds 和 WaitForFrames 实现接口的Tick()方法,每一帧调用Tick()方法检测是否等待结束

 /// <summary>
/// 按秒等待
/// </summary>
public class WaitForSeconds:IWait
{
float _seconds = 0f; public WaitForSeconds(float seconds)
{
_seconds = seconds;
} public bool Tick()
{
_seconds -= Time.deltaTime;
return _seconds <= ;
}
}
 /// <summary>
/// 按帧等待
/// </summary>
public class WaitForFrames:IWait
{
private int _frames = ;
public WaitForFrames(int frames)
{
_frames = frames;
} public bool Tick()
{
_frames -= ;
return _frames <= ;
}
}

定义 WaitForSeconds 和 WaitForFrames ,在构造函数初始化需要等待的时间/帧数

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; public class CoroutineManager
{
private static CoroutineManager _instance = null;
public static CoroutineManager Instance
{
get
{
if (_instance == null)
{
_instance = new CoroutineManager();
}
return _instance;
}
} private LinkedList<IEnumerator> coroutineList = new LinkedList<IEnumerator>(); public void StartCoroutine(IEnumerator ie)
{
coroutineList.AddLast(ie);
} public void StopCoroutine(IEnumerator ie)
{
try
{
coroutineList.Remove(ie);
}
catch (Exception e) { Console.WriteLine(e.ToString()); }
} public void UpdateCoroutine()
{
var node = coroutineList.First;
while (node != null)
{
IEnumerator ie = node.Value;
bool ret = true;
if (ie.Current is IWait)
{
IWait wait = (IWait)ie.Current;
//检测等待条件,条件满足,跳到迭代器的下一元素 (IEnumerator方法里的下一个yield)
if (wait.Tick())
{
ret = ie.MoveNext();
}
}
else
{
ret = ie.MoveNext();
}
//迭代器没有下一个元素了,删除迭代器(IEnumerator方法执行结束)
if (!ret)
{
coroutineList.Remove(node);
}
//下一个迭代器
node = node.Next;
}
}
}

这一段代码是这里最重要的部分。这里用一个链表记录了添加的所有“协程”,并在UpdateCoroutine()方法的每一次执行都去遍历这些“协程”以及检测等待是否结束。

 public class Time
{
//每帧时间(秒)
public static float deltaTime
{ get { return (float)deltaMilliseconds / ; } }
//每帧时间(毫秒)
public static int deltaMilliseconds
{ get { return ; }}
}

模拟一帧的时间。

运用测试:

 public class Program
{
static void Main(string[] args)
{
var t1 = Test01();
var t2 = Test02();
CoroutineManager.Instance.StartCoroutine(t1);
CoroutineManager.Instance.StartCoroutine(t2); while (true)// 模拟update
{
Thread.Sleep(Time.deltaMilliseconds);
CoroutineManager.Instance.UpdateCoroutine();
}
} static IEnumerator Test01()
{
Console.WriteLine("start test 01");
yield return new WaitForSeconds();
Console.WriteLine("after 5 seconds");
yield return new WaitForSeconds();
Console.WriteLine("after 10 seconds");
} static IEnumerator Test02()
{
Console.WriteLine("start test 02");
yield return new WaitForFrames();
Console.WriteLine("after 500 frames");
}
}

测试结果:

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

用C# 模拟实现unity里的协程的更多相关文章

  1. Unity中的协程(一)

    这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines   这篇文章转自:http://blog.csdn. ...

  2. Unity C#笔记 协程

    什么是协程 协同程序,在主程序运行的同时,开启另外一段逻辑处理,来协同当前程序的执行. 可能看了这段文字介绍还是有点模糊,其实可以用多线程来比较. 多线程 多线程,顾名思义,多条同时执行的线程. 最初 ...

  3. Unity中的协程是什么?

    什么是协程? 1.协程是一个分部执行,遇到条件(yield return 语句)会挂起,直到条件满足才会被唤醒继续执行后面的代码. 2.Unity在每一帧(Frame)都会去处理对象上的协程.Unit ...

  4. Unity中使用协程进行服务端数据验证手段

    近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都 ...

  5. unity 自实现协程总结

    unity本人自实现了一个协程调用. 只是moveNext()的简单协程调用和封装,这个没什么好说的, 网上例子一大堆. 但使用的过程中遇到了几个问题. 1. 自己写的moveNext() 协程不能等 ...

  6. Unity XLua之协程

    如何使用xlua实现协程,示例代码如下: 转载请注明出处:https://www.cnblogs.com/jietian331/p/10735773.html local unpack = unpac ...

  7. xlua 实现协程替换Unity中的协程

    C#中的协程: IEnumerator ShowSpiritInfo() { UIMessageMgr.ShowMsgWait(true); DestroyUIModelInfo(); bool is ...

  8. 【Unity笔记】协程Coroutine的简单优化

    一个最简单的协程,也至少需要2帧才能完成.第一帧走到yield return null停止,第二帧从此处接着执行完下面的操作.需求:如果缓存中存在某数据则直接使用,否则联网异步下载. private ...

  9. Go语言模拟文件断点续传以及多协程读取写入文件操作

    今天整理了一个Go语言多协程拷贝文件的案例,之前用Java写过,这次用Go语言来写一下,代码不难,也很简单,但是网上没有案例,整了很长时间.下面贴出来,供其他人参考学习. func main(){ f ...

随机推荐

  1. 复杂的字符串数组解析:{"setting":"简单:10:5,一般:5:10,困难:2:20"},使用split多次截取

    "[0,{"id":563,"name":"测试题1","dscr":null,"picId&quo ...

  2. SQL Server中如何定位Row Lock锁定哪一行数据

    在SQL Server中有时候会使用提示(Hint)强制SQL使用行锁(Row Lock),前两天有个同事咨询了一个问题,如何定位Row Lock具体锁定了哪一行.其实这个问题只适合研究一下,实际意义 ...

  3. A problem has been detected and windows has been shut down to prevent damage to your computer.他么啥意思?看这里!【蓝屏】

    A problem has been detected and windows has been shut down to prevent damage to your computer.  检测到问 ...

  4. [20181225]12CR2 SQL Plan Directives.txt

    [20181225]12CR2 SQL Plan Directives.txt --//12C引入SQL PLAN Directives.12cR1版本会造成大量的动态取样,影响性能.许多人把OPTI ...

  5. python字符串处理以及字符串格式化

    一.python字符串处理 目录: 1.算长度(len),某个元素出现的次数(count) 2.切片   [ ],repr:把不可见字符显示出来 3.查找 #find,rfind从右边查找 4.字符串 ...

  6. Windows 下自动同步文件夹内容到另一个文件夹下

    实现windows 使用bat脚本文件,复制文件夹到另一个盘,参考如下代码:/y是可以不显示:提示你需要覆盖一个文件,如下图: bat文件内容为 @echo off echo "使用bat脚 ...

  7. LeetCode算法题-Find All Anagrams in a String(Java实现)

    这是悦乐书的第228次更新,第240篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第95题(顺位题号是438).给定一个字符串s和一个非空字符串p,找到s中p的字谜的所有 ...

  8. java操作elasticsearch实现查询删除和查询所有

    后期博客本人都只给出代码,具体的说明在代码中也有注释. 1.查询删除 //查询删除:将查询到的数据进行删除 @Test public void test8() throws UnknownHostEx ...

  9. git使用命令行拉取远程代码仓库中的分支至本地

    1.本地创建文件夹用于存放拉取的代码 2.执行git init初始化文件夹 3.与远程代码仓库建立连接 git remote add origin git@github.com.wuylin/noth ...

  10. Linux 与 Unix 到底有什么不同?区别在哪?

    Linux 与 Unix 到底有什么不同?区别在哪? 如果你是一名20多岁或30多岁的软件开发人员,那么你已成长在一个由Linux主导的世界中.数十年来,它一直是数据中心的重要参与者,尽管很难找到明确 ...