在处理Unity5新的AssetBundle的时候,我有一个需求,需要在Editor下(比方一个menuitem的处理函数中,游戏没有执行。也没有MonoBehaviour)载入AssetBundle。而载入AssetBundle的时候又需要使用yield return www;这种协程使用方法。app
因此就有了一个需求,在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; } } }
一、EditorApplication.update,这个是一个delegate,可以绑定一个函数,从而在编辑器下运行Update。函数
二、EditorCoroutineRunner.StartEditorCoroutine(Routine1()); 这样可以在编辑器下开启一个协程。ui
三、另一个思路是不使用协程,绑定一个Update函数,而后推断www.isDone来获取AssetBundle。this
这个我并无实际验证。spa
四、www可以正常的载入出AssetBundle。但是isDone的变量一直为false。额外要注意因为Editor模式下不存在退出游戏清理资源的概念,因此要注意处理已载入的assetbundle的状况,不然可能会报冲突的错误。code
五、理论上仅仅支持yield return null这种状况,延时要本身处理。协程
Unity协程的原理是引擎在特定条件下运行MoveNext运行如下的语句。在上面的代码中不管是延时仍是其它的东西,都是每帧运行MoveNext,这样WaitForSeconds这种协程是无效的。blog
www的状况比較特殊,尽管理论上也是会有问题的。但是确实可以正常的取到结果。游戏