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

本文详细介绍了Unity中的协程概念及其实现方式,并给出了常见的应用场景,包括延时操作和分帧加载等。此外还探讨了协程的执行顺序、原理以及如何在编辑器环境下使用协程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

一,定义

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


二,注意

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


三,语法

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


四,常见应用

1)延时(别想歪)

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class ExampleClass : MonoBehaviour  
  5. {  
  6.     IEnumerator Start()  
  7.     {  
  8.         Debug.Log("Start--" + Time.time);  
  9.         yield return StartCoroutine(WaitAndLog);  
  10.         Debug.Log("End--" + Time.time);  
  11.     }  
  12.       
  13.     IEnumerator WaitAndLog()  
  14.     {  
  15.         yield return new WaitForSeconds(3);  
  16.         Debug.Log("Wait--" + Time.time);  
  17.     }  
  18. }  
2)分帧加载

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class ExampleClass : MonoBehaviour  
  5. {  
  6.     private int _num,_total;  
  7.     Start()  
  8.     {  
  9.         StartCoroutine(LoadAssets);  
  10.     }  
  11.       
  12.     IEnumerator LoadAssets()  
  13.     {  
  14.         while(_num < _total)  
  15.         {  
  16.             _num++;  
  17.             Debug.Log("Load an Asset");  
  18.             yield return null;  
  19.         }  
  20.     }  
  21. }  


五,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返回值的执行顺序,通过官方文档的一张流程图可以清晰地了解:

七,原理

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函数中实现了嵌套调用协程
[csharp]  view plain  copy
  1. public class EditorCoroutine : IEnumerator    
  2.     {    
  3.         private Stack<IEnumerator> executionStack;    
  4.     
  5.         public EditorCoroutine(IEnumerator iterator)    
  6.         {    
  7.             this.executionStack = new Stack<IEnumerator>();    
  8.             this.executionStack.Push(iterator);    
  9.         }    
  10.     
  11.         public bool MoveNext()    
  12.         {    
  13.             IEnumerator i = this.executionStack.Peek();    
  14.     
  15.             if (i.MoveNext())    
  16.             {    
  17.                 object result = i.Current;    
  18.                 if (result != null && result is IEnumerator)    
  19.                 {    
  20.                     this.executionStack.Push((IEnumerator)result);    
  21.                 }    
  22.     
  23.                 return true;    
  24.             }    
  25.             else    
  26.             {    
  27.                 if (this.executionStack.Count > 1)    
  28.                 {    
  29.                     this.executionStack.Pop();    
  30.                     return true;    
  31.                 }    
  32.             }    
  33.     
  34.             return false;    
  35.         }    
  36.     
  37.         public void Reset()    
  38.         {    
  39.             throw new System.NotSupportedException("This Operation Is Not Supported.");    
  40.         }    
  41.     
  42.         public object Current    
  43.         {    
  44.             get { return this.executionStack.Peek().Current; }    
  45.         }    
  46.     
  47.         public bool Find(IEnumerator iterator)    
  48.         {    
  49.             return this.executionStack.Contains(iterator);    
  50.         }    
  51.     }    
2,EditorCoroutineRunner类,类似MonoBehaviour,提供了StartEditorCoroutine方法创建一个协程
[csharp]  view plain  copy
  1. public static class EditorCoroutineRunner    
  2. {        
  3.     private static List<EditorCoroutine> editorCoroutineList;    
  4.     private static List<IEnumerator> buffer;    
  5.     
  6.     public static IEnumerator StartEditorCoroutine(IEnumerator iterator)    
  7.     {    
  8.         if (editorCoroutineList == null)    
  9.         {    
  10.             editorCoroutineList = new List<EditorCoroutine>();    
  11.         }    
  12.         if (buffer == null)    
  13.         {    
  14.             buffer = new List<IEnumerator>();    
  15.         }    
  16.         if (editorCoroutineList.Count == 0)    
  17.         {    
  18.             EditorApplication.update += Update;    
  19.         }    
  20.     
  21.         buffer.Add(iterator);    
  22.         
  23.         return iterator;    
  24.     }    
  25.     
  26.     private static bool Find(IEnumerator iterator)    
  27.     {     
  28.         foreach (EditorCoroutine editorCoroutine in editorCoroutineList)    
  29.         {    
  30.             if (editorCoroutine.Find(iterator))    
  31.             {    
  32.                 return true;    
  33.             }    
  34.         }    
  35.     
  36.         return false;    
  37.     }    
  38.     
  39.     private static void Update()    
  40.     {    
  41.         editorCoroutineList.RemoveAll    
  42.         (    
  43.             coroutine => { return coroutine.MoveNext() == false; }    
  44.         );    
  45.     
  46.   
  47.         if (buffer.Count > 0)    
  48.         {    
  49.             foreach (IEnumerator iterator in buffer)    
  50.             {    
  51.                 if (!Find(iterator))    
  52.                 {    
  53.                     editorCoroutineList.Add(new EditorCoroutine(iterator));    
  54.                 }    
  55.             }    
  56.     
  57.             buffer.Clear();    
  58.         }    
  59.     
  60.         if (editorCoroutineList.Count == 0)    
  61.         {    
  62.             EditorApplication.update -= Update;    
  63.         }    
  64.     }    
  65. }    
3,调用
[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class ExampleClass  
  5. {  
  6.     Start()  
  7.     {  
  8.         EditorCoroutineRunner.StartEditorCoroutine(Routine);  
  9.     }  
  10.       
  11.     IEnumerator Routine()  
  12.     {  
  13.         Debug.Log("Routine");  
  14.         yield return null;  
  15.     }  
  16. }  

九,参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值