Unity3D协程介绍

协程介绍

       Unity的协程系统是基于C#的一个简单而强大的接口,IEnumerator,它允许你为自己的集合类型编写枚举器。这一点你不必关注太多,我们直接进入一个简单的例子来看看协程到底能干什么。首先,我们来看一下这段简单的代码...

倒计时器

这是一个简单的脚本组件,只做了倒计时,并且在到达0的时候log一个信息。


还不错,代码简短实用,但问题是,如果我们需要复杂的脚本组件(像一个角色或者敌人的类),拥有多个计时器呢?刚开始的时候,我们的代码也许会是这样的:


尽管不是太糟糕,但是我个人不是很喜欢自己的代码中充斥着这些计时器变量,它们看上去很乱,而且当我需要重新开始计时的时候还得记得去重置它们(这活我经常忘记做)。

如果我只用一个for循环来做这些,看上去是否会好很多?


现在每一个计时器变量都成为for循环的一部分了,这看上去好多了,而且我不需要去单独设置每一个跌倒变量。

好的,你可能现在明白我的意思:协程可以做的正是这一点!

码入你的协程!

现在,这里提供了上面例子运用协程的版本!我建议你从这里开始跟着我来写一个简单的脚本组件,这样你可以在你自己的程序中看到它是如何工作的。



这一行用来开始我们的Countdown程序,注意,我并没有给它传入参数,但是这个方法调用了它自己(这是通过传递Countdown的return返回值来实现的)。

Yield

在Countdown方法中其他的都很好理解,除了两个部分:

 IEnumerator 的返回值

 For循环中的yield return

为了能在连续的多帧中(在这个例子中,3秒钟等同于很多帧)调用该方法,Unity必须通过某种方式来存储这个方法的状态,这是通过IEnumerator 中使用yield return语句得到的返回值,当你“yield”一个方法时,你相当于说了,“现在停止这个方法,然后在下一帧中从这里重新开始!”。

注意:用0或者null来yield的意思是告诉协程等待下一帧,直到继续执行为止。当然,同样的你可以继续yield其他协程,我会在下一个教程中讲到这些。

一些例子

协程在刚开始接触的时候是非常难以理解的,无论是新手还是经验丰富的程序员我都见过他们对于协程语句一筹莫展的时候。因此我认为通过例子来理解它是最好的方法,这里有一些简单的协程例子:

多次输出“Hello”

记住,yield return是“停止执行方法,并且在下一帧从这里重新开始”,这意味着你可以这样做:


每一帧输出“Hello”,无限循环。。。

通过在一个while循环中使用yield,你可以得到一个无限循环的协程,这几乎就跟一个Update()循环等同。。。


计时

...不过跟Update()不一样的是,你可以在协程中做一些更有趣的事:


这个方法突出了协程一个非常酷的地方:方法的状态被存储了,这使得方法中定义的这些变量都会保存它们的值,即使是在不同的帧中。还记得这个教程开始时那些烦人的计时器变量吗?通过协程,我们再也不需要担心它们了,只需要把变量直接放到方法里面!

开始和终止协程

之前,我们已经学过了通过StartCoroutine()方法来开始一个协程,就像这样:

StartCoroutine(Countdown());

如果我们想要终止所有的协程,可以通过StopAllCoroutines()方法来实现,它的所要做的就跟它的名字所表达的一样。注意,这只会终止在调用该方法的对象中(应该是指调用这个方法的类吧)开始的协程,对于其他的MonoBehavior类中运行的协程不起作用。

如果我们有以下这样两条协程语句:

StartCoroutine(FirstTimer());

StartCoroutine(SecondTimer());

那我们怎么终止其中的一个协程呢?在这个例子里,这是不可能的,如果你想要终止某一个特定的协程,那么你必须得在开始协程的时候将它的方法名作为字符串,就像这样:

StartCoroutine("FirstTimer");

StartCoroutine("SecondTimer");

StopCoroutine("FirstTimer");



第一个教程中,我们已经了解了协程如何让一个方法“暂停”下来,并且让它yield直到某些值到达我们给定的数值;并且利用它,我们还创建了一个很棒的计时器系统。协程一个很重要的内容是,它可以让普通的程序(比方说一个计时器)很容易地被抽象化并且被复用。

协程的参数

抽象化一个协程的第一个方法是给它传递参数,协程作为一个函数方法来说,它自然能够传递参数。这里有一个协程的例子,它在特定的地方输出了特定的信息。


嵌套的协程

在此之前,我们yield的时候总是用0(或者null),仅仅告诉程序在继续执行前等待下一帧。协程最强大的一个功能就是它们可以通过使用yield语句来相互嵌套。

眼见为实,我们先来创建一个简单的Wait()程序,不需要它做任何事,只需要在运行的时候等待一段时间就结束。

IEnumerator Wait(floatduration)

{

                for(float   timer = 0; timer < duration; timer += Time.deltaTime)

                           Yield   return 0;

}

接下来我们要编写另一个协程,如下:


第二个方法用了yield,但它并没有用0或者null,而是用了Wait()来yield,这相当于是说,“不再继续执行本程序,直到Wait程序结束”。

现在,协程在程序设计方面的能力要开始展现了。

控制对象行为的例子

在最后一个例子中,我们就来看看协程如何像创建方便的计时器一样来控制对象行为。协程不仅仅可以使用可计数的时间来yield,它还能很巧妙地利用任何条件。将它与嵌套结合使用,你会得到控制游戏对象状态的最强大工具。

运动到某一位置

对于下面这个简单脚本组件,我们可以在Inspector面板中给targetPosition和moveSpeed变量赋值,程序运行的时候,该对象就会在协程的作用下,以我们给定的速度运动到给定的位置。


这样,这个程序并没有通过一个计时器或者无限循环,而是根据对象是否到达指定位置来yield。

按指定路径前进

我们可以让运动到某一位置的程序做更多,不仅仅是一个指定位置,我们还可以通过数组来给它赋值更多的位置,通过MoveToPosition() ,我们可以让它在这些点之间持续运动。


我还加了一个布尔变量,你可以控制在对象运动到最后一个点时是否要进行循环。

把Wait()程序加进来,这样就能让我们的对象在某个点就可以选择是否暂停下来,就像一个正在巡逻的AI守卫一样,这真是锦上添花啊!

注意:

如果你刚接触协程,我希望这两个教程能帮助你了解它们是如何工作的,以及如何来使用它们。以下是一些在使用协程时须谨记的其他注意事项:

在程序中调用StopCoroutine()方法只能终止以字符串形式启动(开始)的协程;

多个协程可以同时运行,它们会根据各自的启动顺序来更新;

协程可以嵌套任意多层(在这个例子中我们只嵌套了一层);

如果你想让多个脚本访问一个协程,那么你可以定义静态的协程;

协程不是多线程(尽管它们看上去是这样的),它们运行在同一线程中,跟普通的脚本一样;

如果你的程序需要进行大量的计算,那么可以考虑在一个随时间进行的协程中处理它们;

IEnumerator类型的方法不能带ref或者out型的参数,但可以带被传递的引用;

目前在Unity中没有简便的方法来检测作用于对象的协程数量以及具体是哪些协程作用在对象上。

【来自作者:ChevyRay】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容