Unity3D協(xié)程介紹

協(xié)程介紹

? ? ? ?Unity的協(xié)程系統(tǒng)是基于C#的一個(gè)簡(jiǎn)單而強(qiáng)大的接口扭屁,IEnumerator,它允許你為自己的集合類型編寫枚舉器慧起。這一點(diǎn)你不必關(guān)注太多疹吃,我們直接進(jìn)入一個(gè)簡(jiǎn)單的例子來看看協(xié)程到底能干什么。首先乓搬,我們來看一下這段簡(jiǎn)單的代碼...

倒計(jì)時(shí)器

這是一個(gè)簡(jiǎn)單的腳本組件思犁,只做了倒計(jì)時(shí),并且在到達(dá)0的時(shí)候log一個(gè)信息进肯。


還不錯(cuò)激蹲,代碼簡(jiǎn)短實(shí)用,但問題是江掩,如果我們需要復(fù)雜的腳本組件(像一個(gè)角色或者敵人的類)学辱,擁有多個(gè)計(jì)時(shí)器呢乘瓤?剛開始的時(shí)候,我們的代碼也許會(huì)是這樣的:


盡管不是太糟糕策泣,但是我個(gè)人不是很喜歡自己的代碼中充斥著這些計(jì)時(shí)器變量衙傀,它們看上去很亂,而且當(dāng)我需要重新開始計(jì)時(shí)的時(shí)候還得記得去重置它們(這活我經(jīng)常忘記做)萨咕。

如果我只用一個(gè)for循環(huán)來做這些统抬,看上去是否會(huì)好很多?


現(xiàn)在每一個(gè)計(jì)時(shí)器變量都成為for循環(huán)的一部分了危队,這看上去好多了聪建,而且我不需要去單獨(dú)設(shè)置每一個(gè)跌倒變量。

好的茫陆,你可能現(xiàn)在明白我的意思:協(xié)程可以做的正是這一點(diǎn)金麸!

碼入你的協(xié)程!

現(xiàn)在簿盅,這里提供了上面例子運(yùn)用協(xié)程的版本钱骂!我建議你從這里開始跟著我來寫一個(gè)簡(jiǎn)單的腳本組件,這樣你可以在你自己的程序中看到它是如何工作的挪鹏。



這一行用來開始我們的Countdown程序,注意愉烙,我并沒有給它傳入?yún)?shù)讨盒,但是這個(gè)方法調(diào)用了它自己(這是通過傳遞Countdown的return返回值來實(shí)現(xiàn)的)。

Yield

在Countdown方法中其他的都很好理解步责,除了兩個(gè)部分:

?IEnumerator?的返回值

?For循環(huán)中的yield?return

為了能在連續(xù)的多幀中(在這個(gè)例子中返顺,3秒鐘等同于很多幀)調(diào)用該方法,Unity必須通過某種方式來存儲(chǔ)這個(gè)方法的狀態(tài)蔓肯,這是通過IEnumerator?中使用yield?return語句得到的返回值遂鹊,當(dāng)你“yield”一個(gè)方法時(shí),你相當(dāng)于說了蔗包,“現(xiàn)在停止這個(gè)方法秉扑,然后在下一幀中從這里重新開始!”调限。

注意:用0或者null來yield的意思是告訴協(xié)程等待下一幀舟陆,直到繼續(xù)執(zhí)行為止。當(dāng)然耻矮,同樣的你可以繼續(xù)yield其他協(xié)程秦躯,我會(huì)在下一個(gè)教程中講到這些。

一些例子

協(xié)程在剛開始接觸的時(shí)候是非常難以理解的裆装,無論是新手還是經(jīng)驗(yàn)豐富的程序員我都見過他們對(duì)于協(xié)程語句一籌莫展的時(shí)候踱承。因此我認(rèn)為通過例子來理解它是最好的方法倡缠,這里有一些簡(jiǎn)單的協(xié)程例子:

多次輸出“Hello”

記住,yield?return是“停止執(zhí)行方法茎活,并且在下一幀從這里重新開始”昙沦,這意味著你可以這樣做:


每一幀輸出“Hello”,無限循環(huán)妙色。桅滋。。

通過在一個(gè)while循環(huán)中使用yield身辨,你可以得到一個(gè)無限循環(huán)的協(xié)程丐谋,這幾乎就跟一個(gè)Update()循環(huán)等同。煌珊。号俐。


計(jì)時(shí)

...不過跟Update()不一樣的是,你可以在協(xié)程中做一些更有趣的事:


