用C# 模拟实现unity里的协程
注:需要了解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里的协程的更多相关文章
- Unity中的协程(一)
这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines 这篇文章转自:http://blog.csdn. ...
- Unity C#笔记 协程
什么是协程 协同程序,在主程序运行的同时,开启另外一段逻辑处理,来协同当前程序的执行. 可能看了这段文字介绍还是有点模糊,其实可以用多线程来比较. 多线程 多线程,顾名思义,多条同时执行的线程. 最初 ...
- Unity中的协程是什么?
什么是协程? 1.协程是一个分部执行,遇到条件(yield return 语句)会挂起,直到条件满足才会被唤醒继续执行后面的代码. 2.Unity在每一帧(Frame)都会去处理对象上的协程.Unit ...
- Unity中使用协程进行服务端数据验证手段
近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都 ...
- unity 自实现协程总结
unity本人自实现了一个协程调用. 只是moveNext()的简单协程调用和封装,这个没什么好说的, 网上例子一大堆. 但使用的过程中遇到了几个问题. 1. 自己写的moveNext() 协程不能等 ...
- Unity XLua之协程
如何使用xlua实现协程,示例代码如下: 转载请注明出处:https://www.cnblogs.com/jietian331/p/10735773.html local unpack = unpac ...
- xlua 实现协程替换Unity中的协程
C#中的协程: IEnumerator ShowSpiritInfo() { UIMessageMgr.ShowMsgWait(true); DestroyUIModelInfo(); bool is ...
- 【Unity笔记】协程Coroutine的简单优化
一个最简单的协程,也至少需要2帧才能完成.第一帧走到yield return null停止,第二帧从此处接着执行完下面的操作.需求:如果缓存中存在某数据则直接使用,否则联网异步下载. private ...
- Go语言模拟文件断点续传以及多协程读取写入文件操作
今天整理了一个Go语言多协程拷贝文件的案例,之前用Java写过,这次用Go语言来写一下,代码不难,也很简单,但是网上没有案例,整了很长时间.下面贴出来,供其他人参考学习. func main(){ f ...
随机推荐
- .net core 下编码问题
System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo("zh-CN&q ...
- 简单选择排序算法的C++实现
简单选择排序采用最简单的选择方法,即在剩余序列中选出最小(或最大)的关键字,和剩余序列的第一个关键字交换位置,依次选择下去,直至使整个序列有序. 算法中两层循环的执行次数和初始序列没有关系,第二层循环 ...
- Nginx http相关常用配置总结
Nginx http相关常用配置总结 by:授客 QQ:1033553122 测试环境 nginx-1.10.0 client_max_body_size Syntax: client_ma ...
- php 接口与前端数据交互实现
最近在做前后端数据交互的尝试,也跳了很多坑,使用的是php+bootstrap-table+js,把一些收获记录在这里,方便查询. 这个小项目,仅有3个文件,分别为: crud.html data.p ...
- SQL SERVER LINUX
以前在Linux平台上访问SQL Server时常用的方式有:http://www.freetds.org/https://sourceforge.net/projects/jtds/这方面的资料已经 ...
- 使用VSTS的Git进行版本控制(三)——评审历史记录
使用VSTS的Git进行版本控制(三)--评审历史记录 Git使用存储在每个提交中的父引用信息来管理开发的完整历史记录.评审该提交历史记录,能够找出文件更改的时间,并确定代码版本之间的差异. Git使 ...
- jQuery ajax()使用serialize()提交form数据到后台
1.选中要删除的学生信息 2.点击 删除选中 按钮,把复选框中的值取出提交到后台 3.后台获取选中的id 4.前端也跟着删除数据 示例代码: 前端代码: <!DOCTYPE html> & ...
- EOS智能合约开发(四):智能合约部署及调试(附编程示例)
EOS智能合约开发(一):EOS环境搭建和创建节点 EOS智能合约开发(二):EOS创建和管理钱包 EOS智能合约开发(三):EOS创建和管理账号 部署智能合约的示例代码如下: $ cleos set ...
- NUMA导致的Oracle性能问题
背景简介: Oracle版本:11.2.0.4 OS 版本:OEL5.8 在一次Oracle的Dataguard正常switchover过程中,遇到了一个极其诡异的问题,一条主业务的SQL语句在新主库 ...
- JAVA之Math类常用数学运算记录
Math中定义了许多的方法,且这些方法均为static类型,通过Math类就能直接调用. 调用形式:Math.方法名 例如,我要进行e运算,那么我直接调用Math.exp(double 类型 数值); ...