谈一谈游戏AI - 行为树
鄭重說(shuō)明:本文適合對(duì)游戲開(kāi)發(fā)感興趣的小白初學(xué)者,本人力圖將事物用簡(jiǎn)單的語(yǔ)言表達(dá)清楚,但水平有限,能力一般,文章如有錯(cuò)漏之處,還望批評(píng)指正。
在本系列的前幾篇中,我們談到了談一談?dòng)螒駻I - 綜述 以及 談一談?dòng)螒駻I - 狀態(tài)機(jī)。今天我們來(lái)繼續(xù)聊一下另一種高級(jí)決策模型:行為樹(shù)。
一、為什么需要行為樹(shù)
有一種很重要的認(rèn)識(shí)事物的思維模型就是 why-what-how 模型,因此首先我們就要了解一下 why 的問(wèn)題,看看為什么需要行為樹(shù)這種高級(jí)決策模型。
在前面介紹狀態(tài)機(jī)時(shí),分層有限狀態(tài)機(jī)(HFSM) 讓我們能夠以相對(duì)直觀的方式,構(gòu)建相對(duì)復(fù)雜的行為集。
但是這個(gè)設(shè)計(jì)中存在一個(gè)小問(wèn)題:
以狀態(tài)轉(zhuǎn)換規(guī)則構(gòu)成的決策系統(tǒng)與當(dāng)前狀態(tài)強(qiáng)綁定在一起,這是一些游戲所需要的。
仔細(xì)使用狀態(tài)層次結(jié)構(gòu)可以減少重復(fù)轉(zhuǎn)換的數(shù)量,但有時(shí)候,我們的需求不一樣,可能無(wú)論處于哪個(gè)狀態(tài)或幾乎在所有狀態(tài),你的規(guī)則都要適用。打個(gè)比方,如果 AI對(duì)象(agent)的生命值降低到25%時(shí),則無(wú)論其當(dāng)前處于戰(zhàn)斗狀態(tài),空閑狀態(tài)、談話狀態(tài)或者其它任何狀態(tài),你可能都希望他逃跑。如果用狀態(tài)機(jī),你需要在每個(gè)狀態(tài)里都做這樣的判斷邏輯。將來(lái)新增每個(gè)狀態(tài)時(shí),都一定把這個(gè)條件添加進(jìn)去。
針對(duì)這種情況,一個(gè)理想的系統(tǒng)應(yīng)該將決策過(guò)程和狀態(tài)本身分離,這樣你只需要在一個(gè)位置進(jìn)行更改,仍然能夠正確轉(zhuǎn)換狀態(tài),這就是行為樹(shù)的應(yīng)用場(chǎng)景。
二、決策的行為樹(shù)表示
行為樹(shù)定義
在之前的講述游戲AI決策綜述的文章中,我們提到過(guò)一個(gè)球拍擊球的小游戲AI,用代碼 hardcode 的偽代碼如下:
every frame/update while the game is running:if the ball is to the left of the paddle:move the paddle leftelse if the ball is to the right of the paddle:move the paddle right其實(shí)這用一種稱為決策樹(shù)的圖表示起來(lái)更為直觀:
在每次決策循環(huán)執(zhí)行時(shí),只需要從最上面的 Start 開(kāi)始遍歷整棵樹(shù),遇到菱形的節(jié)點(diǎn),判斷其條件,然后選擇對(duì)應(yīng)的分支,直到葉子節(jié)點(diǎn)。
而行為樹(shù)是節(jié)點(diǎn)更豐富功能更強(qiáng)大的決策樹(shù):
黃色的裝飾器節(jié)點(diǎn),也稱為條件節(jié)點(diǎn),對(duì)應(yīng) hardcode 偽代碼中的 if 條件
藍(lán)色的組合節(jié)點(diǎn),可以是 Sequence 順序執(zhí)行節(jié)點(diǎn)和 Selector 選擇節(jié)點(diǎn),這也類似于程序邏輯中的與、或關(guān)系
綠色的行為節(jié)點(diǎn),是AI邏輯中需要具體實(shí)現(xiàn)的比較獨(dú)立的業(yè)務(wù)邏輯,如尋求幫助、巡邏、逃跑、攻擊等
行為樹(shù)的構(gòu)建
由于行為樹(shù)本身比較復(fù)雜,也由于組成樹(shù)的節(jié)點(diǎn)類型比較固定,往往利用圖形化的行為樹(shù)編輯器來(lái)構(gòu)建一整棵行為樹(shù),例如UE中的編輯器:
行為樹(shù)編輯器在使用時(shí),導(dǎo)出形式可以有多種,可以是生成對(duì)應(yīng)的程序代碼;也可以采取數(shù)據(jù)驅(qū)動(dòng)的方式,將關(guān)鍵信息數(shù)據(jù)化,然后放入行為樹(shù)執(zhí)行引擎來(lái)執(zhí)行。
三、行為樹(shù)的實(shí)現(xiàn)形式
實(shí)現(xiàn)行為樹(shù)有幾種不同的方式,但是本質(zhì)上是相同的,而且與前面提到的決策樹(shù)非常相似:從“根節(jié)點(diǎn)”開(kāi)始運(yùn)行,樹(shù)的節(jié)點(diǎn)用來(lái)表示決策或行動(dòng)。但還有一些關(guān)鍵區(qū)別:
節(jié)點(diǎn)的返回值有三種:成功(工作已完成),失敗(無(wú)法運(yùn)行)或正在運(yùn)行(仍在運(yùn)行并且尚未完全成功或失敗);
采取行動(dòng)的節(jié)點(diǎn)將返回正在運(yùn)行,表示行動(dòng)正在進(jìn)行;
之所以有正在運(yùn)行這種返回結(jié)果,是因?yàn)楹芏噙壿嬙谝淮螞Q策循環(huán)中是無(wú)法執(zhí)行完成的,可能跨越很多個(gè)決策循環(huán)周期。因此在遍歷這棵樹(shù)時(shí),繼續(xù)上次的節(jié)點(diǎn)邏輯。
還有一種行為樹(shù)的形式是前面一種形式的變形。筆者之前所在的項(xiàng)目使用過(guò)以下編輯形式:
可以看到這種方式?jīng)]有所謂的選擇節(jié)點(diǎn),其條件邏輯和行為邏輯是并行的關(guān)系,在考察每個(gè)節(jié)點(diǎn)的時(shí)候,會(huì)考慮其對(duì)應(yīng)的條件組是否滿足,條件組本身又可以包括與、或的嵌套邏輯組合。
四、行為樹(shù)的特點(diǎn)
通過(guò)前面的介紹,我們可以總結(jié)出行為樹(shù)的幾個(gè)優(yōu)點(diǎn):
常用于比較復(fù)雜的邏輯
比較直觀,邏輯很清晰
無(wú)狀態(tài),每次都從root開(kāi)始,一幀運(yùn)行不需要知道上一幀是什么狀態(tài)
樹(shù)的分支之間互不關(guān)心、互不影響,只有樹(shù)形的父子層級(jí)關(guān)系,子節(jié)點(diǎn)之間互相沒(méi)有聯(lián)系。因此很靈活,新增、擴(kuò)展、刪除分支都不影響其他的,很方便。而對(duì)比來(lái)看,狀態(tài)機(jī)互相之間是需要知道彼此的存在的,還有轉(zhuǎn)換,經(jīng)常耦合在一起
程序可以和策劃一起配合使用。
它也有很明顯的缺點(diǎn):
每次執(zhí)行都要遍歷整棵樹(shù),效率是個(gè)大問(wèn)題,執(zhí)行時(shí)間比狀態(tài)機(jī)要長(zhǎng)很多
無(wú)狀態(tài),相當(dāng)于沒(méi)有記憶
關(guān)于沒(méi)有記憶帶來(lái)的問(wèn)題,舉個(gè)例子來(lái)說(shuō)明:
一個(gè)農(nóng)民(NPC AI)要收割作物,敵人出現(xiàn)了,農(nóng)民逃跑,逃出了距離敵人的一定范圍之后,又回去收割作物,走到敵人的范圍又逃出,這樣來(lái)回往復(fù),是一個(gè)bug,可以根據(jù)情況來(lái)寫代碼避免,但解決方式不夠優(yōu)雅。
五、解決行為樹(shù)的問(wèn)題
上下文保存
很顯然,狀態(tài)機(jī)需要保存上下文來(lái)解決 AI 行為樹(shù)沒(méi)有記憶的問(wèn)題。
自定義狀態(tài)
很多游戲有自己自定義的狀態(tài)保存結(jié)構(gòu),一個(gè)例子如:
struct AI_RUNTIME_DATA {// 定時(shí) timer// 通用信息,如動(dòng)態(tài)思考間隔、自定義tag標(biāo)記// 移動(dòng)相關(guān)信息,如坐標(biāo)、速度、移動(dòng)技能等// 追擊目標(biāo),射擊信息等 }黑板
更通用一些的做法是一種叫做 “黑板” 的做法,即不關(guān)心狀態(tài)數(shù)據(jù)的組織形式,統(tǒng)一以key-value 的形式來(lái)保存數(shù)據(jù),這有點(diǎn)類似于數(shù)據(jù)存儲(chǔ)領(lǐng)域 NoSQL 的做法:以Key區(qū)分不同的上下文數(shù)據(jù),value為用戶自定義的二進(jìn)制數(shù)據(jù),這樣使得數(shù)據(jù)的保存通用化。
黑板還可能分為本地黑板或者全局黑板。
本地黑板:作用域限定為特定的狀態(tài)機(jī)/行為樹(shù)層級(jí)內(nèi)部
全局黑板:作用域?yàn)檎麄€(gè)游戲邏輯內(nèi)
UE4中就內(nèi)置了黑板的功能,方便行為樹(shù)使用時(shí)候的狀態(tài)保存。
效率優(yōu)化
另一個(gè)需要解決的問(wèn)題就是行為樹(shù)的執(zhí)行效率問(wèn)題。
降低更新頻率
對(duì)于大量AI運(yùn)行的情況,例如服務(wù)器中存在的大量NPC,如果需要每幀都去做一次 Sense/Think/Act 決策行為,對(duì)應(yīng)到行為樹(shù)上就是從 Root 節(jié)點(diǎn)開(kāi)始掃描整棵行為樹(shù),這勢(shì)必帶來(lái)大量的性能消耗。
如果不是每幀都去遍歷,而是用定時(shí)器,定時(shí)思考是一種可以考慮的優(yōu)化方式,其本質(zhì)是降低行為樹(shù)的更新決策頻率。
定時(shí)思考的問(wèn)題是不夠?qū)崟r(shí),因此也要同時(shí)添加對(duì)外部事件的響應(yīng),否則AI就會(huì)顯得很傻。
例如 FF15 中添加事件響應(yīng):
行為樹(shù)中使用Active Selector節(jié)點(diǎn),當(dāng)指定的事件響應(yīng)(OnMessage)時(shí),打斷當(dāng)前行為并且重置狀態(tài)
行為樹(shù)與狀態(tài)機(jī)組合使用
行為樹(shù)本身遍歷是非常耗時(shí)的,而狀態(tài)機(jī)則效率較高,因此我們可以將行為樹(shù)結(jié)合狀態(tài)機(jī)一起使用:
只有最復(fù)雜的部分使用行為樹(shù),其他情況下使用狀態(tài)機(jī)保持住當(dāng)前狀態(tài),而不必用行為樹(shù)頻繁選擇分支。
例如 FF15 中的一個(gè)示例:
上圖只有最復(fù)雜的戰(zhàn)斗邏輯使用了行為樹(shù),其他情況下可以嵌套狀態(tài)機(jī)來(lái)使用。
代碼實(shí)現(xiàn)優(yōu)化
樹(shù)這種數(shù)據(jù)結(jié)構(gòu)在實(shí)現(xiàn)時(shí),往往使用指針來(lái)表示父子節(jié)點(diǎn)之間的關(guān)系,這對(duì)于 CPU 在執(zhí)行時(shí)是不夠友好的。
可以考慮將緩存不友好的樹(shù)遍歷,改造成緩存友好的數(shù)組遍歷,以空間換時(shí)間來(lái)提高執(zhí)行效率。
小結(jié)
在本文,我們談了行為樹(shù)的多個(gè)方面,包括:
引入行為樹(shù)的原因
行為樹(shù)的定義、構(gòu)建以及具體的實(shí)現(xiàn)形式
行為樹(shù)的特點(diǎn)以及解決行為樹(shù)問(wèn)題的幾個(gè)思路
總結(jié)
以上是生活随笔為你收集整理的谈一谈游戏AI - 行为树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 手机使用linux教程,通过手机访问Li
- 下一篇: RTX 30系列性能≥2倍图灵GPU!A