孙广东   2014.7.19

无意之间看到了,Unity维基上的一篇文章,  是关于自己写协程的介绍。

认为非常好,这样能更好的了解到协程的执行机制等特性。还是不错的。

原文链接地址例如以下:

http://wiki.unity3d.com/index.php?title=CoroutineScheduler

项目地址:  http://download.csdn.net/detail/u010019717/8912069

详细的内容例如以下:
        一个简单的协同调度程序。

这个协同调度程序同意全然控制一套协同程序的执行机制。 阅读代码也将帮助您了解  协同怎样在幕后工作。了解协同程序怎样构建.Net 发电机的基础上构建,将同意您将协同支持加入到非Unity的项目。

协同能够yield等待 直到下次更新"yield;",   直到给定的数量的更新已通过 "yield anInt;",   直到给定的秒已通过 "yield aFloat;", 或者直到还有一个协程已完毕"yield scheduler.StartCoroutine(Coroutine());".StartCoroutine(Coroutine());"。

多个 调度 程序实例支持,而且能够非常实用。协同执行能够执行在一个全然不同的 调度程序实例下 (等待)。

不使用Unity的 YieldInstruction 类。由于我门不能訪问这个类所需的调度的内部数据。  语义学Semantics 是和Unity的调度程序略有不同。  比如,在 Unity 中假设你開始协同   它将对其第一次的 yield 马上执行,然而 在自己写的调度程序中,它将不会执行,直到下一次调用 UpdateAllCoroutines。 此功能同意在不论什么时候的不论什么代码開始启动一个协程。

同一时候确保启动协同程序仅仅能执行在特定的时间。

在同样的update协同程序执行之间不应该依赖 更新order。

为更深入地了解和学会很多其它关于 协同程序 怎样实现。

使用:

using UnityEngine;
using System.Collections; /// <summary>
/// CoroutineSchedulerTest.cs
///
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
///
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
///
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gefördert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
///
/// <author>Frank.Otto@htw-berlin.de</author>
///
/// </summary> public class testAPI : MonoBehaviour {
CoroutineScheduler scheduler;
CoroutineScheduler m_scheduler2;
string requestURL = "http://www.my-server.com/cgi-bin/screenshot.pl"; void Start () {
scheduler = new CoroutineScheduler ();
scheduler.StartCoroutine (MyCoroutine ()); m_scheduler2 = new CoroutineScheduler();
m_scheduler2.StartCoroutine(test());
} IEnumerator MyCoroutine ()
{
Debug.Log ("MyCoroutine: Begin");
yield return 0;
// wait for next update
Debug.Log ("MyCoroutine: next update;" + Time.time);
yield return 2;
// wait for 2 updates, same as yield; yield;
Debug.Log ("MyCoroutine: After yield 2;" + Time.time);
yield return 3.5f;
// wait for 3.5 seconds
Debug.Log ("MyCoroutine: After 3.5 seconds;" + Time.time);
// you can also yield for a coroutine running on a completely different scheduler instance
yield return scheduler.StartCoroutine (WaitForMe ());
Debug.Log ("MyCoroutine: After WaitForMe() finished;" + Time.time);
} IEnumerator WaitForMe ()
{
yield return 7.8f;
// wait for 7.8 seconds before finishing
} // Update is called once per
void Update ()
{ scheduler.UpdateAllCoroutines (Time.frameCount, Time.time);
} IEnumerator test()
{
// ...set up request var www = new UnityEngine.WWW(requestURL);
yield return new UnityWWWYieldWrapper(www); // ...loading complete do some stuff
}
}

CoroutineScheduler.cs