這個(gè)方法突出了協(xié)程一個(gè)非扯ㄢ郑酷的地方:方法的狀態(tài)被存儲(chǔ)了吏饿,這使得方法中定義的這些變量都會(huì)保存它們的值,即使是在不同的幀中蔬浙。還記得這個(gè)教程開始時(shí)那些煩人的計(jì)時(shí)器變量嗎猪落?通過協(xié)程,我們?cè)僖膊恍枰獡?dān)心它們了畴博,只需要把變量直接放到方法里面笨忌!

開始和終止協(xié)程

之前,我們已經(jīng)學(xué)過了通過StartCoroutine()方法來開始一個(gè)協(xié)程俱病,就像這樣:

StartCoroutine(Countdown());

如果我們想要終止所有的協(xié)程官疲,可以通過StopAllCoroutines()方法來實(shí)現(xiàn),它的所要做的就跟它的名字所表達(dá)的一樣亮隙。注意途凫,這只會(huì)終止在調(diào)用該方法的對(duì)象中(應(yīng)該是指調(diào)用這個(gè)方法的類吧)開始的協(xié)程,對(duì)于其他的MonoBehavior類中運(yùn)行的協(xié)程不起作用溢吻。

如果我們有以下這樣兩條協(xié)程語句:

StartCoroutine(FirstTimer());

StartCoroutine(SecondTimer());

那我們?cè)趺唇K止其中的一個(gè)協(xié)程呢维费?在這個(gè)例子里,這是不可能的促王,如果你想要終止某一個(gè)特定的協(xié)程掩完,那么你必須得在開始協(xié)程的時(shí)候?qū)⑺姆椒鳛樽址拖襁@樣:

StartCoroutine("FirstTimer");

StartCoroutine("SecondTimer");

StopCoroutine("FirstTimer");



第一個(gè)教程中硼砰,我們已經(jīng)了解了協(xié)程如何讓一個(gè)方法“暫颓遗睿”下來,并且讓它yield直到某些值到達(dá)我們給定的數(shù)值题翰;并且利用它恶阴,我們還創(chuàng)建了一個(gè)很棒的計(jì)時(shí)器系統(tǒng)诈胜。協(xié)程一個(gè)很重要的內(nèi)容是,它可以讓普通的程序(比方說一個(gè)計(jì)時(shí)器)很容易地被抽象化并且被復(fù)用冯事。

協(xié)程的參數(shù)

抽象化一個(gè)協(xié)程的第一個(gè)方法是給它傳遞參數(shù)焦匈,協(xié)程作為一個(gè)函數(shù)方法來說,它自然能夠傳遞參數(shù)昵仅。這里有一個(gè)協(xié)程的例子缓熟,它在特定的地方輸出了特定的信息。


嵌套的協(xié)程

在此之前摔笤,我們yield的時(shí)候總是用0(或者null)够滑,僅僅告訴程序在繼續(xù)執(zhí)行前等待下一幀。協(xié)程最強(qiáng)大的一個(gè)功能就是它們可以通過使用yield語句來相互嵌套吕世。

眼見為實(shí)彰触,我們先來創(chuàng)建一個(gè)簡(jiǎn)單的Wait()程序,不需要它做任何事命辖,只需要在運(yùn)行的時(shí)候等待一段時(shí)間就結(jié)束况毅。

IEnumerator Wait(floatduration)

{

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

? ? ? ? ? ? ? ? ? ? ? ? ? ?Yield ? return 0;

}

接下來我們要編寫另一個(gè)協(xié)程,如下:


第二個(gè)方法用了yield尔艇,但它并沒有用0或者null尔许,而是用了Wait()來yield,這相當(dāng)于是說终娃,“不再繼續(xù)執(zhí)行本程序母债,直到Wait程序結(jié)束”。

現(xiàn)在尝抖,協(xié)程在程序設(shè)計(jì)方面的能力要開始展現(xiàn)了。

控制對(duì)象行為的例子

在最后一個(gè)例子中迅皇,我們就來看看協(xié)程如何像創(chuàng)建方便的計(jì)時(shí)器一樣來控制對(duì)象行為昧辽。協(xié)程不僅僅可以使用可計(jì)數(shù)的時(shí)間來yield,它還能很巧妙地利用任何條件登颓。將它與嵌套結(jié)合使用搅荞,你會(huì)得到控制游戲?qū)ο鬆顟B(tài)的最強(qiáng)大工具。

運(yùn)動(dòng)到某一位置

