This document is about: QUANTUM 2
SWITCH TO

Goal Oriented Action Planning (Beta)


Available in the Gaming Circle and Industries Circle
Circle

1. 概述

GOAP Quantum程式碼及視覺編輯器都在測試版階段。

1.1 GOAP是什麼

目標導向動作計劃(GOAP)是一個AI技術,其由兩部分組成:

  1. 給定目前的條件下,從一個已特定的目標集之中選擇最合適的目標。
    目標(也稱為需要)可以是:擊敗一個目標、治療、偷取敵方旗幟、從
    敵方逃走
  2. 從一個已特定的實現此目標的動作池之中,尋找一個動作集(計劃)。
    動作可以是:尋找物件、尋找目標、拾起物件(比如槍、敵方旗幟、健康
    包)、前往位置、前往作戰範圍、射擊

1.2 比較其他機器人SDK AI方法

與FSM、HFSM及行為樹等更標準的AI方法不同,設計師
不會在這裡建立的精確的AI行為。一個AI被告知它有哪些需求,以及
它可以做什麼,然後基於目前的條件(世界狀態),在運行階段時把精確的步驟放在
一起(已計劃)。

優勢

  • 很好地處理複雜性
    流暢地新增新的目標及動作,其自動地與先前的AI行為
    協同工作

  • 針對較大的專案,可以加速開發時間
    當建立一個夠大的動作及目標集之後,它可以重複用在許多個有著不同行為的AI
    代理之上

  • 自然(模糊)行為
    當AI行為是非一般的,對於玩家而言更難發現一些不想要的
    模式。與任何計算某些效用/相關性/成本的AI一樣,許多的
    價值存在於,AI在相似的情況之間,將可能會有些許不同的行為。

  • 獨特的解決方案

    有了大量的可能動作,AI在解決某些問題上,很可能
    可以找出一個獨特的解決方案——這個行為可以有好的及壞的一面。
    換個角度,有太多動作的話可能影響計劃效能,所以
    需要謹慎地使用這個方法。

劣勢

  • 計劃部分(找出一個合適的動作集的流程)需要評估很多
    可能性,因此一般而言GOAP會比更輕量的AI解決方案(比如FSM)來說
    更慢
  • 更複雜而更難駕馭
    當設計GOAP AI時,使用者需要想辦法簡化一個複雜世界為
    世界狀態值,然後總是要思考GOAP動作將如何影響這個
    世界狀態,而不是直接地指定行為。
  • 因為並非指定AI該做哪些事情,因此對於「執行指令的」AI行為而言較為麻煩,
    比如魔王戰鬥

為了最好的利用GOAP的優勢,需要仔細地設計動作及目標。
GOAP動作應不可部分完成——這意味著更複雜的動作應該被分為多個
動作,前提是如果且僅當這類新建立的動作,可以在不同的情況下使用不同的
動作。一個示例是某些複雜的A 圍剿敵方巢穴 動作,可以被
分為 找出巢穴前往戰鬥範圍攻擊 動作。如果這類方法不可行或
不好用,可能更好的做法是立刻使用一個更標準的AI解決方案。

2. Quantum GOAP編碼

2.1 執行方式

首先讓我們從程式碼的角度來分析GOAP,主要是為了了解它內部工作的
方式,這將透過幾個圖片示例來說明。然後,我們將直接在Unity編輯器上分析它,以繼續
說明。

GOAP的核心位於 GOAP管理員 之中。管理員(在GOAP的背景下稱為
規劃工具)選擇最好的目標,建立一個滿足該選取的目標的計劃(動作序列),
並且在可行的情況下執行來自計劃的所有動作。

透過向後A*,來搜尋可行的動作序列,其中啟發學習法是世界
狀態差異(有多少世界狀態旗幟不同於目標狀態)。

機器人SDK GOAP非常快速並且輕量,但也可以基於特定遊戲需求來
進一步擴展。

2.2 建立及更新一個GOAP代理