using System.Collections;
using UnityEngine; /// <summary>
/// CoroutineScheduler.cs
///
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php? title=CoroutineScheduler
///
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
///
///
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gefördert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
///
/// <author>Frank.Otto@htw-berlin.de</author>
///
///
/// A simple coroutine scheduler. Coroutines can yield until the next update
/// "yield;", until a given number of updates "yield anInt", until a given
/// amount of seconds "yield aFloat;", or until another coroutine has finished
/// "yield scheduler.StartCoroutine(Coroutine())".
///
/// Multiple scheduler instances are supported and can be very useful. A
/// coroutine running under one scheduler can yield (wait) for a coroutine
/// running under a completely different scheduler instance.
///
/// Unity's YieldInstruction classes are not used because I cannot
/// access their internal data needed for scheduling. Semantics are slightly
/// different from Unity's scheduler. For example, in Unity if you start a
/// coroutine it will run up to its first yield immediately, while in this
/// scheduler it will not run until the next time UpdateAllCoroutines is called.
/// This feature allows any code to start coroutines at any time, while
/// making sure the started coroutines only run at specific times.
///
/// You should not depend on update order between coroutines running on the same
/// update. For example, StartCoroutine(A), StartCoroutine(B), StartCoroutine(C)
/// where A, B, C => while(true) { print(A|B|C); yield; }, do not expect "ABC" or
/// "CBA" or any other specific ordering.
/// </summary>
public class CoroutineScheduler : MonoBehaviour
{ CoroutineNode first = null;
int currentFrame;
float currentTime; /**
* Starts a coroutine, the coroutine does not run immediately but on the
* next call to UpdateAllCoroutines. The execution of a coroutine can
* be paused at any point using the yield statement. The yield return value
* specifies when the coroutine is resumed.
*/ public CoroutineNode StartCoroutine (IEnumerator fiber)
{
// if function does not have a yield, fiber will be null and we no-op
if (fiber == null) {
return null;
}
// create coroutine node and run until we reach first yield
CoroutineNode coroutine = new CoroutineNode (fiber);
AddCoroutine (coroutine);
return coroutine;
} /**
* Stops all coroutines running on this behaviour. Use of this method is
* discouraged, think of a natural way for your coroutines to finish
* on their own instead of being forcefully stopped before they finish.
* If you need finer control over stopping coroutines you can use multiple
* schedulers.
*/
public void StopAllCoroutines ()
{
first = null;
} /**
* Returns true if this scheduler has any coroutines. You can use this to
* check if all coroutines have finished or been stopped.
*/
public bool HasCoroutines ()
{
return first != null;
} /**
* Runs all active coroutines until their next yield. Caller must provide
* the current frame and time. This allows for schedulers to run under
* frame and time regimes other than the Unity's main game loop.
*/
public void UpdateAllCoroutines(int frame, float time)
{
currentFrame = frame;
currentTime = time;
CoroutineNode coroutine = this.first;
while (coroutine != null)
{
// store listNext before coroutine finishes and is removed from the list
CoroutineNode listNext = coroutine.listNext; if (coroutine.waitForFrame > 0 && frame >= coroutine.waitForFrame)
{
coroutine.waitForFrame = -1;
UpdateCoroutine(coroutine);
}
else if (coroutine.waitForTime > 0.0f && time >= coroutine.waitForTime)
{
coroutine.waitForTime = -1.0f;
UpdateCoroutine(coroutine);
}
else if (coroutine.waitForCoroutine != null && coroutine.waitForCoroutine.finished)
{
coroutine.waitForCoroutine = null;
UpdateCoroutine(coroutine);
}
else if (coroutine.waitForUnityObject != null && coroutine.waitForUnityObject.finished)//lonewolfwilliams
{
coroutine.waitForUnityObject = null;
UpdateCoroutine(coroutine);
}
else if (coroutine.waitForFrame == -1 && coroutine.waitForTime == -1.0f
&& coroutine.waitForCoroutine == null && coroutine.waitForUnityObject == null)
{
// initial update
UpdateCoroutine(coroutine);
}
coroutine = listNext;
}
} /**
* Executes coroutine until next yield. If coroutine has finished, flags
* it as finished and removes it from scheduler list.
*/
private void UpdateCoroutine(CoroutineNode coroutine)
{
IEnumerator fiber = coroutine.fiber;
if (coroutine.fiber.MoveNext())
{
System.Object yieldCommand = fiber.Current == null ? (System.Object)1 : fiber.Current; if (yieldCommand.GetType() == typeof(int))
{
coroutine.waitForFrame = (int)yieldCommand;
coroutine.waitForFrame += (int)currentFrame;
}
else if (yieldCommand.GetType() == typeof(float))
{
coroutine.waitForTime = (float)yieldCommand;
coroutine.waitForTime += (float)currentTime;
}
else if (yieldCommand.GetType() == typeof(CoroutineNode))
{
coroutine.waitForCoroutine = (CoroutineNode)yieldCommand;
}
else if (yieldCommand is IYieldWrapper) //lonewolfwilliams
{
coroutine.waitForUnityObject = yieldCommand as IYieldWrapper;
}
else
{
throw new System.ArgumentException("CoroutineScheduler: Unexpected coroutine yield type: " + yieldCommand.GetType()); //this is an alternative if you don't have access to the function passed to the couroutineScheduler - maybe it's
//precompiled in a dll for example - remember you will have to add a case every time you add a wrapper :/
/*
var commandType = yieldCommand.GetType();
if(commandType == typeof(UnityEngine.WWW))
{
coroutine.waitForUnityObject =
new UnityWWWWrapper(yieldCommand as UnityEngine.WWW);
}
else if(commandType == typeof(UnityEngine.AsyncOperation))
{
coroutine.waitForUnityObject =
new UnityASyncOpWrapper(yieldCommand as UnityEngine.AsyncOperation);
}
else if(commandType == typeof(UnityEngine.AssetBundleRequest))
{
coroutine.waitForUnityObject =
new UnityAssetBundleRequestWrapper(yieldCommand as UnityEngine.AssetBundleRequest);
}
else
{
throw new System.ArgumentException("CoroutineScheduler: Unexpected coroutine yield type: " + yieldCommand.GetType());
}
*/
}
}
else
{
// coroutine finished
coroutine.finished = true;
RemoveCoroutine(coroutine);
}
} private void AddCoroutine (CoroutineNode coroutine)
{ if (this.first != null) {
coroutine.listNext = this.first;
first.listPrevious = coroutine;
}
first = coroutine;
} private void RemoveCoroutine (CoroutineNode coroutine)
{
if (this.first == coroutine) {
// remove first
this.first = coroutine.listNext;
} else {
// not head of list
if (coroutine.listNext != null) {
// remove between
coroutine.listPrevious.listNext = coroutine.listNext;
coroutine.listNext.listPrevious = coroutine.listPrevious;
} else if (coroutine.listPrevious != null) {
// and listNext is null
coroutine.listPrevious.listNext = null;
// remove last
}
}
coroutine.listPrevious = null;
coroutine.listNext = null;
} }//class