對(duì)于下面這個(gè)簡(jiǎn)單腳本組件框咙,我們可以在Inspector面板中給targetPosition和moveSpeed變量賦值咕痛,程序運(yùn)行的時(shí)候,該對(duì)象就會(huì)在協(xié)程的作用下喇嘱,以我們給定的速度運(yùn)動(dòng)到給定的位置茉贡。


這樣,這個(gè)程序并沒有通過一個(gè)計(jì)時(shí)器或者無限循環(huán)者铜,而是根據(jù)對(duì)象是否到達(dá)指定位置來yield腔丧。

按指定路徑前進(jìn)

我們可以讓運(yùn)動(dòng)到某一位置的程序做更多放椰,不僅僅是一個(gè)指定位置,我們還可以通過數(shù)組來給它賦值更多的位置愉粤,通過MoveToPosition() 砾医,我們可以讓它在這些點(diǎn)之間持續(xù)運(yùn)動(dòng)。


我還加了一個(gè)布爾變量衣厘,你可以控制在對(duì)象運(yùn)動(dòng)到最后一個(gè)點(diǎn)時(shí)是否要進(jìn)行循環(huán)如蚜。

把Wait()程序加進(jìn)來,這樣就能讓我們的對(duì)象在某個(gè)點(diǎn)就可以選擇是否暫停下來影暴,就像一個(gè)正在巡邏的AI守衛(wèi)一樣错邦,這真是錦上添花啊坤检!

注意:

如果你剛接觸協(xié)程兴猩,我希望這兩個(gè)教程能幫助你了解它們是如何工作的,以及如何來使用它們早歇。以下是一些在使用協(xié)程時(shí)須謹(jǐn)記的其他注意事項(xiàng):

在程序中調(diào)用StopCoroutine()方法只能終止以字符串形式啟動(dòng)(開始)的協(xié)程倾芝;

多個(gè)協(xié)程可以同時(shí)運(yùn)行,它們會(huì)根據(jù)各自的啟動(dòng)順序來更新箭跳;

協(xié)程可以嵌套任意多層(在這個(gè)例子中我們只嵌套了一層)晨另;

如果你想讓多個(gè)腳本訪問一個(gè)協(xié)程,那么你可以定義靜態(tài)的協(xié)程谱姓;

協(xié)程不是多線程(盡管它們看上去是這樣的)借尿,它們運(yùn)行在同一線程中,跟普通的腳本一樣屉来;

如果你的程序需要進(jìn)行大量的計(jì)算路翻,那么可以考慮在一個(gè)隨時(shí)間進(jìn)行的協(xié)程中處理它們;

IEnumerator類型的方法不能帶ref或者out型的參數(shù)茄靠,但可以帶被傳遞的引用茂契;

目前在Unity中沒有簡(jiǎn)便的方法來檢測(cè)作用于對(duì)象的協(xié)程數(shù)量以及具體是哪些協(xié)程作用在對(duì)象上。

【來自作者:ChevyRay】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慨绳,一起剝皮案震驚了整個(gè)濱河市掉冶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脐雪,老刑警劉巖厌小,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異战秋,居然都是意外死亡璧亚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門脂信,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涨岁,“玉大人拐袜,你說我怎么就攤上這事∩倚剑” “怎么了蹬铺?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)秉撇。 經(jīng)常有香客問我甜攀,道長(zhǎng),這世上最難降的妖魔是什么琐馆? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任规阀,我火速辦了婚禮,結(jié)果婚禮上瘦麸,老公的妹妹穿的比我還像新娘谁撼。我一直安慰自己,他們只是感情好滋饲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布厉碟。 她就那樣靜靜地躺著,像睡著了一般屠缭。 火紅的嫁衣襯著肌膚如雪箍鼓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天呵曹,我揣著相機(jī)與錄音款咖,去河邊找鬼。 笑死奄喂,一個(gè)胖子當(dāng)著我的面吹牛铐殃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跨新,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼富腊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了玻蝌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤词疼,失蹤者是張志新(化名)和其女友劉穎俯树,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰盗,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡许饿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舵盈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陋率。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡球化,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓦糟,到底是詐尸還是另有隱情筒愚,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布菩浙,位于F島的核電站巢掺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劲蜻。R本人自食惡果不足惜陆淀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望先嬉。 院中可真熱鬧轧苫,春花似錦、人聲如沸疫蔓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳄袍。三九已至绢要,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拗小,已是汗流浹背重罪。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哀九,地道東北人剿配。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像阅束,于是被迫代替她去往敵國(guó)和親呼胚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容