這裡是建立及更新您自己的代理時,您需要做的各個步驟:

  1. 新增GOAPAgent元件到您的實體。這可以直接在Unity上的實體
    原型上完成,不過它也可以使用幀API,直接從Quantum程式碼
    之內完成;

  2. 找到所需的GOAPRoot資產,並且在初始化方法上使用它:

    C#

    var goapRoot = frame.FindAsset<GOAPRoot>(playerData.GOAPRoot.Id);
    GOAPManager.Initialize(frame, entity, goapRoot);
    
  3. 調用更新方法,以一個參數傳送代理實體:

    C#

    GOAPManager.Update(frame, filter.Entity, frame.DeltaTime);
    
  4. 當需要的時候,手動地設定代理的目前的狀態,透過:

    C#

    goapAgent->CurrentState.SetFlag();
    

2.3 GOAP狀態

World State

GOAP狀態代表了 與規劃工具相關 的遊戲的狀態。各個AI代理
有其自己的GOAP狀態。在我們的執行方法中,狀態被表示為
位元遮罩。這意味著各個世界狀態旗幟可以有三個值:真、假及
未定義。

對於一個好的GOAP AI設計而言,選擇一個正確的旗幟集是非常重要的。通用的規則是
如果且僅當旗幟在規劃時可以改變的話,旗幟應該呈現在世界狀態中
(= 用作為某些GOAP動作的一個 條件 或一個 效果)。

舉例而言:如果沒有GOAP動作有IsHungry作為一個條件或一個效果,就算其他遊戲程式碼使用它,
在世界狀態中沒必要有IsHungry旗幟。在這個
情況,更好的做法是將IsHungry旗幟放在您的自訂的代理的資料中。

為了新增旗幟到世界狀態,您需要在GOAPState.qtn檔案中編輯EWorldState enum

可以透過自訂資料來擴展世界狀態。

2.4 GOAP目標

Goal Sample

目標狀態
規劃工具在規劃流程時試著達到的狀態。

開始狀態
通常是留白。當規劃工具正在開始規劃流程,它使用目前的代理的
狀態,並且將其與目標的 開始狀態 合併。這個已合併狀態之後作為「從」狀態,而
目標狀態 作為「到」狀態。

注意事項:通常用於從代理的狀態清除某些旗幟,以確保某些特定動作將被規劃。

驗證
如果一個目標是無效的,在目標選取流程時,它將不會被考慮。

相關性
說明這個目標的相關程度。有著最大的相關性的目標將被規劃工具所選擇。
當兩個有效的目標有著相同的相關性,在目標清單的第一個目標將被
選擇。

停用時間
在目標可以被重新使用之前所需的時間。

注意事項:停用時間經常使用的情況是,我們不希望一個AI代理去連續多次執行
相同的目標,就算它被認為是該情況下最好的目標(比如,我們
可能不希望一個敵人連續投擲五顆手榴彈)。當找不到規劃時
(某些行動在目前的情況下無效),而且需要選擇不同的目標的情況下,
這一點也很重要。

已完成
當滿足目標後,規劃工具停用這個目標,並且開始搜尋新的目標。
目標被滿足的前提是 已完成 為真,或是代理的GOAP狀態含有
目標的 目標狀態

中斷行為
啟用的目標(計劃)的執行可以被中斷。如果啟用中斷,規劃工具
將定期檢查是否存在更相關的某些目標。如果存在,那麼將停止目前計劃的
執行,並且將計劃一個新的目標。

● Always - Always check whether more relevant goal exists
● Never - Plan is never interrupted
● Based On Actions - Active action controls if the plancan be interrupted

在初始規劃上
在規劃流程開始前執行的動作。

在啟用上
當成功地找到一個規劃,並且開始執行規劃時,所執行的動作。

在停用上
當停用目標時執行的動作。

2.5 GOAP動作

Action Sample

條件
為了在規劃中考量這個動作,這個動作需要的狀態。

