Unity3D协同程序(Coroutine)
一。什么是[协同程序][5]
协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行。换句话说,开启协同程序就是开启一个线程。
二。协同程序的开启与终止
在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。
在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。
在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该MonoBehaviour中的协同程序。
还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重名。
三。协同程序的输入、输出类型
协同程序的返回类型为Coroutine类型。在Unity3D中,Coroutine类继承于YieldInstruction,所以,协同程序的返回类型只能为null、等待的帧数(frame)以及等待的时间。
协同程序的参数不能指定ref、out参数。但是,我们在使用WWW类时会经常使用到协同程序,由于在协同程序中不能传递参数地址(引用),也不能输出对象,这使得每下载一个WWW对象都得重写一个协同程序,解决这个问题的方法是建立一个基于WWW的类,并实现一个下载方法。如下:
using UnityEngine;
using System.Collections;
public class WWWObject : MonoBehaviour
{
public WWW www;
public WWWObject(string url)
{
if(GameVar.wwwCache)
www = WWW.LoadFromCacheOrDownload(url, GameVar.version);
else
www = new WWW(url);
}
public IEnumerator Load()
{
Debug.Log("Start loading : " + www.url);
while(!www.isDone)
{
if(GameVar.gameState == GameState.Jumping || GameVar.gameState == GameState.JumpingAsync)
LoadScene.progress = www.progress;
yield return 1;
}
if(www.error != null)
Debug.LogError("Loading error : " + www.url + "\n" + www.error);
else
Debug.Log("End loading : " + www.url);
}
public IEnumerator LoadWithTip(string resourcesName)
{
Debug.Log("Start loading : " + www.url);
LoadScene.tipStr = "Downloading resources <" + resourcesName + "> . . .";
while(!www.isDone)
{
if(GameVar.gameState == GameState.Jumping || GameVar.gameState == GameState.JumpingAsync)
LoadScene.progress = www.progress;
yield return 1;
}
if(www.error != null)
Debug.LogError("Loading error : " + www.url + "\n" + www.error);
else
Debug.Log("End loading : " + www.url);
}
}
调用 :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LoadResources : MonoBehaviour
{
static string url = "http://61.149.211.88/Package/test.unity3d";
public static WWW www = null;
IEnumerator Start()
{
if(!GameVar.resourcesLoaded)
{
GameVar.gameState = GameState.Jumping;
WWWObject obj = new WWWObject(url);
www = obj.www;
yield return StartCoroutine(obj.LoadWithTip("Textures"));
GameVar.resourcesLoaded = true;
GameVar.gameState = GameState.Run;
}
}
}
本博客系博主原创,希望大家能够开开心心交流,提出宝贵意见。
----宇文骐轩