行為樹實(shí)戰(zhàn)訓(xùn)練營-行為樹詳解、實(shí)戰(zhàn)

前言
今天給大家分享的是行為樹實(shí)戰(zhàn)訓(xùn)練營。我們會(huì)以空洞騎士的BOSS AI為例,為大家介紹行為樹的系統(tǒng)實(shí)現(xiàn)
行為樹,在游戲行業(yè)當(dāng)中是我們實(shí)現(xiàn)游戲AI的一種方式。除此之外,我們還可以使用最簡(jiǎn)單的如:switch case、 if else實(shí)現(xiàn)最基本的游戲AI;復(fù)雜一點(diǎn),我們可以使用狀態(tài)機(jī)、分層狀態(tài)機(jī)來實(shí)現(xiàn)游戲的AI
行為術(shù)在游戲AI的實(shí)踐實(shí)現(xiàn)上,有它自己的優(yōu)勢(shì)。我會(huì)給大家分別介紹,各種游戲AI的實(shí)現(xiàn)方式。給大家做一個(gè)清晰的比較,幫助大家去選擇適合自己游戲項(xiàng)目的游戲AI實(shí)現(xiàn)方式。
版權(quán)聲明
本文為“優(yōu)夢(mèng)創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明
點(diǎn)贊、關(guān)注、分享可免費(fèi)獲得配套學(xué)習(xí)資源
行為樹詳解

行為樹:以模塊化方式描述任務(wù)之間的切換

所謂的行為樹,就是把一個(gè)怪物的行為拆分成若干個(gè)子行為。比如說,一個(gè)怪物的行為,拆分成攻擊和巡邏等
詳細(xì)的案例分析,請(qǐng)參考行為樹實(shí)戰(zhàn)訓(xùn)練營視頻公開課
行為樹的節(jié)點(diǎn)類型

行為樹是由一個(gè)一個(gè)的節(jié)點(diǎn)構(gòu)成的。我們對(duì)每一個(gè)節(jié)點(diǎn)賦予一定的功能。行為樹的節(jié)點(diǎn)可以分成兩大類:
控制節(jié)點(diǎn)
一棵行為樹,所有的控制節(jié)點(diǎn)都是這棵行為樹上的做非葉子節(jié)點(diǎn)
把行為樹看成是一棵樹,頂端的節(jié)點(diǎn)是樹根,所有下方的綠色節(jié)點(diǎn)可以看作是樹枝或者樹干,灰色節(jié)點(diǎn)是葉子節(jié)點(diǎn),所有的樹枝或者是樹干節(jié)點(diǎn),我們都叫它控制節(jié)點(diǎn)
控制節(jié)點(diǎn)在行為樹里面又可以分成兩類,一類叫做組合節(jié)點(diǎn),另外一類叫做條件節(jié)點(diǎn)
動(dòng)作節(jié)點(diǎn):
葉子節(jié)點(diǎn)相當(dāng)于一棵樹上的樹葉,我們知道樹葉是不會(huì)再分叉,它是這個(gè)整棵樹的最末梢的節(jié)點(diǎn)
葉子節(jié)點(diǎn)代表了程序當(dāng)中一個(gè)個(gè)的動(dòng)作
行為樹要點(diǎn)

行為樹是由節(jié)點(diǎn)構(gòu)成的,每個(gè)節(jié)點(diǎn)要想運(yùn)作起來,它都必須要要有一個(gè)節(jié)點(diǎn)的狀態(tài),每個(gè)節(jié)點(diǎn)都必須處于處于三個(gè)狀態(tài)之一:
Running,表示程序正在執(zhí)行這個(gè)節(jié)點(diǎn)
Success,每個(gè)節(jié)點(diǎn)它可能會(huì)有一個(gè)執(zhí)行結(jié)束,比如巡邏狀態(tài),目標(biāo)從a點(diǎn)走到B點(diǎn),如果已經(jīng)走到B點(diǎn),那么這個(gè)狀態(tài)就是處于一個(gè)成功的狀態(tài)
Failure,有一些節(jié)點(diǎn)是用來執(zhí)行判定的。它可以判定當(dāng)前這個(gè)角色是否看見敵人,如果看見,就是成功;如果沒看見,就是處于失敗狀態(tài)
在真正的開發(fā)行為樹的時(shí)候,我們通常不會(huì)直接使用那些現(xiàn)成的行為樹節(jié)點(diǎn),而是要對(duì)行為節(jié)點(diǎn)進(jìn)行定制,在我們的訓(xùn)練營里面會(huì)帶領(lǐng)大家去定制一個(gè)一個(gè)的行為樹節(jié)點(diǎn)
節(jié)點(diǎn)可以進(jìn)行組合,比如要完成一個(gè)NPC的一個(gè)攻擊的AI
它需要先有一個(gè)檢測(cè)節(jié)點(diǎn)檢測(cè)附近是否有可以攻擊的目標(biāo)
當(dāng)出現(xiàn)目標(biāo),需要追擊這個(gè)目標(biāo),當(dāng)目標(biāo)處于可攻擊范圍,要對(duì)目標(biāo)釋放技能
一個(gè)組合節(jié)點(diǎn),它包括了檢測(cè)目標(biāo),移動(dòng)到目標(biāo),實(shí)施攻擊,三個(gè)子節(jié)點(diǎn)構(gòu)成
? ?3. 組合節(jié)點(diǎn)是怎樣執(zhí)行的?
組合節(jié)點(diǎn)執(zhí)行的順序:
從左到右
Priority/Random ?Selector除外
行為樹常用控制節(jié)點(diǎn)簡(jiǎn)介