CoroutineNode.cs

using System.Collections;
using UnityEngine; /// <summary>
/// CoroutineNode.cs
///
/// Port of the Javascript version from
/// http://www.unifycommunity.com/wiki/index.php?title=CoroutineScheduler
///
/// Linked list node type used by coroutine scheduler to track scheduling of coroutines.
///
/// BMBF Researchproject http://playfm.htw-berlin.de
/// PlayFM - Serious Games für den IT-gestützten Wissenstransfer im Facility Management
/// Gefördert durch das bmb+f - Programm Forschung an Fachhochschulen profUntFH
///
/// <author>Frank.Otto@htw-berlin.de</author>
///
/// </summary> public class CoroutineNode
{
public CoroutineNode listPrevious = null;
public CoroutineNode listNext = null;
public IEnumerator fiber;
public bool finished = false;
public int waitForFrame = -1;
public float waitForTime = -1.0f;
public CoroutineNode waitForCoroutine;
public IYieldWrapper waitForUnityObject; //lonewolfwilliams public CoroutineNode(IEnumerator _fiber)
{
this.fiber = _fiber;
}
}

IYieldWrapper.cs

/*
* gareth williams
* http://www.lonewolfwilliams.com
*/ public interface IYieldWrapper
{
bool finished { get; }
}

Example Wrappers

Below are some examples of wrappers I have used, in fact they have almost identical signatures so a more generic implementation could probably be written ^_^

UnityASyncOpWrapper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; /*
* Gareth Williams
* http://www.lonewolfwilliams.com
*/ class UnityASyncOpWrapper : IYieldWrapper
{
private UnityEngine.AsyncOperation m_UnityObject;
public bool finished
{
get
{
return m_UnityObject.isDone;
}
} public UnityASyncOpWrapper(UnityEngine.AsyncOperation wraps)
{
m_UnityObject = wraps;
}
}

UnityWWWYieldWrapper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; /*
* Gareth Williams
* http://www.lonewolfwilliams.com
*/ public class UnityWWWYieldWrapper : IYieldWrapper
{
private UnityEngine.WWW m_UnityObject;
public bool finished
{
get
{
return m_UnityObject.isDone;
}
} public UnityWWWYieldWrapper(UnityEngine.WWW wraps)
{
m_UnityObject = wraps;
}
}





