zoukankan      html  css  js  c++  java
  • 神马都是浮云,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>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;
       }
    }



    
    
    
  • 相关阅读:
    Cannot get a NUMERIC value from a STRING cell? 已解决
    Android Studio快捷键大全
    mysql索引
    eclipse中出现错误 Syntax error, insert "}" to complete Block
    function
    IGS OPC UA 配置
    IFIX 5.9 历史数据 曲线 (非SQL模式)
    IFIX 5.9 报警存sql
    IFIX 数据源 节点 标签 域名
    IFIX 目录结构
  • 原文地址:https://www.cnblogs.com/mthoutai/p/6881816.html
Copyright © 2011-2022 走看看