AI邏輯實現-選擇行為樹還是狀態機?
關注AI的朋友可能會看過賴勇浩翻譯的《有限狀態機時代終結的10大理由》 ,里面談到了狀態機的諸多弊端。同時在ppt(附上下載地址)中述說了行為樹的諸多優點,這里就不在贅述了。更多得是想總結一下自己玩了一陣子行為樹后的一些實踐體會。
個人體會:
狀態機來實現AI更符合我們思維的朴素表達,我想任何一個有經驗的coder都能直觀得去寫一個自己的AI狀態機。它用於一些簡單的ai其實是沒有大問題的,(搜索敵人,靠近,攻擊,死亡)用狀態機其實更加便捷。但是面對一些復雜的ai邏輯實現就會顯得比較繁雜。同時,當需要對現有行為邏輯進行擴展的時候,代碼上就會顯得比較吃力,因為要維護的狀態量會成倍增加。
行為樹,實現AI的過程更加得有技巧,框架設計者較為全面考慮了我們可能會遇到的種種情況,把每種情況都抽象成了一個類型的節點,而我們要做的就是按照規范去寫節點,然后把節點連接成一顆行為樹。更加得具有面向對象的味道,行為模塊間的藕合度相對較低。
舉個粗糙的例子來比較一下兩者的不同:
AI行為:吃飯 睡覺 打豆豆(很消耗體力和腦力的;)
1.打豆豆 HP -= 5 / 秒 MP -= 3 / 秒
2.吃飯 HP += 10/秒 MP -= 1 / 秒
3.睡覺 MP += 15/秒 HP -= 2/秒
4.吃飯和睡覺是不可打斷的動作(pending),必須執行到吃飽(HP = 100) or 睡飽(MP = 100)
5.打豆豆是瞬發動作,每幀都可以執行一次
狀態機的實現邏輯圖:
行為樹的實現邏輯圖:
其實不管你知不知道什么是selector,condition都不要緊,至少從上圖,應該可以看出來,行為樹節點間的聯系並不像狀態機那樣得“緊密”。
選擇兩種不同的ai實現方法,也決定了具體行為的實現邏輯。
比如對於sleep動作的實現,如果是狀態機:
function sleep() =
if Y == 100 then
AwakeEvent()
return
end
HP -= X
MP += Y
end
然后每一幀執行sleep()
如果是選擇行為樹:
function sleep()
local sleepTime = (100/15)
–不好意思亂入了一段cocos2dx的代碼
self:runAction(cc.Sequence:create(cc.DelayTime:create(sleepTime),cc.CallFunc:create(cancelPending)))
local cancelPending = function()
pending = false
end
end
羅列一下行為樹的概念:
對於有限狀態機而言,必須明確 狀態的轉換方式;對於行為樹,必須明確狀態前提:前提條件
每一個行為必須有“前提條件” ,這決定了該行為是否被選擇。
行為樹的運算也是通過幀循環的update來驅動,不一定是每幀都update,但是要周期性update。
每一次run從根節點(root)開始,每一運行都會選擇一個可行的子節點運行,這種選擇可以是隨機方式,也可以是預設好優先條件
行為樹由葉子節點和中間節點組成,葉子節點是最基本的行為(如跑動,攻擊),中間節點代表邏輯單元(巡邏,逃跑)。
當一個葉子節點被選擇后,就會激活其對應的基本的行為
最基本的行為可能執行成功也可能失敗。
高等級的行為(中間節點)是否執行成功依賴於他們的孩子節點是否執行成功。
一個子節點失敗可能導致父母節點選擇另外一個孩子。
除了選擇(selector)一個單獨的子節點行為,一個節點還可能順序(sequence)or並行(concurrent)得運行他的所有子節點。
一個行為除了有前提條件,可能還有上下文條件(父節點or孩子節點可能存儲一定的狀態變量)。
高優先級的行為可能搶占低優先級的行為
轉載一段akara的行為樹實現方案:
- Composite Node 組合節點
- Decorator Node 裝飾節點
- Condition Node 條件節點
- Action Node 行為節點
各種節點的詳細描述:
* Selector Node 選擇節點
描述:從頭到尾,按順序選擇第一個執行條件為真的子節點,遇到True停止。
處理流程:當執行本類型Node時,它將從begin到end迭代執行自己的Child Node:如遇到一個Child Node執行后返回True,那停止迭代,本Node向自己的Parent Node也返回True;否則所有Child Node都返回False,那本Node向自己的Parent Node返回False。
-
Sequence Node 序列節點
描述:從頭到尾,按順序執行每一個子節點,遇到False停止。
處理流程:當執行本類型Node時,它將從begin到end迭代執行自己的Child Node:如遇到一個Child Node執行后返回False,那停止迭代,本Node向自己的Parent Node也返回False;否則所有Child Node都返回True,那本Node向自己的Parent Node返回True。 -
Parallel Node 並行節點
描述:從頭到尾,平行執行它的所有子節點。
Parallel Selector Node: 有一個子節點True返回True,否則返回False。
Parallel Sequence Node: 有一個子節點False返回False,否則返回True。
Parallel Fall On All Node: 所有子節點False才返回False,否則返回True。
Parallel Succeed On All Node: 所有子節點True才返回True,否則返回False。
Parallel Hybird Node: 指定數量的子節點返回True或False后,才決定結果。 -
Decorator Node 裝飾節點
描述:裝飾節點一般用來作為額外的附加條件。例如,時間間隔控制,次數控制,頻率控制,結果取反,錯誤處理等。 -
Condition Node 條件節點
描述:顧名思義,就是對應條件的節點。 -
Action Node 行為節點
描述:顧名思義,就是用於完成某種動作的節點。
從代碼實現的角度來談下優缺點
優點:
1. 行為邏輯和狀態數據分離,任何節點寫好以后可以反復利用
2. 重用性高,可用通過重組不同的節點來實現不同的行為樹
3. 呈線性的方式擴展,易於擴展
4. 可配置,把工作交給designer
5. 能夠勝任”AI” “掉寶”等等場景。
缺點:
1. 每一幀都從root開始,有可能會訪問到所以的節點,相對State Machine消耗更多的cpu
2. 任何一個簡單的操作都必須要使用節點
原文地址:http://blog.csdn.net/u011484013/article/details/52369313