如果你不是很清楚协同(Coroutine),或者在使用中发现它不能按照你预想的方式工作时你应该读下这篇引导。
协同(Coroutine)适用于以下场合:
比如你可以利用协同实现一组精心组织的场景镜头组合,或者简单的让敌人播放死亡动画,暂停然后复活。
协同是Unity的强大功能之一,但很多初学者可能对其有许多误解,这篇教程会帮你认识协同的强大功能和灵活性,同时也对其运作方式有更深了解。
首先,我们需要清楚认识到:协同不是线程,它不能异步执行。(如果你熟悉Symbian中的活动对象AO的话,你就能更快理解Coroutine,两者的机制非常相似)
线程是进程里与其它线程彼此独立运行的处理过程,在多处理器的设备上,一个线程甚至可以跟其它线程同时执行指令。多线程会是个很复杂的机制,因为某个线程在修改共享数据的时候可能另外一个线程正在读取它,导致脏数据问题,因此你必须检查是否有共享内存,或者对其加锁以建立资源互斥访问区,以保证同一时刻只有一个线程可以访问它。
Ok,我们已经明确了协同不是线程,那么就意味着协同只能运行于主线程中(如果协同内部发生了阻塞,那么一样会阻塞主线程),而且同一时刻只有一个协同在执行。事实上,这也是主游戏逻辑在那个时间段唯一做的事情。
这里有协同的定义:
A coroutine is a function that is executed partially and, presuming suitable conditions are met, will be resumed at some point in the future until its work is done.
协同(coroutine)是一个可以部分执行的函数,一旦合适的条件出现,可以在未来的某个时间点恢复执行,直到任务结束。
Unity会在每帧中每个活动状态的游戏对象(GameObject)处理协同,类似于调度器,这个处理过程发生在Update()方法之后,或者LateUpdate()方法之前,但也有特例:
一旦协同被激活,那它会一直运行到下一个yield声明,然后它会暂停直到(满足条件后)被再次恢复。你能在上图中看到它在何处恢复,不过也得看你yield了什么。
让我们看一个简单的协同示例:
IEnumerator TestCoroutine()
{
while(true)
{
Debug.Log(Time.time);
yield return null;
}
}
这个协同拥有一个无限循环,很显然,会永远运行下去,它把当前时间输出日志然后再yield。一旦它被恢复,仍然会回到循环中,再次输出时间然后yield。
这个循环内部的代码非常像Update()方法。每帧它都会在这个对象(GameObject)的Update后运行(如果脚本里有的话)。
当你调用StartCoroutine(TestCoroutine())后,代码会立即执行直到第一次yield后暂停,然后在Unity处理这个对象的协同时,又会重新被激活,继续恢复执行。
还有个情况-上面这个测试协同看似可以无限循环下去,但如果你在这个游戏对象中调用了终止协同,或者这个游戏对象被销毁,那么这个循环会终止。另外,如果脚本被失效,或者调用SetActiveRecursively(false)后,这个循环也会被暂停。
Unity processes coroutines every frame of the game for every object that has one or more running.
Unity会在每一帧中,处理每一个活动状态游戏对象的所有协同例程。
现在我们知道可以yield不同的值(来描述特定的条件需求)以暂停当前协同,这里是可能用到的yield:
你也可以声明yield break; 这样会立即结束当前协同。
当然,协同最大的好处是你可以编写延时运行的函数,或者等待某个外部事件的发生,还有把这些优雅的集成在一个方法里,让代码有更好的可读性,而不用写一大堆函数来检查状态变化。
原文地址:http://unitygems.com/coroutines/
本人只负责翻译,版权仍归原作者所有,如需转载,请注明该出处!