zoukankan      html  css  js  c++  java
  • 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的情况比較特殊,尽管理论上也是会有问题的。可是确实能够正常的取到结果。


  • 相关阅读:
    第6章4节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览-翻译命令字串
    Android RecyclerView And CardView
    openstack配置增加
    Failed to allocate the network(s), not rescheduling
    openstack 网络
    python
    云安全
    Python
    ERROR (ClientException): Unexpected API Error
    cocos2d-x 场景切换
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5321940.html
Copyright © 2011-2022 走看看