Unity协程&在编辑器中使用协程

尊重原创,转载请在文首注明出处:http://blog.csdn.net/cai612781/article/details/78992805

一,定义

Unity协程(Coroutine),不是卖机票的携程,是一种类似子线程的机制,可以用来实现一些延时处理的需求,c#中通过yield return语句配合可以中断执行,延时一定时间后从中断处继续执行。


二,注意

协程不是线程,协程不是线程,协程不是线程,协程还是在主线程里!!!


三,语法

脚本需要继承MonoBehaviour,提供了两个方法StartCoroutine(IEnumerator routine)或者StartCoroutine(string methodName)开启一个协程,以及对应的StopCoroutine(IEnumerator routine)或StopCoroutine(string methodName)关闭协程。推荐使用前者,因为传递方法名需要用到反射机制,影响性能。


四,常见应用

1)延时(别想歪)

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
	IEnumerator Start()
	{
		Debug.Log("Start--" + Time.time);
		yield return StartCoroutine(WaitAndLog);
		Debug.Log("End--" + Time.time);
	}
	
	IEnumerator WaitAndLog()
	{
		yield return new WaitForSeconds(3);
		Debug.Log("Wait--" + Time.time);
	}
}
2)分帧加载

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
	private int _num,_total;
	Start()
	{
		StartCoroutine(LoadAssets);
	}
	
	IEnumerator LoadAssets()
	{
		while(_num < _total)
		{
			_num++;
			Debug.Log("Load an Asset");
			yield return null;
		}
	}
}


五,yield

yield语句用于暂停协程的执行,yield return 的值决定什么时候恢复协程的执行。yield return 返回一个IEnumerator对象,当该对象的MoveNext()返回false,即该对象的Current已迭代到最后一个元素时,才会执行yield return后的代码。

yield语句的返回有如下类型:
yield return null;//下一帧再继续往下执行
yield return new WaitForFixedUpdate();//等到下一次调用FixedUpdate再往下执行
yield return new WaitForSceonds(n);//等待n秒再往下执行
yield return StartCoroutine(Method);//开启另一个协程,直到Method执行完毕再往下执行
yield return new WaitForEndOfFrame();//等到该帧结束再往下执行
yield return WWW;//等待资源加载完成再往下执行
yield break;//结束协程

六,执行顺序

协程是每帧lateUpdate前执行yield return之前的代码,lateUpdate后执行yield return之后的代码。
不同yield return返回值的执行顺序,通过官方文档的一张流程图可以清晰地了解:
http://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg

七,原理

Unity的协程应该是一个扩展成支持嵌套的迭代器(IEnumator)。
它将c# IEnumerator封装为Coroutine对象,它记录了该协程的上一级协程是谁,当这个协程执行完成,会继续执行上一级协程。
当Unity Coroutine调用IEnumerator的MoveNext返回一个新Coroutine时,Unity设置新对象的上级Coroutine为当前Coroutine,同时将新Coroutine压入队列,通过此实现嵌套。
然后Unity在主线程中定时检测当前每个等待的Coroutine,满足条件则执行。

八,在Editor下使用Coroutine

编辑器下因为没有运行Unity,也没有创建GameObject,因此也无法通过Monobehaviour的StartCoroutine创建协程。
以下代码来自网上不知哪位大牛,根据Unity协程原理另外实现了个协程:
1,EditorCoroutine协程类实现了IEnumerator接口,在MoveNext函数中实现了嵌套调用协程
public class EditorCoroutine : IEnumerator  
    {  
        private Stack executionStack;  
  
        public EditorCoroutine(IEnumerator iterator)  
        {  
            this.executionStack = new Stack();  
            this.executionStack.Push(iterator);  
        }  
  
        public bool MoveNext()  
        {  
            IEnumerator i = this.executionStack.Peek();  
  
            if (i.MoveNext())  
            {  
                object result = i.Current;  
                if (result != null && result is IEnumerator)  
                {  
                    this.executionStack.Push((IEnumerator)result);  
                }  
  
                return true;  
            }  
            else  
            {  
                if (this.executionStack.Count > 1)  
                {  
                    this.executionStack.Pop();  
                    return true;  
                }  
            }  
  
            return false;  
        }  
  
        public void Reset()  
        {  
            throw new System.NotSupportedException("This Operation Is Not Supported.");  
        }  
  
        public object Current  
        {  
            get { return this.executionStack.Peek().Current; }  
        }  
  
        public bool Find(IEnumerator iterator)  
        {  
            return this.executionStack.Contains(iterator);  
        }  
    }  
2,EditorCoroutineRunner类,类似MonoBehaviour,提供了StartEditorCoroutine方法创建一个协程
public static class EditorCoroutineRunner  
{      
    private static List editorCoroutineList;  
    private static List buffer;  
  
    public static IEnumerator StartEditorCoroutine(IEnumerator iterator)  
    {  
        if (editorCoroutineList == null)  
        {  
            editorCoroutineList = new List();  
        }  
        if (buffer == null)  
        {  
            buffer = new List();  
        }  
        if (editorCoroutineList.Count == 0)  
        {  
            EditorApplication.update += Update;  
        }  
  
        buffer.Add(iterator);  
      
        return iterator;  
    }  
  
    private static bool Find(IEnumerator iterator)  
    {   
        foreach (EditorCoroutine editorCoroutine in editorCoroutineList)  
        {  
            if (editorCoroutine.Find(iterator))  
            {  
                return true;  
            }  
        }  
  
        return false;  
    }  
  
    private static void Update()  
    {  
        editorCoroutineList.RemoveAll  
        (  
            coroutine => { return coroutine.MoveNext() == false; }  
        );  
  

        if (buffer.Count > 0)  
        {  
            foreach (IEnumerator iterator in buffer)  
            {  
                if (!Find(iterator))  
                {  
                    editorCoroutineList.Add(new EditorCoroutine(iterator));  
                }  
            }  
  
            buffer.Clear();  
        }  
  
        if (editorCoroutineList.Count == 0)  
        {  
            EditorApplication.update -= Update;  
        }  
    }  
}  
3,调用
using UnityEngine;
using System.Collections;

public class ExampleClass
{
	Start()
	{
		EditorCoroutineRunner.StartEditorCoroutine(Routine);
	}
	
	IEnumerator Routine()
	{
		Debug.Log("Routine");
		yield return null;
	}
}

九,参考

http://gad.qq.com/article/detail/10552
http://blog.csdn.net/langresser_king/article/details/44244369







你可能感兴趣的:(Unity)