注:需要了解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. iOS ----------如何修改mac的host文件

    第一步:前往文件夹 或者 按快捷键组合 Shift+Command+G 三个组合按键. 第二步:前往/private/etc/      找到Hosts 文件   复制到桌面    修改  然后  保 ...

  2. Verilog实现模长等于六十的二进制编码计数器

    注释都加上了 由于参考网上的代码,其实现了置数 ,使能等功能,一并加上了 编译结果能通过 百度网盘文件下载:https://pan.baidu.com/s/1IVTD19NRk-s2dKBXtATkA ...

  3. php 接口与前端数据交互实现

    最近在做前后端数据交互的尝试,也跳了很多坑,使用的是php+bootstrap-table+js,把一些收获记录在这里,方便查询. 这个小项目,仅有3个文件,分别为: crud.html data.p ...

  4. JSON基础知识点

    一.介绍: JSON是一种轻量级的数据交换格式.易于人阅读和编写.同时也易于机器解析和生成. 二.数据格式: 1.JSON建构于两种数据格式: “名称/值”对(键值对)的集合,不同的语言中,它被理解为 ...

  5. c/c++ 数组 数组的引用,指针数组的引用

    c/c++ 数组 知识点 1,数组的声明和初始化,对应代码里的test1和test2 2,char数组,对应代码里的test3 3,数组不可以拷贝和复制,对应代码里的test4 4,指针数组, 数组的 ...

  6. realloc 用方法

    realloc 用方法 void* realloc(void*, n) 根据n的大小,如果n比较小,就沿用原来的内存地址(也就是返回的地址就是原来的地址),在原来地址的内存空间的最后面,加上n大小的内 ...

  7. Python常用的数据类型转换

    在实际开发中.经常要根据需求来转变一些变量的类型. 需要用到以下函数:

  8. perl语言中的.pm文件和.pl文件区别

    perl...呵呵呵 按照惯例,.pm 应该保存 Perl Module,也就是 Perl 模块.例如 Socket.pm.pl 应该保存 Perl Library,也就是 Perl 库文件.例如 p ...

  9. 使用 cmd连接 Oracle,MySql,SQL Server 数据库

    1. Oracle cmd连接数据库 语法: sqlplus 用户/口令(密码)@服务器IP/数据库实例名(SID) 1.1 方式一 数据库服务在本机上IP可以用localhost替换 sqlplus ...

  10. 浏览器本地数据存储解决方案以及cookie的坑

    本地数据存储解决方案以及cookie的坑 问题: cookie过长导致页面打开失败 背景: 在公司的项目中有一个需求是打开多个工单即在同一个页面中打开了多个tab(iframe),但是需要在刷新时只刷 ...