效果
這個動作在代理的狀態上有的效果。

驗證
無效的動作將不會在規劃流程中被考量。

注意事項:這樣您可以在特定情況下「停用」特定動作,而不需要實際上
以不必要的旗幟來複雜化世界狀態。如同世界狀態章節所提到,世界
狀態應該只含有在其規劃流程時可以改變的屬性。

成本
決定動作的成本。規劃工具試著找出一個有著最低總成本
的動作序列。一個動作的成本必須大於零。通常最好將成本
思考為動作將使用的時間,以秒為單位,但保持一定的合理範圍(比如0.5到5之間,
大多數動作在1左右)。過大的成本差異可能傷害GOAP效能。請參見
最佳化 章節以取得更多資訊。

已完成
如果一個動作已完成,規劃工具繼續進行規劃中的下一個動作。動作已
完成的前提是 已完成 為真,或當所有 效果 都呈現在代理的狀態中時自動地完成。

已失敗
當動作失敗,整個計劃都失敗,並且再次開始搜尋新的最佳目標。

可中斷
動作是否可以中斷。目前啟用的目標需要讓 終端行為
設定為 基於動作,以讓這個設定被考慮。

在啟用上
當這個GOAP動作被啟用時,執行AI動作。

在更新上
當這個GOAP動作被更新時,執行AI動作。

在停用上
當這個GOAP動作被停用時,執行AI動作。

計劃狀態驗證
計劃狀態驗證節點用於進階GOAP功能。這基本上意味著它將
在規劃時基於目前的規劃狀態來驗證動作。它也
可以將規劃進行分支。

3. 編輯器

3.1 建立一個新的GOAP

Create Document

在編輯器的頂端列,按一下(+)按鈕,然後選擇其他選項GOAP。

然後將提示您儲存HFSM檔案。將它儲存在您希望的地方。這將建立一個
資料資產,用於保存您已 在視覺編輯器上完成 的工作:

GOAP Asset

注意事項:您現在選擇的名稱,將是當您編譯您在視覺編輯器上已完成的工作時,
進一步生成的另一個資料資產的名稱。這將成為用於實際驅動您的機器人的
資料資產,所以您已經可以選擇一個具有暗示性的名稱。

當您儲存您的檔案,主要機器人SDK視窗將顯示一個GOAP文件的最基本的
格式,其中您將看見兩個容器:一個名為GOAP Goals而另一個名為
GOAP Actions

GOAP Clean Document

3.2 建立新的GOAP目標

為了建立一個新的目標,以右鍵按一下在機器人SDK視窗上的任何空的空間,並且選擇一個
GOAPDefaultGoal。在更進階的設定中,您可以建立您自己的目標,
其也將列於右鍵選單中。

Create GOAL

在根階層,一個未修改的目標節點看起來如此:

GOAL Root Level

也可以按兩下任何目標節點,以查看其細節。預設目標
提供您許多欄位,您將需要填入這些欄位,以表達您希望您的AI有的
欄位。

GOAL Detailed

每個目標的兩個核心概念是「開始狀態」及「目標狀態」,其是
EWorldState類型的列舉,其代表針對一個特定的GOAP代理的目前的世界狀態
(所以這 是一個共享的/全域狀態)。這些狀態用於規劃流程中,以
選擇將以滿足代理的目的的方式來改變遊戲狀態的目標。

可以將一個世界狀態旗幟表達為正或負。在規劃流程,
規劃工具將篩選出適當地滿足所需的世界狀態的目標。讓我們以一個示例
來舉例說明。

注意事項:在Quantum GOAP編碼章節取得更多關於世界狀態的定義的
細節。