順序節(jié)點(diǎn)
每一個(gè)節(jié)點(diǎn),它都有運(yùn)行成功或失敗的狀態(tài),如果第一個(gè)節(jié)點(diǎn)運(yùn)行成功了,它就會(huì)按照順序去執(zhí)行第二個(gè)節(jié)點(diǎn),如果第二個(gè)節(jié)點(diǎn)也運(yùn)行成功了,它就會(huì)執(zhí)行第三個(gè)節(jié)點(diǎn),如果這三個(gè)節(jié)點(diǎn)都執(zhí)行成功了,那么就說明這個(gè)順序節(jié)點(diǎn)執(zhí)行成功
順序節(jié)點(diǎn)的應(yīng)用
當(dāng)要實(shí)現(xiàn)的邏輯需要按照順序執(zhí)行時(shí)
順序節(jié)點(diǎn)的邏輯關(guān)系類似于C/C++程序里面的與運(yùn)算
? ?2. 選擇節(jié)點(diǎn)
相當(dāng)于邏輯運(yùn)算的或運(yùn)算
如果選擇節(jié)點(diǎn)當(dāng)中的某個(gè)節(jié)點(diǎn)執(zhí)行失敗了,它會(huì)不會(huì)造成選擇節(jié)點(diǎn)失???
不會(huì)造成選擇節(jié)點(diǎn)失敗
如果第一個(gè)節(jié)點(diǎn)執(zhí)行失敗了,它會(huì)繼續(xù)運(yùn)行第二個(gè)節(jié)點(diǎn);第二個(gè)節(jié)點(diǎn)如果運(yùn)行失敗,也不會(huì)造成選擇節(jié)點(diǎn)失敗,它會(huì)運(yùn)行第三個(gè)節(jié)點(diǎn)
三個(gè)節(jié)點(diǎn)里面,當(dāng)有一個(gè)節(jié)點(diǎn)運(yùn)行成功,就說明這個(gè)選擇節(jié)點(diǎn)的運(yùn)行是成功的
? 3. 并行節(jié)點(diǎn)
程序當(dāng)中同時(shí)執(zhí)行多個(gè)行為的行為就是并行行為,這個(gè)時(shí)候可以用定型節(jié)點(diǎn)進(jìn)行執(zhí)行。當(dāng)有N個(gè)子節(jié)點(diǎn)時(shí)可以通過添加一個(gè)并行節(jié)點(diǎn),讓他們并行執(zhí)行
? 4. 裝飾器節(jié)點(diǎn)
裝飾節(jié)點(diǎn),可以理解成一個(gè)修改節(jié)點(diǎn)。它會(huì)對(duì)一個(gè)節(jié)點(diǎn)的行為進(jìn)行修改
類似于程序當(dāng)中的否運(yùn)算,比如原本一個(gè)節(jié)點(diǎn)的運(yùn)行結(jié)果是成功,當(dāng)給它做一個(gè)修飾節(jié)點(diǎn)之后,可以反轉(zhuǎn)節(jié)點(diǎn),把一個(gè)運(yùn)行成功的節(jié)點(diǎn)反轉(zhuǎn)成運(yùn)行失敗
裝飾節(jié)點(diǎn)除了可以反轉(zhuǎn)節(jié)點(diǎn)外,還可以重復(fù)執(zhí)行節(jié)點(diǎn),重新嘗試節(jié)點(diǎn),然后超時(shí)節(jié)點(diǎn),強(qiáng)制失敗節(jié)點(diǎn)
行為樹實(shí)戰(zhàn)

請(qǐng)用行為樹實(shí)現(xiàn)以下敵人AI

