在處理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 > )
{
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 == )
{
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 > )
{
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 == )
{
EditorApplication.update -= Update;
}
}
}
這裡需要注意幾個地方:
1、EditorApplication.update,這個是一個delegate,可以綁定一個函數,進而在編輯器下執行Update。
2、EditorCoroutineRunner.StartEditorCoroutine(Routine1()); 這樣可以在編輯器下開啟一個協程。
3、另外一個思路是不使用協程,綁定一個Update函數,然後判斷www.isDone來擷取AssetBundle。這個我并沒有實際驗證。
文章轉載自Unity如何在Editor下執行協程(coroutine),感謝原作者提供好文章