我們知道腳本都是繼承自MonoBehaviour類,而其中的Update方法里面放置了大部分的游戲邏輯處理代碼。Update方法是游戲循環(huán)的每一幀都去執(zhí)行,這就要求我們的代碼“無時(shí)無刻”不在處理所有的可能發(fā)生的情況,并做出相應(yīng)的處理。如果我們想要完成“一段時(shí)間”的邏輯代碼,例如在游戲中發(fā)射一顆子彈,這個(gè)過程相對于游戲無限循環(huán)的時(shí)間來說,非常的短暫,如果我們在Update中去完成這樣的邏輯,需要根據(jù)時(shí)間來進(jìn)行判斷,顯然這個(gè)完成過程非常的復(fù)雜。這個(gè)時(shí)候,Unity給我們提供了協(xié)程,從字面意義上理解就是協(xié)助程序的意思,類似于“線程”,幫助我們在主任務(wù)進(jìn)行的同時(shí),需要一些分支任務(wù)配合工作來達(dá)到最終的效果。但是,協(xié)程不是線程,協(xié)程依舊是在主線程中進(jìn)行。Unity中的協(xié)程由協(xié)程函數(shù)和協(xié)程調(diào)度器兩部分構(gòu)成。通過關(guān)鍵字IEnumerator來定義一個(gè)協(xié)程(迭代方法),然后再程序中通過StartCoroutine來開啟一個(gè)協(xié)程。
接下來,我們創(chuàng)建一個(gè)“SampleScene8”的新創(chuàng)景,然后創(chuàng)建一個(gè)“Cube”和一個(gè)“CubeCoroutine.cs”的腳本文件,并將他們附加在一起。接下來,我們就在腳本文件中定義一個(gè)協(xié)程方法,如下所示
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeCoroutine : MonoBehaviour
{
// Update is called once per frame
void Update()
{
// 按下空格鍵
if (Input.GetKeyDown(KeyCode.Space))
{
// 啟動協(xié)程
StartCoroutine("MoveTest");
}
}
// 定義協(xié)程方法
IEnumerator MoveTest()
{
transform.Translate(new Vector3(1, 0, 0));
yield return null;
transform.Translate(new Vector3(1, 0, 0));
yield return null;
}
}
在上面的代碼中,我們使用IEnumerator MoveTest來定義協(xié)程方法,方法名稱為MoveTest。在協(xié)程方法中,我們讓Cube沿X軸移動兩次,每次移動1個(gè)單位長度。然后我們在Update方法中監(jiān)聽空格鍵的按下,使用StartCoroutine方法來啟動協(xié)程,方法參數(shù)就是協(xié)程方法名稱。接下來我們就Play當(dāng)工程,查看運(yùn)行效果
當(dāng)我們按下一次空格的時(shí)候,Cube會移動兩次,每次移動1個(gè)單位長度,由于代碼執(zhí)行太快,因此我們看不到兩次移動之間的間隔。但是從Inspector檢視面板中的X數(shù)值可以看到,我們每次按下空格的時(shí)候,Cube的確是移動了兩個(gè)單位的長度。
當(dāng)然,這樣簡單的代碼并不能展示協(xié)程的強(qiáng)大之處。我們先從協(xié)程方法里面的return解釋一下。在普通方法里面,我們經(jīng)常使用return方法來返回方法的執(zhí)行的結(jié)果值,但是在協(xié)程方法里面,這個(gè)return并不是返回結(jié)果值。上文代碼中的“yield return null;”表示暫停協(xié)程等待下一幀繼續(xù)執(zhí)行。這樣的返回設(shè)計(jì),讓我們能夠控制在指定數(shù)量的幀中來執(zhí)行不同的代碼,而不是在所有的幀中執(zhí)行復(fù)雜的條件代碼。什么意思呢?
transform.Translate(new Vector3(1, 0, 0));
yield return null;
transform.Translate(new Vector3(1, 0, 0));
yield return null;
我們的協(xié)程方法執(zhí)行后,會在Update方法中執(zhí)行transform.Translate(new Vector3(1, 0, 0))代碼,也就是讓Cueb沿X軸移動1個(gè)單位的距離。然后使用yield return null停止協(xié)程方法等待下一次Update方法。下一次Update方法執(zhí)行后,就會執(zhí)行協(xié)程中第二個(gè)transform.Translate(new Vector3(1, 0, 0))代碼,繼續(xù)讓Cueb沿X軸移動1個(gè)單位的距離。然后使用yield return null停止協(xié)程方法。至此,協(xié)程方法執(zhí)行完畢。
我們回頭思考一下發(fā)射子彈的協(xié)程該如何實(shí)現(xiàn)呢?當(dāng)我們按下空格鍵代表發(fā)射動作的時(shí)候,我們可以啟動一個(gè)子彈飛行協(xié)程,在這個(gè)協(xié)程方法中,我們可以根據(jù)指定的速度和射程來移動子彈,協(xié)程結(jié)束也就代表子彈的飛行邏輯結(jié)束。但是,這個(gè)需要借助精確的時(shí)間來實(shí)現(xiàn)。此時(shí),我們可以借助使用“yield return new WairForSeconds(時(shí)間);”來表示等待規(guī)定時(shí)間后繼續(xù)執(zhí)行,這樣讓我們從時(shí)間角度出發(fā)來執(zhí)行我們的代碼,而不用考慮他們到底在那一幀中去執(zhí)行。我們稍微改動我們的代碼。
// 定義協(xié)程方法
IEnumerator MoveTest()
{
transform.Translate(new Vector3(1, 0, 0));
//yield return null;
yield return new WaitForSeconds(1.0f);
transform.Translate(new Vector3(1, 0, 0));
yield return null;
}
說白了,我們讓兩次移動間隔1秒鐘。接下來,我們在來Play當(dāng)前工程,查看運(yùn)行效果
這次當(dāng)我們按下空格鍵的時(shí)候,兩次移動之間由于間隔了1秒鐘,因此我們看的比較清楚了。從左邊的Inspector檢視視圖中我們也能夠看到X從0變到1,再變到2的過程了。接下來,我們回到子彈發(fā)射的問題上來。注意,子彈的速度我們可以固定為一個(gè)數(shù)值,然后射擊的距離也可以固定為一個(gè)數(shù)值。那么,在那個(gè)時(shí)間點(diǎn),子彈飛行到哪里,我們就能夠計(jì)算出來了。如果覺得1秒鐘不精確的話,我們可以減小這個(gè)時(shí)間,這樣子彈位置的更新就比較連續(xù)了。最后,協(xié)程方法也可以定義形參,那么在使用StartCoroutine調(diào)用的時(shí)候,可以不使用字符串而直接調(diào)用方法。代碼如下:
// Start is called before the first frame update
void Start()
{
StartCoroutine(ParamTest(100));
}
// 定義包含參數(shù)的協(xié)程方法
IEnumerator ParamTest(int x)
{
Debug.Log(x);
yield return null;
}
運(yùn)行結(jié)果如下:
注意:可以使用 StopCoroutine 和 StopAllCoroutines 來停止協(xié)程。 當(dāng)用 SetActive(false) 禁用某個(gè)協(xié)程所附加到的游戲?qū)ο髸r(shí),該協(xié)程也將停止。調(diào)用 Destroy銷毀游戲?qū)ο髸r(shí)候,也會停止自身的協(xié)程。但通過在 MonoBehaviour 實(shí)例上將 enabled 設(shè)置為 false 來禁用 MonoBehaviour 時(shí),協(xié)程不會停止。
總結(jié):協(xié)程只啟動一次。而后Unity會在后續(xù)的update中執(zhí)行協(xié)程中的循環(huán)體。有多次循環(huán),就會在多少次update去分別執(zhí)行循環(huán)體代碼。說白了,協(xié)程就是將一個(gè)過程化的行為分解到了update方法中執(zhí)行。Unity中的協(xié)程可以有兩種用途:第一,延遲調(diào)用;第二,分解操作,把一個(gè)過程分解執(zhí)行。例如,敵人死亡后淡出消失,改變材質(zhì)顏色透明度即可,讓透明度由1變成0,這是一個(gè)過程,可以使用協(xié)程來實(shí)現(xiàn)。再比如,我們可以通過協(xié)程進(jìn)行尋路A點(diǎn),B點(diǎn),C端(巡邏)。其實(shí)現(xiàn)方式就是協(xié)程嵌套協(xié)程,一個(gè)協(xié)程完成從一個(gè)點(diǎn)A移動到另一個(gè)點(diǎn)B后,本協(xié)程結(jié)束后再開啟下一個(gè)協(xié)程,然后從當(dāng)前點(diǎn)B在繼續(xù)移動到下一個(gè)點(diǎn)C。文章來源:http://www.zghlxwxcb.cn/news/detail-448795.html
本課程涉及的內(nèi)容已經(jīng)共享到百度網(wǎng)盤:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id文章來源地址http://www.zghlxwxcb.cn/news/detail-448795.html
到了這里,關(guān)于第十八章 Unity 協(xié)程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!