當(dāng)敵人看見玩家:
敵人進(jìn)入追擊狀態(tài)
當(dāng)敵人看不見玩家:
敵人進(jìn)入巡邏狀態(tài)
應(yīng)該如何實(shí)現(xiàn)?
首先Entry表示敵人狀態(tài)機(jī)的入口,然后進(jìn)入到這個(gè)的selector
選擇器,相當(dāng)于或運(yùn)算,如果前面的節(jié)點(diǎn)執(zhí)行失敗,那么就執(zhí)行后面的節(jié)點(diǎn),不會(huì)造成整個(gè)這個(gè)節(jié)點(diǎn)全部執(zhí)行失敗
節(jié)點(diǎn)的執(zhí)行是按照優(yōu)先級(jí),從左往右排部的,首先它會(huì)執(zhí)行左邊Sequence順序節(jié)點(diǎn)
順序節(jié)點(diǎn)必須要一個(gè)一個(gè)執(zhí)行,前面的執(zhí)行成功才執(zhí)行,如果前面的執(zhí)行不成功,那么這個(gè)順序節(jié)點(diǎn)就執(zhí)行失敗
數(shù)據(jù)節(jié)點(diǎn)執(zhí)行失敗,那么選擇器節(jié)點(diǎn)就會(huì)選擇另外一個(gè)分支來進(jìn)行執(zhí)行。
敵人的行為數(shù)假設(shè)為行為數(shù),那么程序會(huì)怎么走呢?
首先選擇器開始,走左邊分支走到順序節(jié)點(diǎn),判定是否發(fā)現(xiàn)敵人,如果發(fā)現(xiàn)了,就會(huì)順序的執(zhí)行追擊功能
如果沒有發(fā)現(xiàn)敵人,那么這個(gè)順序節(jié)點(diǎn)就執(zhí)行失敗了,執(zhí)行失敗以后就返回回去,然后選擇器就會(huì)選擇巡邏狀態(tài)來進(jìn)行執(zhí)行
2. 行為樹看上去一切都很完美,是否是這樣?
如果在這個(gè)行為書里面,我們不做特殊處理,那么當(dāng)前面Sequence順序節(jié)點(diǎn)分支沒有發(fā)現(xiàn)這個(gè)敵人,那么sequence這個(gè)分支執(zhí)行失敗了。那么選擇器就會(huì)選擇右邊節(jié)點(diǎn)進(jìn)入巡邏節(jié)點(diǎn),進(jìn)入巡邏節(jié)點(diǎn)以后,它就會(huì)卡死在這個(gè)狀態(tài)永遠(yuǎn)跳不出
即使在巡邏狀態(tài),也要執(zhí)行左邊這個(gè)分支。發(fā)現(xiàn)敵人節(jié)點(diǎn)的檢測(cè)工作要一直執(zhí)行,并且這個(gè)節(jié)點(diǎn)狀態(tài)為true的時(shí)候,按順序能夠把巡邏節(jié)點(diǎn)給中斷掉。讓它中斷掉再切回到順序節(jié)點(diǎn),發(fā)現(xiàn)敵人以后進(jìn)入到追擊狀態(tài)
完美的行為樹
必須能在巡邏和追擊節(jié)點(diǎn)之間正常的切換
節(jié)點(diǎn)之間的切換需要利用行為樹組合節(jié)點(diǎn)的ConditionAbort,中斷機(jī)制
組合節(jié)點(diǎn)的中斷機(jī)制

四種中斷類型
None:不會(huì)產(chǎn)生中斷
Self:當(dāng)前組合任務(wù)還沒運(yùn)行完,所有子任務(wù)的OnUpdate會(huì)繼續(xù)運(yùn)行,檢測(cè)是否發(fā)生中斷
Lower Priority:同層且比自身優(yōu)先級(jí)低級(jí)的任務(wù)還沒運(yùn)行完,所有子任務(wù)的OnUpdate會(huì)繼續(xù)運(yùn)行,檢測(cè)是否發(fā)生中斷
Both:Self+Lower Priority
請(qǐng)用行為樹實(shí)現(xiàn)以下敵人AI

