Unity Coroutine的深度理解与实践

以前一直用unity的 coroutine,什么意思,以及怎么用都知道(我相信大部分人都知道,但是要说出其中的原理,以及如何来扩展自己的coroutine 就不是每个人都知道了)

其实了解一个事物基本上都是从几个方面来:第一,能干嘛,能解决什么问题;  第二,怎么用,能否自己扩展

下面不装B,直接进入正题:

coroutine 的存在其实是为了缓解update的压力,试想如果逻辑的检查都丢到update里面去,那么update将会不堪重负,而且有些特殊的情况根本就不适合丢到update里面去。

比如:角色死亡后20s复活,这样的需求,如果丢到 update里面去,那么每一帧都会去判断角色是否死亡这个很少的需求。而如果用coroutine那么不需要放到没帧去检查了,只需要你执行逻辑那里调用即可。(WaitForSeconds大家都会用)

说到这里,需要了解一下coroutine的生命周期,为啥这么说呢? 因为一度有好多人以为coroutine是thread的替代品(Lua就是这样),而unity其实coroutine并不是thread的替代品,它跟Start, Update 等函数一样,都是Unity底层维护并调用的,具体可以查看unity官方文档,这里只取最重要的部分


这里可以看到,coroutine的执行是在update之后,lateupdate和渲染之前。也就是说当你yield 了以后,下次调用的时机。


using UnityEngine;
using System.Collections;

public class CoroutineHelper : MonoBehaviour {

	void Start () {
		StartCoroutine (Fireworks());
	}

	void Update () {
		Debug.Log("Update time = " + Time.time);
	}

	void LateUpdate () {
		Debug.Log("LateUpdate time = " + Time.time);
	}

	bool bInTask = true;
	IEnumerator Fireworks(){
		Debug.Log ("outside while"); // 这里只是进来一次
		while (bInTask) { 
			float timestart = Time.time;
			Debug.Log ("inside while-1:" + timestart);
			yield return null; // 下一帧调用, 什么都不做
			Debug.Log ("inside while-2:" + timestart);
		}
	}
	  
	void OnGUI(){
		if (GUILayout.Button ("stop")) {
			bInTask = false;
		}
	}
}

这里不是在扣字眼,因为我从来不扣字眼,为啥要去测试这个玩意,是为了更好理解coroutine的执行顺序,然后管理游戏,试想一下相机的处理逻辑一般我们会放到lateupate中,因为这个时候逻辑更新已经处理,咳咳,所以coroutine其实也已经处理了,所以不用担心在coroutine里面的东西有没有在相机之前被执行。

其实从流程图里面可以看到还有好多形式的return 类型。

NULL  : 等待一帧进行处理后续逻辑

WaitForSeconds: 等待指定的时间后处理后续逻辑

WWW:等待下载完毕再处理后续逻辑

Coroutine: 等待着coroutine结束在处理后续逻辑


如何停止coroutine呢? 

这个问题就直接给答案了,一个是通过unity的 stop*** ,另外一个就是把GameObject给enable =false 掉,如果你enable掉的是GameObject上的脚本,你将会发现coroutine并没有被关掉。这里也可以说明coroutine和mono的执行还是不同的,虽然都是由底层来调用。但是和所在的mono没啥关系,只是有所在的mono进行启动而已



好吧~上面的可能并不过瘾~你想要做自己的 干完****处理后续逻辑。这里就需要扩展了~~~

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

扩展部分:

这里有两篇文章,写得不错,先给你们看看 http://www.2cto.com/kf/201507/415345.html   http://www.tuicool.com/articles/ArQJB3

其实很多事都是这样,看上去不起眼的东西当你去实现就会遇到坑哈哈,我就遇到了,当然是我自己sb了,希望能对其他同学有所帮助,我这里模拟了WaitForSeconds的功能。

using UnityEngine;
using System.Collections;

public class Cortine : MonoBehaviour {

	IEnumerator TestCorotine(){
		float startTime = Time.time;
		Debug.Log("startTime - 1: " + startTime);
		yield return new WaitForSeconds(1.0f);
		yield return StartCoroutine(new WaitTaskEndCoroutine(3.0f));
		Debug.Log("endTime - 2: " + Time.time);
		Debug.Log("endTime - 2: " + (Time.time - startTime));
	}

	void OnGUI(){
		if(GUILayout.Button("TestCorotine")){
			StartCoroutine(TestCorotine());
		}
	}
}

class WaitTaskEndCoroutine : IEnumerator{ //继承 
	float taskTime;
	float startTime;
	public WaitTaskEndCoroutine(float time){
		taskTime = time;
		startTime = Time.time;
	}
 
	public object Current{  //重写即可
		get{
			return null;
		}
	}
	//这里我被黑了好久!~刚好把return 的值填反了~~一直没有执行下去
	public bool MoveNext(){
		if((Time.time - startTime)>=taskTime)
		{
			Debug.Log("end....");
			return false;
		}
		Debug.Log("tick....");
		return true;
	}

	public void Reset(){<pre name="code" class="csharp">//重写即可
}}

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我所看到的一些coroutine的优秀的写法

while(true)

{

      dothing

      yield return **

     dothing

}

为啥说这个比较好的写法呢,可以想象一下如果放到update里面会出现什么呢? 首先这需求是一个我要反复做某件事,如果放到updae里面就真的是一帧执行一次了,这样写可以大大减少执行逻辑。

















  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值