游戏人工智能开发之6种决策方法
人工智能遵循著:感知->思考->行動
決策方法:有限狀態機(Finite-State Machines),分層狀態機(Hierarchical Finite-State Machines),行為樹(Behavior Trees),效用系統(Utility Systems),目標導向型行動計劃(Goal-Oriented Action??Planners),分層任務網絡(Hierarchical Task Networks)
有限狀態機
有限狀態機是目前游戲AI中最常見的行為模型。狀態機的代碼簡單又快速,使用上強大、靈活、計算開銷小。
狀態機的一個好處是可以可視化,如下圖所示:
?
圖中有四個狀態:巡邏(patrol),查看(investigate),攻擊(attack),逃走(flee),我們把實心圓當做初始狀態。
簡要過程:假設NPC士兵正在保衛他的陣地,當前狀態為巡邏,當他聽到什么動靜時就會轉到查看狀態,跑到聲音源去查看,如果看到敵人就轉到攻擊狀態,如果沒看到過一段時間又會回到巡邏狀態。在攻擊狀態中如果血值低下就會進入逃跑狀態。如果擊敗了敵人,又會回到巡邏狀態。
狀態機狀態類的一個主要結構如下,onEnter函數就相當于unity中的Start()函數,在類開始時調用,作為對舊狀態的過度和新狀態產生的開始,比如當從巡邏轉向攻擊狀態時,可以在攻擊狀態的開始讓NPC大喊“發現敵人!進攻!”等等。onUpdate()就相當于unity中的Update(),你可以讓它每幀都執行,或者幾秒鐘執行一次,是循環執行的,每次執行時間間隔由你來決定。onExit()就是在退出一個狀態之前要執行的,比如,殺死敵人之后由攻擊狀態轉向巡邏狀態之前,讓NPC做一個歡呼手勢并大叫勝利了。FSMTransition列表為將要轉到的所有可能的狀態。
每個狀態還存儲著FSMTransition的類,代表能從當前狀態可以轉到的狀態
當轉換條件滿足時isValid()返回true,比如當發現敵人NPC就從巡邏狀態轉到攻擊,getNextState()返回將要轉到的狀態,onTransition()是狀態之間轉換的過渡,和上面說的onEnter()差不多。
最后是有限狀態機類FiniteStateMachine
?
有限狀態機類包含一個包含所有狀態的列表states,initialState為初始狀態,activeState為當前狀態。
偽代碼如下:
?
在編寫有限狀態機的代碼只前最好畫一個上面的草圖,這樣既可以明確轉換關系,又可以不漏掉該有的狀態。
分層有限狀態機
有限狀態機雖然好,但是它有很大的缺點,當狀態少的時候可以運用自如,當狀態多的時候10個以上就已經結構非常復雜,而且容易出錯。
如果我們讓NPC巡邏兩個地方,比如安全的室內,和門口。
?
如果我們想在一個狀態上附加一些狀況,例如當NPC在巡邏時,讓他接一個電話然后再恢復巡邏,此時如果使用有限狀態機的話我們必須要新建一個打電話的狀態來做過渡,但是此時的巡邏有兩個,所以能接到電話的狀態也有兩個,然后加了兩個相同的狀態,很多這樣的重復的小狀態使得狀態機越來越復雜。如下圖:
?
這時,我們可以用分層有限狀態機來解決這個問題,把多個狀態機歸為一層,如下圖,把巡邏安全處和門口歸為看守建筑,這樣我們只需要有一個手機號買號打電話狀態就可以了。
分層有限狀態機增加了一個滯后,在有限狀態機中并沒有,在一個普通的有限狀態機中,是從初始狀態開始的,在分層有限狀態機中是一個嵌套的狀態。注意上圖有H的圈,代表歷史狀態(history state),當我們第一次進入嵌套狀態->看守建筑時,歷史狀態H表示為初始狀態,之后歷史狀態H表示為最近處在的一個狀態。
在我們的例子中:初始狀態就是看守建筑,,然后進入看到手機按住這個嵌套,巡邏安全處是初始狀態。當從巡邏安全處轉換到巡邏門口這個狀態時,H歷史狀態就轉變為巡邏門口狀態,此時來電話了,轉換到接電話狀態,接電話結束,我們回到嵌套狀態中的歷史狀態,此時為巡邏門口,可見H歷史狀態就是一個臨時的,便于嵌套外的狀態返回到之前的嵌套內的小狀態,以不至于出錯,或者換回了別的狀態,如果接完電話回到巡邏安全處,那就出大錯了。
分層有限狀態機,就這樣避免了重復狀態,可以實現更大的更復雜的狀態。
實例:
Halo2使用了這一技術,如下圖:
?
可見:把使用手雷、掩蔽、防御歸為自衛,交戰部分使用了多層嵌套,但是原理是一樣的,向尸體設計和搜查尸體歸為戰后處理。在撤退和閑置部分只有一個行為被嵌套,但是日后可以繼續添加行為,可擴展性良好。
至于如何在嵌套的層里對行為進行選擇,可以就按這個順序執行,也可以加上權重優先級,或者你想讓他執行哪個通過代碼來控制。
行為樹
行為樹是樹型結構的,每個節點都代表了一個行為,每個行為都可以有子行為。
所有行為都有一個先決條件,就是產生的這些行為的條件。
整個算法先從樹的根部開始,然后開始檢查每一個先決條件。樹的每一層只可以執行一個行為,所以當一個行為正在執行,它的兄弟節點都不會被檢查,但是它們的子節點還是要檢查的。相反如果一個行為的先決條件當前并不滿足,則跳過判斷它的子節點,繼續判斷它的兄弟節點。一個樹全部檢查完畢之后,決定執行優先級最大的,然后再依次執行每個動作。
偽代碼:
?
不同于狀態機,行為樹是無狀態的,不需要記下之前執行的行為,只是判斷行為該不該執行。
行為樹的節點之間是不相關的,刪除或增加節點,對其他節點都無影響。所以,可擴展性也是行為樹的一個優勢。另外還可以為決策樹添加靈活性與隨機性,父節點可以隨機決定是否檢查子節點。
缺點:決策樹做的選擇并不一定是最優的,結果也不一定是我們想要的。而且決策每次都要從根部往下判斷選擇行為節點,比狀態機要耗費時間。每次決策都要經過大量的條件判斷語句,會變得非常慢。
另外還有一個問題,例如:一個農民要收割作物,敵人出現了,農民逃跑,逃出了距離敵人的一定范圍之后,又回去收割作物,走到敵人的范圍又逃出,這樣來回往復,是一個弊端,,可以根據情況來寫代碼避免,否則會被玩家***的。
效用系統
人工智能的邏輯->電腦的邏輯,是基于簡單的bool問題,比如:“我能看到敵人嗎?”,“我有彈藥嗎”,是簡單的是或者不是的問題,所以做出的行為通常是極端化的,一個單一的行動。比如:
?
所以有些情況,只是做這些布爾判斷是不合適的,會遺漏很多情況,判斷也不妥當。比如:我們可能需要同時考慮與敵人的距離、有多少彈藥、饑餓程度、HP值,等等。這些判斷條件能映射出許多動作,比我們單一的判斷做不做這個動作要好很多。utility-based system,基于效用的系統,會根據權重、比率、隊列和許多需要考慮的事項來做出最優選擇,使AI比普通的行為樹更有頭腦。根據上面的例子,使用效用系統我們的AI可以做出我們想要的動作,并根據當前情況做出不同強度的動作,使AI真實、更具可能性,也不再是只有一個正確的選擇了。決策樹就是對AI說,“只是你將要做的一個行為”,效用系統就是對AI說:“這些是你可能要做的行為”
Sims模擬人生的人工智能就是使用的效用系統(sims的人工智能讓我膜拜至今),在sims中,小人結合當前環境和自身的狀態,來做出行動的選擇。例如:小人“非常餓”結合環境“沒有食物”會比只有“有一點餓”更加吸引人的眼球。如果“有一點餓”小人會以接近“美食”為第一執行行為。注意,這里的“美食(的美味程度)”、“食物很少(食物儲備程度)”、“一點餓(餓的程度)”,都是一個有范圍的數值(常用的是0-1的浮點值)。
當需要選擇新的行為時,我們通過分數(上面說的各種程度)來選擇相對最優的選擇,或者加上一個隨機值再選擇,使得接近優選的幾個選擇都有一定幾率(幾率可根據所加隨機值決定)被選中。
目標導向型行動計劃
GOAP來源于STRIPS方法,這兩種都是讓AI創造他們自己的方法去解決問題,我們提供給它一系列可能的動作作為對這個世界的描述,和每個動作使用的先決條件,和行動帶來的影響。AI擁有一個初始狀態和他需要達到的目標。有一組目標,AI可以通過優先級或當前狀態選擇一個。計劃系統決定一個動作序列來滿足當前目標,計劃出一個像路徑一樣的能最簡單達到目標狀態的動作序列。
GOAP是一個反向鏈接搜索,從要實現的目標開始,找到什么動作能實現目標,在尋找剛才動作的先決條件,一直往前推,知道達到你的當前(初始)狀態。這種反向鏈接搜索替代了啟發式的前向鏈接搜索。
偽代碼:
?
例如:我們建立一個NPC士兵,把它的目標設為殺死其他敵人,我們設置它的目標為Target.Dead。為了讓目標去死,NPC必須要有一個武器用來射擊,這是一個先決條件,但是現在NPC并沒有正在裝備的武器,NPC就需要執行找到武器這個動作,如果NPC有武器庫,他就會從武器庫中拿一個,如果病沒有武器庫,就需要尋路去找一個武器裝備了。得到武器裝備之后就要找到敵人,實現方式多種多樣,徒步尋找、或者NPC周圍有車也可以開著車去尋找。我么發現,我們給NPC大量的動作選擇,讓NPC自己決定該做什么,因而產生動態不可預知又有趣的行為,而且表現得很自然,比開發者創建行為好多了。
分層任務網絡
HTN也是尋找一個計劃來讓AI執行,不同之處在于怎樣找出這個計劃。開始擁有一個初始狀態和一個跟任務代表我們需要解決的問題。原理是最高級的任務分解成更小的任務再繼續分解直到我們解決問題。每個高級任務都有很多方式被完成,當前世界狀態決定高級任務要分解成哪組小任務。HTN與GOAP相反,HTN是前向鏈接搜索,是從當前狀態一直推到目標狀態,向前推直到問題解決。世界狀態分散成幾種屬性,它的HP、精力,敵人的HP、相距距離,計劃根據這些來制定。
我們有兩種任務:原始任務和復合任務。原始任務是可以只解決問題的任務,也就是可以直接達到目標的任務。在游戲中,它可以為開火、裝填子彈、移動到掩蔽物。這些人物可以影響世界狀態,開火這個任務需要先有子彈,并執行裝填子彈這個任務。復合任務是高級別的任務,可以看作方法。一個方法是一組任務可以完成復合任務,這一組任務是由先決條件決定的。復合任務讓HTN推斷出世界并且決定該做什么動作。
使用復合任務,我們就能構建一個HTN域,這個域是一大層任務,代表我們解決問題的方法。
偽代碼:
?
HTN就是從最高級的根任務分解更小的任務再分解成更更小,分解是需要判斷當前狀態和條件的。當我們終于分解為原始任務,我們把原始任務加到最終計劃中,每一個原始任務都是一個可操作步驟,我們可以直接執行它。
總結
以上是生活随笔為你收集整理的游戏人工智能开发之6种决策方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unity3d干货分享:实现敌人锥形视角
- 下一篇: 利用文件摘要简化游戏资源的引用管理