需要在行為樹的Sequence節(jié)點(diǎn)設(shè)置打斷,并且打斷類型是Both
設(shè)置Both后就能滿足行為樹在追擊和巡邏之間切換。具體可以分成兩種情況來討論:
看見敵人時(shí):
行為樹會(huì)執(zhí)行黃色的分支,選擇器選擇左邊Sequence節(jié)點(diǎn),因?yàn)榘l(fā)現(xiàn)敵人因此進(jìn)入到追擊狀態(tài)。
由于Self可以打斷自身,它會(huì)一直不停的監(jiān)控這個(gè)發(fā)現(xiàn)敵人這個(gè)條件節(jié)點(diǎn)。當(dāng)這個(gè)條件節(jié)點(diǎn)為假時(shí),Sequence節(jié)點(diǎn)可以打斷自身的追擊節(jié)點(diǎn)的執(zhí)行,使Sequence節(jié)點(diǎn)進(jìn)入失敗狀態(tài),從而就進(jìn)入到巡邏狀態(tài)
看不見敵人時(shí):
由于看不見敵人,發(fā)現(xiàn)敵人就為假,會(huì)造成Sequence失敗,于是進(jìn)入到巡邏狀態(tài)
由于Sequence節(jié)點(diǎn)設(shè)置了Both,因此既能監(jiān)控也可以打斷自身的子節(jié)點(diǎn)追擊,同時(shí)還可以打斷比它低優(yōu)先級(jí)的巡邏
節(jié)點(diǎn)會(huì)持續(xù)的監(jiān)控是否會(huì)發(fā)現(xiàn)敵人,當(dāng)敵人被發(fā)現(xiàn)的時(shí),它會(huì)打斷sequence右邊比它低優(yōu)先級(jí)的巡邏節(jié)點(diǎn)從而進(jìn)入到追擊狀態(tài)
3. 中斷類型設(shè)置Both后,左側(cè)分支在看見敵人的情況下可以打斷追擊進(jìn)入巡邏;在看不見的情況下可以打斷巡邏,進(jìn)入追擊,這樣就能實(shí)現(xiàn)一個(gè)完美的行為數(shù)
小測(cè)驗(yàn)

若將Sequence節(jié)點(diǎn)的中斷類型設(shè)置為L(zhǎng)ower Priority會(huì)有什么問題?
這個(gè)問題就不提供答案了,如果大家有什么不明白地方可以加一下文末的Alice老師,然后進(jìn)群討論,或者加我為好友討論問題都是可以的
注意

Conditional Abort,只能由條件節(jié)點(diǎn)發(fā)起
Conditional Abort可以被任何的組合節(jié)點(diǎn)獲取
行為樹的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)
易于理解并且可以使用可視化編輯器進(jìn)行創(chuàng)建
很大的靈活性,非常強(qiáng)大,并且非常容易對(duì)其進(jìn)行更改
能夠創(chuàng)建由簡(jiǎn)單任務(wù)組成的非常復(fù)雜的任務(wù),而不必要擔(dān)心簡(jiǎn)單任務(wù)是如何實(shí)現(xiàn)的
每個(gè)行為邏輯互不影響,行為模塊間的耦合度相對(duì)較低
2. 缺點(diǎn)
行為樹的選擇并不是最優(yōu)的,結(jié)果也不一定是我們想要的。而且決策每次都要從根部往下判斷行為節(jié)點(diǎn),比狀態(tài)機(jī)要耗費(fèi)時(shí)間。每次決策都要經(jīng)過大量的條件判斷語句,會(huì)變得非常慢
如果AI對(duì)象就只有3個(gè)或以下數(shù)量的狀態(tài),用行為樹設(shè)計(jì)的話,計(jì)算量會(huì)更大,反而會(huì)更耗費(fèi)性能
面試與進(jìn)階

當(dāng)面對(duì)一個(gè)客戶端開發(fā),包括服務(wù)器開發(fā),因?yàn)橛螒虻腁I也可以寫在服務(wù)器上
如果是狀態(tài)同步的游戲,寫在服務(wù)器上,如果是真同步的游戲,是寫在客戶端上面
關(guān)于狀態(tài)同步和幀同步的內(nèi)容,我們的V I P課程里主程進(jìn)價(jià)的項(xiàng)目框架是同時(shí)支持這兩種數(shù)據(jù)同步模式的教學(xué)
2. 在我們進(jìn)行面試和這個(gè)進(jìn)階的商業(yè)項(xiàng)目的應(yīng)用開發(fā)的時(shí)候,我們需要去根本從根本上去理解底層,夠熟練的運(yùn) ?用行為樹:
理解行為樹底層原理
能熟練運(yùn)用行為樹
能熟練拓展行為樹節(jié)點(diǎn)
能熟練增加行為樹節(jié)點(diǎn)
閱讀過至少一種行為樹系統(tǒng)源碼
能夠自己實(shí)現(xiàn)行為樹框架
基于行為樹的AI框架
3. 行為樹的底層原理,我會(huì)在我們的VIP課程里面做行為樹的源碼解析,感興趣的同學(xué)可以添加文末Alice老師的聯(lián)系方式,并加入到我們的VIP課程當(dāng)中去
寫在最后
本文為“優(yōu)夢(mèng)創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明
更多學(xué)習(xí)資源請(qǐng)私信我獲?。ㄆ髽I(yè)級(jí)性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項(xiàng)目實(shí)戰(zhàn)/每周直播/一對(duì)一指導(dǎo))
點(diǎn)贊、關(guān)注、分享可免費(fèi)獲得配套學(xué)習(xí)資源