3.2.1 設定開始/目標狀態:

  1. 按一下Start StateTarget State按鈕,以定義哪些旗幟 必須
    在規劃流程時被世界狀態所包含,以負或
    正的方式;

    Add World Flag
  2. 在選擇所需的狀態之後,它們現在將被包含在目標節點之中:

    World States Added
  3. 預設下,世界狀態將與一個小的綠色圓圈一同顯示。這意味著預計
    世界狀態旗幟們將含有該世界狀態旗幟 以及 意味著它應該為
    正。然後可以按一下小的綠色圓圈來更改它為
    負。圓圈將隨之變成紅色:

    World State Negative
  4. 在上述範例中,預計世界狀態旗幟將告知,代理 是在
    亂鬥範圍內,但是 並不在復原中,以讓這個目標被包含在
    規劃流程中(與其他目標並存)。但是它只在目標狀態的結果
    將協助完成代理的目前的目標時,才被包含。在上述的示例中,
    選擇該目標的結果是目標物將被擊敗;

  5. 也可以從根階層來 看見及改變 世界狀態旗標。您可以
    回到根的方法是按下「ESC」,或按一下在頂端列的階層連結列上的
    「根」按鈕。根階層目標總是以摘要的方式呈現:

    Root Level World Flags

3.2.2 包含目標並且組織它們

為了讓目標節點被包含在規劃流程之中,必須讓GOAP目標容器
包含它們(灰色區域)。
為了達到這個,只需拖放您的目標節點到容器中:

GOALS Container

也可以 重新命名目標節點。為了完成這個,選擇節點並且按下F2,或是以右鍵按一下
節點並且選擇其他選項「重新命名」:

Goal Renamed

一件很重要的注意事項是 節點的順序很重要。相較於其他節點而言,在最上方的節點將有
最高的優先順序。如果規劃工具決定,
有著相同的相關性的目標超過一個,且都可以透過相同的方式以達成代理的目標的話,
則節點位置是關鍵。重新命名目標節點並且適當地重新排序它們,是一個好的
作法:

Organised Goals

3.3 建立新的GOAP動作

在建立、編輯及組織節點方面,上述同樣的概念適用於GOAP
動作。這裡是在動作容器上包含的一些動作的簡單示例:

Actions Container

3.4 忽略及停用目標/動作

可以將目標及動作從規劃流程中拿走,且不需要
刪除節點。當偵錯及嘗試替代路徑時,這可以很有用,因為不會
失去您的節點資料,這樣您可以決定再次新增它們回來。
有兩個主要的方法來完成這件事情:

  1. 為了忽略一個節點,只需從容器移除它,並且如果它不應該再被忽略的話,可以
    新增它回來;
  2. 為了停用一個節點,以右鍵按一下它,並且選擇其他選項「停用」。節點之後將變成
    稍微透明,以表示它被停用。停用節點是很有用的,因為您
    不會失去它在容器上的位置/順序。

已忽略及停用的節點將在編譯流程中被略過,所以請不要忘記
在做這件事的時候重新編譯。

3.5 設定槽值

當編輯GOAP目標及GOAP動作時(在按兩下它們之後),您將可以
編輯許多槽值。它們之中的一些值可能是硬式編碼的值,或它們可能來自其他
節點,而另外其他一些槽,比如動作槽,可能只能連接到一個或多個動作
節點。

在這個章節,我們探索您定義該值的一些方法選項。

3.5.1 基本類型

舉例而言,GOAP目標有少許槽有著FP及布林值類型。您可以
按一下這些槽值,以直接在編輯器中定義這些槽值:

Edit Slot

但是除了硬式編碼值以外,也可以透過節點來連接槽,其節點可能
含有一個預先定義的值或一個預先定義的邏輯,在輪詢該槽值的時候將運行此值或邏輯。有
許多方法可以透過節點來連接槽,而所有方法都在這個主題中有所說明:

共享概念

3.5.2 動作槽

GOAP目標及GOAP動作兩者都在其右側附有一些動作槽。這些是
將被使用者執行的微動作,其將實際上改變遊戲

狀態。這些動作可以用於追逐一個目標物,執行一次攻擊,收集一個物品
或做其他事情。
重要事項: 請不要混淆「GOAP動作」和「動作」。這是兩種不同的
概念。

