Unity怎样在Editor下运行协程(coroutine)
在处理Unity5新的AssetBundle的时候,我有一个需求,须要在Editor下(比方一个menuitem的处理函数中,游戏没有执行。也没有MonoBehaviour)载入AssetBundle。而载入AssetBundle的时候又须要使用yield return www;这种协程使用方法。
所以就有了一个需求,在Editor下运行协程。我从网上找到一个EditorCoroutine。其代码例如以下:
using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; public static class EditorCoroutineRunner { private class EditorCoroutine : IEnumerator { private Stack<IEnumerator> executionStack; public EditorCoroutine(IEnumerator iterator) { this.executionStack = new Stack<IEnumerator>(); 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); } } private static List<EditorCoroutine> editorCoroutineList; private static List<IEnumerator> buffer; public static IEnumerator StartEditorCoroutine(IEnumerator iterator) { if (editorCoroutineList == null) { // test editorCoroutineList = new List<EditorCoroutine>(); } if (buffer == null) { buffer = new List<IEnumerator>(); } if (editorCoroutineList.Count == 0) { EditorApplication.update += Update; } // add iterator to buffer first buffer.Add(iterator); return iterator; } private static bool Find(IEnumerator iterator) { // If this iterator is already added // Then ignore it this time foreach (EditorCoroutine editorCoroutine in editorCoroutineList) { if (editorCoroutine.Find(iterator)) { return true; } } return false; } private static void Update() { // EditorCoroutine execution may append new iterators to buffer // Therefore we should run EditorCoroutine first editorCoroutineList.RemoveAll ( coroutine => { return coroutine.MoveNext() == false; } ); // If we have iterators in buffer if (buffer.Count > 0) { foreach (IEnumerator iterator in buffer) { // If this iterators not exists if (!Find(iterator)) { // Added this as new EditorCoroutine editorCoroutineList.Add(new EditorCoroutine(iterator)); } } // Clear buffer buffer.Clear(); } // If we have no running EditorCoroutine // Stop calling update anymore if (editorCoroutineList.Count == 0) { EditorApplication.update -= Update; } } }
这里须要注意几个地方:
1、EditorApplication.update,这个是一个delegate,能够绑定一个函数,从而在编辑器下运行Update。
2、EditorCoroutineRunner.StartEditorCoroutine(Routine1()); 这样能够在编辑器下开启一个协程。
3、另外一个思路是不使用协程,绑定一个Update函数,然后推断www.isDone来获取AssetBundle。
这个我并没有实际验证。
4、www能够正常的载入出AssetBundle。可是isDone的变量一直为false。额外要注意由于Editor模式下不存在退出游戏清理资源的概念,所以要注意处理已载入的assetbundle的情况,否则可能会报冲突的错误。
5、理论上仅仅支持yield return null这种情况,延时要自己处理。
Unity协程的原理是引擎在特定条件下运行MoveNext运行以下的语句。在上面的代码中无论是延时还是其它的东西,都是每帧运行MoveNext,这样WaitForSeconds这种协程是无效的。
www的情况比較特殊,尽管理论上也是会有问题的。可是确实能够正常的取到结果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2015-03-26 Android 中屏幕点击事件的实现
2015-03-26 java HashMap中出现反复的key, 求解释
2015-03-26 JAVA修饰符类型(public,protected,private,friendly)
2015-03-26 C/C++产生随机数
2015-03-26 用C设计,用C++编码
2015-03-26 排序总结之高速排序
2015-03-26 Chord算法(原理)