Unity3D协同程序

xiaoxiao2021-02-28  94

原文来自博客园http://www.cnblogs.com/xpvincent/archive/2013/07/25/3214388.html 

还有网易博客http://wg2009perfect.blog.163.com/blog/static/127997663201211111222126/

【协同程序】

协同程序——在主程序运行的同时开启另一就是段逻辑处理,来协同当前程序的执行,开启协同程序就是开启一个线程。

【开启协同程序】

使用MonoBehavior.StartCoroutine可以开启一个协同程序,所以该方法需要在继承Monobehaviour的类中调用

Unity3D中,使用StartCoroutine(String methodName)和startCoroutine(IEnumerator routine)都可以开启一个线程,

a. 使用字符串作为参数可以开启线程并在线程结束之前终止线程,开启线程最多只能传递一个参数

b. 使用IEnumeraotor开启的的线程不能随时终止(除非使用StopAllCoroutines()方法)

没有参数个数的限制

【终止协同程序】

a. Unity使用StopCoroutine(String methodName)来终止一个协同程序,使用StopAllCoroutine来终止所有协同程序,但是这两个方法都只能终止该MonoBehaviour中的协同程序

b. 将协同程序所在的gameObject的acitve属性设置为false,当再次设置active为true的时候,协同程序不会再开启,而设置enable和false则不会生效,因为协同程序开启后是以一个线程在运行的,它与MonoBehavior是互不干扰的模式在运行,此后除非代码调用,他们共同作用于同一个对象,只有当对象不可见的时候才能够同时终止这两个线程。

 

【基本的yield和StartCoroutine讲解】

写游戏代码,往往最终需要代码为连续的事件.结果会像这样: [它可以实现将一段程序延迟执行或者将其各个部分分布在一个时间段内连续执行。]

