Unity怎樣在Editor下運行協程(coroutine)

        在處理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的狀況比較特殊,儘管理論上也是會有問題的。但是確實可以正常的取到結果。遊戲

相關文章
相關標籤/搜索