神马都是浮云,unity中自己写Coroutine协程源代码

孙广东   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>[email protected]</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>[email protected]</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>[email protected]</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;
   }
}

??

??

??

时间: 2024-10-03 14:04:07

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

在Unity中实现动画的正反播放代码

using UnityEngine; using System.Collections; public class AnimationAntiSowing : MonoBehaviour { public static AnimationAntiSowing _initialise; void Awake() { _initialise = this; } /// <summary> /// 动画进行正反播放 /// </summary> /// <param name=&q

IBM简单提问。。。捂脸哭。。神马都不记得了。。。

刚刚接到IBM电话,我都快忘了我投了什么职位,瞎蒙了一个前端,还真是哎..blueMix的前端..汗!完全聊不下去,呜呜呜T^T! 1.阻止冒泡 if (window.event) {//IE  e.cancelBubble=true; } else { //FF  e.stopPropagation(); } 2.异步编程 setTimeout 和 setInterval 在记住一个promise对象: Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口.

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

对于多量的.复杂的.有规律的控制器使用代码生成 动画状态代码控制 1:每个动画状态,比如进入状态,离开状态, 等都有可能需要代码来参与和处理,比如,进入这个动画单元后做哪些事情,来开这个动画单元后做哪些事情,为了解决这个问题,unity允许每个动画单元来绑定一个脚本代码,这个脚本代码必须继承于StateMachineBehaviour;2: 可以在动画状态的Add Behaviour上添加挂载一个脚本到动画状态;3: StateMachineBehaviour主要接口: (1)OnStateEn

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

这个位置可以看到ppsspp的特殊处理文件位置来看看这些特效 用来测试的未加特效图片 ppsspp: 传说系列一生爱---英杰传说 最后的战士 aacolor 是关于饱和度,亮度,对比度,色调的调节,ppsspp中的默认参数为饱和度加强1.2倍,对比度增强1.25倍,在unity中我们可以设为外部变量自己调节 关键代码: float4 frag(v2f i) :COLOR { float size = 1 / _Size; float3 c10 = tex2D(_MainTex, i.uv_Ma

Joda开源扩展插件,神马日期工具类都是浮云!!Demo下载运行即可查看,注释齐全,真心好用,分享大家。

原文:Joda开源扩展插件,神马日期工具类都是浮云!!Demo下载运行即可查看,注释齐全,真心好用,分享大家. 源代码下载地址:http://www.zuidaima.com/share/1550463610604544.htm 真心好用,分享大家.

从王自如和老罗的论战中我貌似懂得了点神马...

3个小时啊!本猫从未一鼓作气看过超过2个小时的非电影作品啊!说是论战,结果基本就是骂战,并且还是一边倒.我本来非常少看这类辩论性的"节目",由于本猫的脑袋瓜子从来都是"海绵式"而不是"淘金式"的工作原理丫,首先这个就让我貌似懂得了神马... 其次我原先对二人都不熟,更不是不论什么人的粉丝脑残或黑丝脑残,不是必需做不论什么人的水军或5毛党.王自如其人原来压根不认识,他的測评站点(公司)Zxx(网上搜到的,如今名字还懒得记)神马的曾经也从没听说过;而

课程14:get和post是神马

http://www.codeschool.cn/lesson/14.html get和post是神马? get和post是http中两种最常用到的请求类型 简单理解get请求 get请求多用于获取信息(无修改操作) 1. 常用于页面整体刷新 比如:浏览器现在是百度的首页www.baidu.com,点击 贴吧 后整体刷新到贴吧的页面tieba.baidu.com,整个浏览器页面都重新刷新了 2. 参数都在url中,常用于页面整体跳转 比如:http://tieba.baidu.com/f?kw=

【iOS开发每日小笔记(五)】实测copy到底是个神马玩意

这篇文章是我的[iOS开发每日小笔记]系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧.该分类的文章,内容涉及的知识点可能是很简单的.或是用很短代码片段就能实现的,但在我看来它们可能会给用户体验.代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下.其实,90%的作用是帮助自己回顾.记忆.复习.如果看官觉得太easy,太碎片,则可以有两个选择:1,移步[iOS探究]分类,对那里的文章进行斧正:2,在本文的评论

4G+又是神马鬼?和LTE-A有什么关系?

4G+又是神马鬼?和LTE-A有什么关系? 先说LTE 和LTE-A LTE全称long-term-evolution这个名字听怎么听怎么觉得有些仓促,它又称为3.9G,其上行峰值速率和最大带宽略低于4G标准,真正将网络带入4G的是LTE-Advanced,即LTE-A. LTE-A是一个LTE演进的代称,它满足ITU-R 的IMT-Advanced技术征集的需求,不仅是3GPP形成欧洲IMT-Advanced技术提案的一个重要来源,还是一个后向兼容的技术,完全兼容LTE,是演进而不是革命.它的