1: <span style="font-size:18px;">private int state = 0; 2: void Update() 3: { 4: if (state == 0) 5: { 6: //做步骤0 7: state = 1; 8: return; 9: } 10: if (state == 1) 11: { 12: // 做步骤1 13: state = 2; 14: return; 15: } 16: // ... 17: } </span>

往往使用yield语句更为方便.yield语句是一个特殊的返回类型,它确保函数从yield语句的下一行继续执行.

1: <span style="font-size:18px;">while(true) { 2: // 做步骤0 3: yield return 0; 4: // 等待一帧 5: // 做步骤1 6: yield return 2; 7: // 等待两帧 8: // ... 9: } </span> 你也可以传递时间值到yield语句,Update函数会在yield结束后执行下一语句. 1: <span style="font-size:18px;"> // do something 2: yield return WaitForSeconds (5.0); 3: //等待5秒 4: // do something more... </span> 你可以入栈并连接协程. 这个例子将执行Do,但是do函数之后的print指令会立刻执行. 1: <span style="font-size:18px;">Do (); 2: Console.WriteLine("This is printed immediately"); 3: IEnumerator Do () 4: { 5: Console.WriteLine("Do now"); 6: yield return new WaitForSeconds (2); 7: Console.WriteLine("Do 2 seconds later"); 8: } </span> 这个例子将执行Do,并等待,直到Do完成再执行其他语句.【注:这里的等待是把线程时间交给其他任务,而不是阻塞式等待】 1: <span style="font-size:18px;">// 启动协程 2: yield return StartCoroutine("Do"); 3: Console.WriteLine("Also after 2 seconds"); 4: Console.WriteLine ("这个print将在Do协程执行完以后显示。"); 5: IEnumerator Do () 6: { 7: Console.WriteLine("Do now"); 8: yield return new WaitForSeconds (2); 9: Console.WriteLine("Do 2 seconds later"); 10: } 11: </span> 任何事件处理程序都可以是协同程序 。 注意你不能在Update或FixedUpdate函数内使用yield,但是你能使用 StartCoroutine  开始一个函数. 查看 YieldInstruction , WaitForSeconds , WaitForFixedUpdate , Coroutine  and MonoBehaviour.StartCoroutine  可以获得更多使用yield的信息. yield return可以看做是一种特殊的return,会返回到父类继续执行,但是yield return后面的类型或方法会有一个执行条件,当条件满足时会回调包含yield的子函数,例如下面代码 例1: 1: <span style="font-size:18px;">void Start () { 2:  3:  4: print("Starting:" + Time.time); 5:  6:  7: StartCoroutine(WaitAnPrint(2.0F)); 8:  9:  10: print("Before WaiAndPrint:" + Time.time); 11:  12:  13: } 14:  15:  16: IEnumerator WaitAndPrint(float waitTime) 17:  18:  19: { 20:  21:  22: yield return new WaitForSeconds(waitTime); 23:  24:  25: print("WaitAndPrint:" + Time.time); 26:  27:  28: } 29: </span> 在执行yield return new WaitForSeconds(waitTime)时暂停的条件没有满足,故返回到start函数中继续执行,直到满足条件后再回调WaitAndPrint,所以输出为: Starting:0 Before WaiAndPrint:0 WaitAndPrint:2.12291 例2: 5:  6: <span style="font-size:18px;">IEnumerator Start() 7:  8:  9: { 10:  11:  12: print("starting:" + Time.time); 13:  14:  15: yield return StartCoroutine(WaitAndPrint(2.0F)); 16:  17:  18: print("done:" + Time.time); 19:  20:  21: } 22:  23:  24: IEnumerator WaitAndPrint(float waitTime) 25:  26:  27: { 28:  29:  30: yield return new WaitForSeconds(waitTime); 31:  32:  33: print("WaitAndPrint:" + Time.time); 34:  35:  36: }</span>

因为start为顶级函数,所以会阻塞在这里,直到StartCoroutine(WaitAndPrint(2.0F))执行完毕,输出为: starting:0 WaitAndPrint:2.00315 done:2.00315

 

【协同程序的输入、输出】

协同程序返回类型: 为Coroutine型,在Unity中,Coroutine继承于YieldInstruction,所以,协同程序的返回类只能为 null/等待的帧数/等待的时间,协同程序不能指定ref、out参数,所以,通常需要自己实现一个类来完成参数地址(引用)的传递。

如下是一个基于www的类,实现一个下载方法

1: using UnityEngine; 2: using System.Collections; 3: public class WWWObject : MonoBehaviour 4: { 5: public WWW www; 6: 7: public WWWObject(string url) 8: { 9: if(GameVar.wwwCache) 10: www = WWW.LoadFromCacheOrDownload(url, GameVar.version); 11: else 12: www = new WWW(url); 13: } 14: 15: public IEnumerator Load() 16: { 17: Debug.Log("Start loading : " + www.url); 18: while(!www.isDone) 19: { 20: if(GameVar.gameState == GameState.Jumping || GameVar.gameState == GameState.JumpingAsync) 21: LoadScene.progress = www.progress; 22: 23: yield return 1; 24: } 25: if(www.error != null) 26: Debug.LogError("Loading error : " + www.url + "\n" + www.error); 27: else 28: Debug.Log("End loading : " + www.url); 29: } 30: 31: public IEnumerator LoadWithTip(string resourcesName) 32: { 33: Debug.Log("Start loading : " + www.url); 34: LoadScene.tipStr = "Downloading resources <" + resourcesName + "> . . ."; 35: while(!www.isDone) 36: { 37: if(GameVar.gameState == GameState.Jumping || GameVar.gameState == GameState.JumpingAsync) 38: LoadScene.progress = www.progress; 39: 40: yield return 1; 41: } 42: if(www.error != null) 43: Debug.LogError("Loading error : " + www.url + "\n" + www.error); 44: else 45: Debug.Log("End loading : " + www.url); 46: } 47: }

调用:

1: using UnityEngine; 2: using System.Collections; 3: using System.Collections.Generic; 4: public class LoadResources : MonoBehaviour 5: { 6: static string url = "http://61.149.211.88/Package/test.unity3d"; 7: public static WWW www = null; 8: IEnumerator Start() 9: { 10: if(!GameVar.resourcesLoaded) 11: { 12: GameVar.gameState = GameState.Jumping; 13: 14: WWWObject obj = new WWWObject(url); 15: www = obj.www; 16: yield return StartCoroutine(obj.LoadWithTip("Textures")); 17: 18: GameVar.resourcesLoaded = true; 19: GameVar.gameState = GameState.Run; 20: } 21: } 22: }
转载请注明原文地址: https://www.6miu.com/read-31939.html

最新回复(0)