神马都是浮云,unity中自己写Coroutine协程源代码的更多相关文章

  1. oracle第一招之神马都是浮云

    oracle: 一款关系型(二维表)数据库,可以用来存储海量数据.在大数据量并发检索的情况下,性能要高于其他的同类数据库产品.一般运行环境是Linux和Unix操作系统上! 目前最流行的商业数据库,主 ...

  2. 关于Unity中Mecanim动画的动画状态代码控制与代码生成动画控制器

    对于多量的.复杂的.有规律的控制器使用代码生成 动画状态代码控制 1:每个动画状态,比如进入状态,离开状态, 等都有可能需要代码来参与和处理,比如,进入这个动画单元后做哪些事情,来开这个动画单元后做哪 ...

  3. 【转】Unity中的协同程序-使用Promise进行封装(三)

    原文:http://gad.qq.com/program/translateview/7170967 译者:崔国军(飞扬971)    审校:王磊(未来的未来) 在这个系列的最后一部分文章,我们要通过 ...

  4. unity3d ppsspp模拟器中的post processing shader在unity中使用

    这个位置可以看到ppsspp的特殊处理文件位置来看看这些特效 用来测试的未加特效图片 ppsspp: 传说系列一生爱---英杰传说 最后的战士 aacolor 是关于饱和度,亮度,对比度,色调的调节, ...

  5. 浅析Unity中的Enlighten与混合光照

    0x00 前言 在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten[1]来提供实时全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapp ...

  6. Unity中巧用协程和游戏对象的生命周期处理游戏重启的问题

    主要用到协程(Coroutines)和游戏对象的生命周期(GameObject Lifecycle)基础知识,巧妙解决了游戏重启的问题. 关于协程,这里有篇文章我觉得写的非常好,理解起来也很容易.推荐 ...

  7. Unity中的ShaderToys——将大神们写的shader搬到unity中来吧

    http://lib.csdn.net/article/unity3d/38699 这篇文章翻译自国外的一篇文章(这里是原文链接),正在使用unity的你是否在shader toy上发现很多牛逼哄哄的 ...

  8. struts神马的不过是对servlet、filter的封装而已,hibernate神马的也不过是对jdbc的封装而已,他们只是把一些常见的操作流程化了,如果不懂servlet、filter,不懂jdbc,使用struts和hibernate出问题了都不知道是怎么回事。

    struts神马的不过是对servlet.filter的封装而已,hibernate神马的也不过是对jdbc的封装而已,他们只是把一些常见的操作流程化了,如果不懂servlet.filter,不懂jd ...

  9. 神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观

    前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本 ...

随机推荐

  1. linux查看内核版本和发行版本号

    1.查看Linux内核版本号:1.1 uname -r #查看当前linux系统的内核版本号显示举例:2.6.21-1.3194.fc71.2 uname -a #可以查看包括内核版本号.机器硬件信息 ...

  2. 网络基础编程_5.4聊天室-IOCP服务器

    聊天室-IOCP服务器 main 创建完成端口内核对象(CreateIoCompletionPort) 获取核心数并创建线程(GetSystemInfo + CreateThread) 创建套接字并绑 ...

  3. Python+Selenium 自动化测试获取测试报告内容并发送邮件

    这里封装一个send_mail()方法,用于测试完成后读取测试报告内容,并将测试结果通过邮件发送到接收人 # coding: utf-8 import smtplib from email.mime. ...

  4. WPF动画 - Loading加载动画

    存在问题: 最近接手公司一个比较成熟的产品项目开发(WPF桌面端),其中,在登陆系统加载时,60张图片切换,实现loading闪烁加载,快有密集恐惧症了!!! 代码如下: private void L ...

  5. 04Hibernate连接数据库环境配置

    Hibernate连接数据库环境配置

  6. hdfs深入:08、hdfs的JavaAPI以及如何解决winutils的问题

    /** * 通过url注册的方式访问hdfs,了解,不会用到 * @throws Exception */ 以下为详细代码://1.注册hdfs的url,让java代码能识别hdfs的url形式URL ...

  7. [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

    偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943   ...

  8. 笔试算法题(21):将stack内外颠倒 & 判断扑克牌顺子

    出题:要求用递归将一个栈结构的元素内外颠倒: 分析: 本题再次说明系统栈是程序员最好的帮手,但递归度较高所以时间复杂度较大,可以使用空间换时间的方法(额外数组保存栈元素,然后逆向压入): 第一层递归( ...

  9. 虚拟机Linux与本地虚拟网卡配置---NAT链接方式

    虚拟机Linux与本地虚拟网卡配置---NAT链接方式 **********这是我亲自尝试多次实践出来的结果,不是复制粘贴************************* 首先进行初始化,这样避免有 ...

  10. 升级openssh踩得坑

    升级背景: 项目中使用的系统为CentOS6.8,经过漏洞扫描后发现openssh高危漏洞,具体描述如下:OpenSSH 7.2p2之前版本, sshd/ session.c/ do_setup_en ...