Linked Action

動作是一個常見的主題,因為它們也被機器人SDK的HFSM及UT重新使用。如需取得
使用動作的方式的更多資訊,請參見這個主題:

編碼動作

3.5 編譯您的GOAP

為了實際使用您建立的GOAP,您必須編譯您已經完成的工作,這樣
您可以獲得由Quantum模擬使用的Quantum資產。
為了編譯,您有兩個選項:

Compile Buttons
  • 左側按鈕只用於編譯目前開啟的文件;
  • 右側按鈕用於編譯您在您的專案上有的每個AI
    文件。

您的GOAP檔案將位於:Assets/Resources/DB/CircuitExport/GOAP_Assets

3.6 設定AI以讓您的機器人使用

為了使用已編譯資產,您需要從Quantum程式碼之內參照它。您可以
基於GUID來載入資產以完成它,或是您只需建立AssetRefGOAPRoot以指向

所需的AI資產。它可以被包含在某些元件、某些資料資產、
運行階段設定、運行階段玩家,或是任何更適合您的程式碼架構的東西之內:

GOAP Root Reference

附註:在Quantum GOAP編碼章節取得更多細節。

4. 最佳化及偵錯

4.1 偵錯

機器人SDK附有其自己的偵錯工具,但是GOAP編輯器目前沒有
使用它。新增偵錯工具是GOAP編輯器的下一個即將來臨的功能之一。

目前您可以使用GOAP記錄功能。簡單地指派一個實體到
GameManager.DebugEntity之中,之後偵錯訊息將被列印到主控台之中。

GOAP Debug 1

4.2 最佳化

GOAP最佳化通常可歸結為限制A*需要處理的節點數量。
為了檢查數量及它處理時需要的時間,啟用實體偵錯(請參見上述)及
檢查記錄訊息:

GOAP Debug 2

注意事項:通常在Unity編輯器中的搜尋時間值,比在遊戲的實際組建中的搜尋時間值來得更大
的多。但是當試著改善效能的時候,這是一個好的參照。

一般而言,您希望讓已造訪的節點數量保持低,但是確切的數量
取決於AI的複雜程度。如果已造訪的節點數量太高(比如針對簡單的AI而言
超過100個),有可能是不正確地設計了動作。常見的問題是
動作的條件及效果太過模糊,以至於規劃工具需要考量非常多的選項,但是
大多數的選項最終是無效的。另一件需要注意的事情是動作 成本。A*使用成本
以決定在規劃流程中哪個最佳動作序列最佳。所以如果有
不正確地設定的動作成本,將導致規劃工具在回到正確的分支之前,
命中很多無效的結果。最好的做法是想像動作將需要的時間成本(以秒為單位),
不過讓它保持在某個範圍(比如0.5到5,大多數動作在1左右),就算動作實際上
將需要更少或更多的時間,這只是為了讓動作之間不要存在巨大的成本差異。

5 額外的細節

5.1 AI參數

如需取得更多關於使用AIParam的資訊,如果您希望有更
彈性的欄位,其可以透過不同的方式來定義的話,請參見此處:手動或從
黑板/常數/設定節點來設定:AI參數

5.2 AI內容

如需了解更多以參數傳送代理內容的資訊的方式,請參見此處:AI內容

5.3 機器人SDK系統

有一個層級用於自動化一些流程,比如取消配置黑板
記憶體。如需取得更多關於它的資訊,請參見此處:機器人SDK系統

5.4 視覺編輯器註解

如需取得更多關於如何在視覺編輯器上建立註解的資訊,請參見此處:視覺編輯器註解

5.5 更改編譯匯出資料夾

預設下,機器人SDK的編譯生成的資產將被放在
「資產/資源/DB/循環匯出」資料夾之中。請參見此處以了解您如何更改匯出資料夾:更改匯出資料夾

Back to top