[程式] 使用者預先定義並且容易拆解的遊戲AI引擎
實作一個由使用者預先定義並且容易拆解及重複利用的遊戲AI引擎
網頁好讀版 https://tinyurl.com/ya9cxjrt
緣由
剛好在重構異世界物流士的 AI 部分,所以回想起15年前曾經實作過一個 AI 引擎。就把
一些舊文件拿來看,蠻多概念有點過時了,請多多包涵。
這個引擎主要的目的是:實作一個由使用者預先定義並且容易拆解及重複利用的
遊戲AI引擎。(不包含實作路徑搜尋或是評估模組)
簡單來講這是一個通用版的AI引擎。
主要特點在決策及行為的分解及組合使用。來避免常見初寫遊戲AI若使用決策樹的撰寫風
格下一發不可收拾不好除錯的問題。
參考資料
當時的實作參考自這些資料給各位參考
適合的遊戲類型
而當時在評估這個引擎的時候,特別比較了什麼樣的遊戲類型適合使用。
很明顯得戰術小隊的類型是主要的應用客戶。
大架構
架構圖分為
上方是遊戲
左方是知識
中間及中間偏右側是思考的判斷區域
各種部件的說明
Plugin: AI引擎常見的插件
為了防止誤會,關於AI常用的工具我還是要列在這裡。但是這不是這個系統實作的內容,
所以我才用plugin來稱呼。
Effic. Engine : 評估計算,用來計算哪個目標有較高的性價比。
Path Finding : 尋路。
Collision : 碰撞運算。
Editor : 編輯器(即時觀察器)
Condition Bank
條件式的零組件中心
讓使用者可以把一些好用的判斷式寫成零組件,實際使用的時候再重組。其中包含幾類:
客製化條件式:距離某單位是否距離夠近,某單位是否在眼前,這種常用的判斷式。
邏輯閘:AND OR 等組合用。
常用元件:距離及時間或數值判斷的常用元件。
一旦有了以上這些寫好的判斷式零組件。使用者在寫AI單位需要判斷的時候件就可以拿來
組合,不需要重新寫。
以上圖為例 自己(AI)是否被玩家看到可以用這些零組件組合而成。
Blackboard/Notebook/Memory
AI 需要去了解世界,所以要有一個類似 dictionary 的東西讓遊戲去填值,同時讓 AI
可以方便地取出那些數值。沒有這樣一個標準化的介面的話,AI就必須去了解(參照)遊
戲的類別,而每個遊戲的數值設計可能都不一樣,這樣就會造成AI無法在專案間切換(強
耦合)。
這邊分為三個名稱的原因是想要做成。
全域,小隊,以及個人的三層式資料。
同時更新的節奏也可以因為這三層來做區分。
如果不想這麼麻煩的話也可以所有的AI都直接用全域去存取。
Event
相對於了解世界,AI也需要去操控影響世界,所以需要一個事件系統讓AI能發送命令給遊
戲端。一樣是為了解耦合的目的。不過幸好,事件系統在很多引擎中已經是常見的工具。
ThinkingState
這邊的狀態是讓AI能夠將現況做切割。State的意思:是在什麼"情況"下,應該要採取的
不同後續邏輯。
通常的做法是
準備一個預設邏輯(Default),沒有滿足任何條件下的思考情況。
準備若干個應急邏輯(Reaction),例如說主堡被攻擊,需要即時切換的思考狀態。
然後依此去設計滿足條件下可以轉換的狀態:滿足了某些條件,就切換過去的思考情況。
所以這邊使用了類似狀態機的概念,同時用上了上述的條件式零組件,讓AI可以在遊戲進
行的情況下做適當的切換。
特別提到切換也是一個狀態,所以當狀態 A 要切換到狀態 B 的時候應該也要有一個
A->B 的狀態來做過度。(不過切換的狀態可以做比較少的事情,甚至不做事情)
Tactic Action Animation
這三個在引擎中是分為三層分別是戰術,行動,及動作。
其中動作就是對應遊戲內的Animation(由美術做好的一次性動作)
行動是抽象的一個動作,一對一的對應到動作。
戰術則是多個抽象動作組合而成的邏輯。
每一個狀態下有可能有多個可以預先設計好的戰術。
例如,前述的搜索敵人狀態下,AI目前選定的戰術是“(過河)前往某個地點”,其中會
需要走到河邊,游泳過河,抵達對岸,再行動到目的地。
走到河邊用的是走路動作
游泳過河用的是游泳動作
抵達對岸可能加一個上岸的動作
行動到目的地又回到走路動作。
總結
這個AI系統讓使用者可以事先寫好一些零組件,在最終應用中組合來重複使用。最初會覺
得都在硬碼,但是當零組件工具變多了,後面就會變成比較像在重複組合一些已經設計過
的部件。
而且因為已經部件化了,除錯或從舊的物件複製一份改成新的物件也變得簡單多。從實際
使用者的回饋也差不多是如此。使用者像是把需要修改的行為(不論是判斷或是行動)=
零件拿出來改一下再組回去。
補充 One-State FSM for AI :
準確的名詞我忘了。當時可能是在Game Programming Gems看到的。
其實這才是我想要找的資料,後續在物流士這個案子實作。
簡單解釋
因為傳統的FSM有大量的狀態機切換,導致AI邏輯不好整理。
所以當初有人提出來的簡化法。
把Game AI化為兩個狀態機,思考及行動。思考的時候就決定要做什麼。然後思考完畢切
到執行,就等待執行完畢。然後在適當時機再回過頭來思考。
這樣的優點是架構比較簡單。
缺點就是回到思考的時機會造成這個AI的反應表現。打個比方,如果用一定的時間碼表做
思考,那麼在還沒倒數完成的時候場景的參數變化,AI就不會來得及作出反應。就會看起
來笨笨的。
但是如果這個時間碼表週期設定的太短,那AI又會佔用太多的資源。如果場上的AI數量變
多,思考的資源就會不可忽視。(尤其是AI常常伴隨著路徑搜尋或是全局比較哪個怪物比
較應該攻擊,那又是特別浪費資源的運算)
在異世界物流士這個案子中思考的虛擬碼大概是這樣的
我們先定義這個角色可以身處的幾種情況(程式碼中是用FSM,但是因為避免與上面
One-State混淆,我們把這個稱之為情況。
每個畫格中會先依照現行情況執行需要持續執行的動作(移動或動畫)
A假如正在動畫流程(One-State),就不思考。
B假如思考碼表還沒到,就不思考。
依照目前設計者指定的情況來做該情況的思考並執行動畫,並接著切換情況.
如果進入執行動畫的旗標會打開,所以會被A卡住.
如果沒有把執行動畫的旗標打開,那麼至少在B碼表之內不會重新思考.
這邊情況只是讓判斷的寫法簡單一點(等於是簡化的決策樹),跟上面提到的
One-State 的狀態其實不是同一件事..
當然只要將B的思考碼表設短一點,那麼我們從外界依照某種規則來切換情況,AI就不會
陷入每個畫格在那邊跳情況的問題。跳情況就是切換的規則沒寫好。譬如說情況甲滿足某
個條件切到情況乙,情況乙又滿足某個條件切到情況甲。
如果要捨棄情況的問題,那也不難就是在思考的流程把整個決策樹跑一遍.就要注意這一
個時間點不要在一個畫格內浪費太多運算力。(以Unity來說就是用Coroutine/Async去思
考直到有結果為止)
--
"May the Balance be with U"(願平衡與你同在)
遊戲設計教學,討論,分享。歡迎來信。
黑水溝歷史文庫 https://ndark.wordpress.com/
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.169.95.150 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1762523599.A.BD2.html
※ 編輯: NDark (1.169.95.150 臺灣), 11/07/2025 21:53:47
※ 編輯: NDark (1.169.95.150 臺灣), 11/07/2025 21:53:54
推
11/07 23:29,
3小時前
, 1F
11/07 23:29, 1F
GameDesign 近期熱門文章
PTT遊戲區 即時熱門文章
18
43
-14
25