作者:我是曰照人_692 | 来源:互联网 | 2023-07-17 19:28
尊重原创,转载请在文首注明出处:http:blog.csdn.netcai612781articledetails78992805一,定义Unity协程(Corout
尊重原创,转载请在文首注明出处: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