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

翻译 2015年07月21日 08:55:15

孙广东   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;
   }
}






举报

相关文章推荐

Unity5.1 新的网络引擎UNET(三) UNET NetworkManager

孙广东   2015.7.12 我们先来看看这第一个大类的 定义:http://docs.unity3d.com/ScriptReference/Networking.NetworkManager.h...

Unity5.1 新的网络引擎UNET(一) 概括2

孙广东   2015.7.12 有两种网络功能的用户:• 用户使用Unity 制作多人游戏。这些用户应该开始使用NetworkManager 或者 High Level API.• 用户建设网络基础设...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

Unity5.1 新的网络引擎UNET(六) UNET Multiplayer Lobby

孙广东   2015.7.12 Multiplayer Lobby 多人游戏大厅很多多人游戏 都有一个暂存区(staging area ):实际游戏之前等待所有玩家加入的地方,在这一area  -  ...

Unity5.1 新的网络引擎UNET(七) UNET 单人游戏转换为多人

单人游戏转换为多人   孙广东   2015.7.12 本文档描述将单人游戏转换为使用新的网络系统的多人游戏的步骤。这里描述的过程是简化,对于一个真正的游戏其实需要更高级别版本的实际流程,现在介绍的是...

Unity5.1 新的网络引擎UNET(四) UNET Remote Actions

孙广东   2015.7.12 The network system has ways to perform actions across the network. These type of act...

Unity5.1 新的网络引擎UNET(九) UNET 官方推荐视频教程

孙广东  2015.7.14在新的网络引擎出现之前,Unity提供的是 内置 Raknet网络引擎, 这一次Unity想更新UGUI一样,花了大的手笔更新了, UNET, 原来的旧的网络组件 被提示 ...

Unity5.1 新的网络引擎UNET(五) UNET Network Messages

孙广东   2015.7.12 除了high level facilities 的命令和 RPC 调用,还有可能将原始网络消息进行发送。还有一类被称为 MessageBase,可以扩展,使可序列化的网...

Unity5.1 新的网络引擎UNET(十五) Networking 引用--中

孙广东 2015.7.21本节提供了与网络系统一起使用的组件的详细信息。3、NetworkClient        NetworkClient 是一个 HLAPI 类,管理网络连接到服务器 — —...

Unity5.1 新的网络引擎UNET(八) UNET 系统概括

孙广东   2015.7.12 Server and Host在Unity 的 网络系统,游戏有 一个服务器和多个客户端。当没有专用的服务器时,客户端之一扮演服务器的角色 — — 我们称之为此客户端“...

Unity5.1 新的网络引擎UNET(一) 概括1

Unity 将为开发者发布全新的多玩家在线工具、技术和服务。该技术的内部项目名称为 UNET,全称为 Unity Networking。然而,我们的愿景却不仅仅只是简单的联网。众所周知,Unity 公...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)