This document is about: QUANTUM 2
SWITCH TO

Behaviour Tree

概述

機器人SDK的行為樹仍然是內部測試版,這意味著它將隨著時間逐漸準備好生產,而且將在進一步的版本中改善API及效能。

這裡是一個關於行為樹的工作方式的簡介影片,以及一些我們自己的執行方式的細節:

**您將在影片中看到...**

從開始到1:15:概述;

從1:15到21:40:行為樹基本概念;

從21:40到結束:探索範例裝飾項目/分葉/服務節點的程式碼。

建立一個新的行為樹

在編輯器的頂端列上,按一下(+)按鈕,然後選擇行為樹選項。

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

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

initial node

當您儲存檔案時,主要機器人SDK視窗將填入一個單一節點,其為 根節點,讓您來開始您的工作。

根節點

如同名稱所提示,這是樹的起始點。它是BT代理元件上應參照的主要資產,並且定義第一個應執行的複合或分葉節點。

根節點 只能有一個下層。為了連接根節點到任何其他節點,將滑鼠游標放在根節點的底部部分之上,並且按一下顯示的「+」按鈕。這將開始連結流程。

如果您還沒有建立其他節點,您可以按一下任何空白的空間,之後將出現一個節點建立面板。

initial node

節點狀態

幾乎所有在行為樹上的節點都有其自己的狀態。這是非常重要的,因為這是行為樹的工作流程的主要定義方式。

狀態可以是:

  • 成功:當節點成功地完成它應該完成的工作時。當節點傳回成功時,控制走到樹的上方到上層節點,其現在知道下層已經成功,並且可以基於該資訊來定義工作流程;
  • 失敗:當節點無法執行其工作。當它發生時,當結果成功時,控制走到樹的上方只是湖;
  • 運行中:如果在該特定幀上,節點在執行其工作時沒有成功或失敗,那麼節點需要運行更多幀,才能重新調整執行到其上層節點。一次只能有一個運行中的節點,因為運行中的節點被快取在BT代理上,並且是在連續的幀上重複地被執行,直到結果改變。
  • 停用:只在內部使用,所以您不必擔心這個問題

當撰寫您自己的遊戲特定節點的程式碼時,您將決定您何時希望它們成功、失敗或繼續運行。這將直接地影響將選擇哪一個行為樹的分支。

我們之後將進一步說明節點的類型,以及您建立新的節點的方式。

建立新的節點

有兩種主要的方式可以建立新的節點:

  • 當您以滑鼠右鍵按一下編輯器視窗上的任何空白空間,從內容選單建立
  • 從一個節點初始化一個新的連結,然後按一下任何空白空間來建立

現在,讓我們看一下可以建立哪些類型的節點。

複合節點

這些是行為樹上的工作流程控制的主要來源。它們定義了可能要執行的下一個節點,而且它們的行為方式有所不同。

複合節點嘗試 從左到右執行它們的下層節點,這意味著這是 定義優先順序的方式

一個複合節點 可以連接0個到許多個 下層節點,其可以是複合或分葉節點。

選取器節點

等價於一個 運算子。

  • 任何它的下層成功時,它就成功。在這個時刻,停止它們的執行,而且控制走到選取器的上層節點,並帶有「成功」結果。如果還有任何下層等待被執行,在這個迭代中它們將不會被執行;
  • 只有當所有下層都失敗時,它才失敗,在這種情況下,選取器傳回「失敗」結果到其上層節點。
selector node

序列節點

等價於一個 運算子。

  • 任何它的下層失敗時,它就失敗。傳回「失敗」結果到其上層節點,並且剩下的下層這次不會被執行;
  • 只有當所有下層都成功時,它才成功,在這種情況下,序列傳回「成功」結果到其上層節點。
sequence node

以裝飾項目來中斷

如同節點狀態主題中所說明,如果一個分葉節點的狀態是「運行中」,這意味著特定分葉節點將被快取,並且將在下一個幀上被重新執行。但是這也意味著我們也需要基於某些情況,來使用一些方法以中斷該分葉節點的執行。舉例而言,如果您的FPS角色正在射擊一個目標,並且它突然識別到一個手榴彈正朝著她/他的方向來投擲,那麼角色將停止射擊並且尋找掩護以躲避手榴彈。

已經 檢查過的裝飾項目,將 不會 在每個幀重新檢查。但是如同上述示例所說明,我們可能希望存在一些特殊情況,其中裝飾項目應被重新執行,以能夠中斷一個分葉。

有兩個方式可以完成中斷檢查:

動態複合節點

如同您可能已經注意到的,每個複合節點有一個IsDynamic欄位,其是一個您可以在編輯時間中切換的布林值:

dynamic composites

如果一個複合節點是動態的,這意味著,當該特定複合是目前正在執行的子樹的一部分時,它的所有裝飾項目都將在每個幀被重新檢查。如果任何裝飾項目失敗,那麼目前的分葉節點將被中斷,並且該複合節點將成為 失敗

這樣做的優勢是您可以選擇哪一些複合 需要 在每個刷新被重新評估,所以您可以更好地控制您最佳化您自己的樹的方式。

反應式裝飾項目

如果您有取決於黑板的裝飾項目節點,您可以讓這些裝飾項目 監看特定黑板輸入項目的改變

這樣做的好處是,再一次地,不用在每個刷新時執行裝飾項目檢查,而是取而代之地,只檢查您是否在黑板輸入項目上設定了任何可能的新內容。

舉例而言:您有一個「比較整數裝飾項目」,其檢查一個來自黑板的整數「A」是否大於來自黑板的整數「B」。有了反應式裝飾項目,只有在您的程式碼的任何部分,您在黑板上更改輸入項目「A」或「B」時,才進行檢查。

當中斷發生時,您可以選擇您希望 中止 目前執行的方式,其可以有三種類型:

  • 自身:停止目前節點的執行,並且中止所有事情,直到它到達中止節點;
  • 較低優先順序:繼續執行目前節點,但是中止同層節點;
  • 兩者:同時使用兩個邏輯

可以在裝飾項目節點自身上定義 中止類型

reactive decorators

反應式裝飾項目是在模擬程式碼上設定,所以請看一下BT 編碼章節以取得更多細節。

分葉節點

這些是在行為樹上的最低階層的節點。

它們負責執行大多數的遊戲特定邏輯,高度依賴它們運行時應傳回的狀態。

分葉節點的簡單示例有:

  • 等待節點:持續運行,直到一個特定數量的時間經過。當計時器結束時傳回「成功」;
  • 追擊節點:當運行時,持續將BT代理向一個目標實體移動。如果代理成功到達其目標,則傳回「成功」。如果代理被阻擋而無法到達該目標(比如,目標被摧毀,或是在一個不同的導航網格區域),則傳回「失敗」;
  • 偵錯節點:在主控台上列印一個訊息,並且總是傳回「成功」;

所以您將需要傳回的狀態完全取決於您的需求。

leaf node
**附註:** SDK提供的其中一個分葉節點是`WaitLeaf`。為了讓這個節點正常工作,請啟用`BotSDKTimerSystem`,因為這個被該節點使用以計算經過時間。

裝飾項目節點

裝飾項目是 條件式節點。它們目的是協助定義哪一些分支應該被執行。

除了能夠傳回一個狀態,這個節點類型 也傳回一個布林值,如果布林值結果為真,其之後引導至「成功」,而如果布林值結果為假,其引導至「失敗」。

裝飾項目節點可以 阻擋或允許 其附加到的子樹的執行。它們在 複合及分葉 節點中被新增,所以您可以選擇性地表達哪些節點在被執行之前應該考量哪些情況。

裝飾項目節點的示例有:

  • 有武器節點:如果BT代理在它的武器上有超過零個子彈,則傳回「真」;

  • 有目標節點:如果BT代理有一個在其記憶體上(或在其黑板上)定義的目標,則傳回「真」;

  • 冷卻節點:只有在該特定節點不在最後的「T秒」內被執行時,才傳回「真」;

所以裝飾項目應該用於協助允許或阻擋某些分支。舉例而言,「有武器節點」可用於讓「射擊」分支被執行,或阻擋它並且引領樹到「重新裝填武器」分支。

為了定義裝飾項目,按兩下任何 複合或分葉節點 然後您將被帶到其子圖表。在那裡,您將找到一個裝飾項目列表,其將以指定的順序執行。以滑鼠右鍵來建立新的裝飾項目,並且 以裝飾項目根節點來連接它們,如同下述圖片所示:

decorator node

在節點的子圖表上定義的裝飾項目,可以在裝飾項目列表上在其頂部階層檢視中看見:

decorators top view

服務節點

大部分作為協助程式節點,其不直接影響行為樹的工作流程。這些節點通常用於更改遊戲狀態,且不需要重新調整任何事情。

服務節點是 唯一一個不會傳回一個狀態的節點類型

如同裝飾項目,服務節點 可以被新增到複合或分葉節點。只需前往節點的子圖表,並且建立/連接它到服務根節點。

服務節點的一個重要特性是 它們按照時間的間隔被執行。每個服務節點有一個IntervalInSec欄位,您可以在編輯時間中定義它,以定義執行服務的頻率,這相當有用,因為您將有更多機會控制效能。

附註: 為了使用服務節點,請啟用 機器人SDK計時器系統,因為這是這些節點將計時的方式;

service sample

服務節點的示例有:

  • 更新目標位置節點: 隨著時間,更新代理應該前往的位置。它可以被關聯到導航網格(比如在它上面獲得一個隨機的位置),可以被關聯到追擊一個特定實體等等;
  • 執行跳躍節點: 隨著時間,代理執行一個跳躍;

所以服務用作為協助工具,因為它們不需要傳回狀態,它們可以被附加到您需要的任何節點,甚至有助於解耦之類的事情。

重要注意事項是 服務被儲存為子樹的一部分被執行,這意味著如果您有一個帶有服務的選取器節點。而且您目前由於運行一個特定的分葉而「卡住」,選取器節點含有的服務 將持續執行 直到該子樹不再是目前的。所以,可以這樣說,您的整個樹取決於有一個已更新的目標位置,然後您可以新增一個UpdateTargetPosition節點到您有的第一個選取器/序列。或是,如果只有樹的一個部分需要目標位置,那麼您可以就在那裡新增服務。所以它非常彈性。

如同裝飾項目,您可以在頂層圖表檢視上觀察服務清單:

service sample
## 編譯您的行為樹

為了實際上使用您建立的BT,您需要編譯您的工作。

為了編譯,您有兩個選項:

compile buttons
  • 左按鈕只用於編譯目前開啟的文件;
  • 右按鈕用於編譯您在您的專案中有的每個AI文件。

您的BT檔案將位於:「Assets/Resources/DB/CircuitExport/BT_Assets」。

bt asset

設定用於您的機器人的AI

為了最終使用建立的AI,您只需要參照已編譯的資產。 您可以基於GUID來載入資產以完成它,或是您可以只是建立一個AssetRefBTRoot以指向所需的AI資產:

referencing ai

行為樹編碼

新增元件到實體

為了設定您自己的代理,新增元件BTAgent到它,直接在一個實體原型上進行 透過var btAgent = new BTAgent()來建立元件,然後以frame.Set(myEntity, btAgent)來設定它到選取的實體,以從程式碼來新增它。

初始化BT代理

然後,在任何更適合您的應用程式的點,您必須調用:

C#

var btRootAsset = f.FindAsset<BTRoot>(btReference.Id);
BTManager.Init(f, myEntity, btRoot);

參數是:

  1. 幀;
  2. 含有BT代理元件的實體;
  3. 從視覺編輯器建立的BT根資產;

現在已經初始化實體的BT代理,您只需要在一個系統的更新上調用更新方法:

C#

BTManager.Update(f, myEntity);

有了這個,AI應該已經執行您在視覺編輯器上建立的工作流程。

節點編碼

總體而言,大部分的節點類型繼承於相同的層級,所以它們全部都共享非常相似的API,其可以被覆寫,以建立您自己的自訂程式碼。

在這個初始行為樹開發階段上,我們鼓勵您現在只 執行分葉、裝飾項目及服務節點,並且格外注意是否需要執行一個新的複合節點,因為這個節點類型需要更多對於BT工作方式的了解。您也可以要求新增新的複合節點,而且如果它作為通用節點是有意義的,而不是某種遊戲特定的節點,我們可以將它作為預設SDK的一部分來執行及交付。

開始您自己的裝飾項目/分葉節點

  • 為了建立一個新的裝飾項目節點,建立一個繼承於BTDecorator的新的層級;
  • 為了建立一個新的分葉節點,建立一個繼承於BTLeaf的新的層級;
  • 為了建立一個新的服務節點,建立一個繼承於BTService的新的層級;

重要事項: 您需要將上述任何層級標記為[System.Serializable]

針對裝飾項目及分葉節點的API

  • 只調用 一次 Init,就是當調用BTManager.Init的時候。它應該用來針對該特定節點的資料來配置空間。如需取得更多關於這個情況的資訊,請閱讀跟隨的 節點資料 主題;
  • 在造訪特定節點的時刻,並且在執行節點的更新之前調用OnEnter。它對於設定資料而言非常有用,比如儲存一個計時器FP。WaitLeaf層級有一個在代理上儲存計時器資訊的示例。但是再次強調,在 節點資料 主題中對它有更好的說明;
  • 在每個分葉被執行的刷新時都會調用OnUpdate。傳回BTStatus,這樣您可以選擇是否/何時希望傳回Success/Failure/Running。一個非常簡單的示例,其總是導致在DebugLeaf層級中看見SuccessWaitLeaf層級有一個稍微複雜一點的範例,其導致RunningSuccess
  • 當節點完成其工作時,或是當中止它並且執行向樹的上方走時調用OnExit。可以在需要時用於取消初始化任何資料;

關於裝飾項目節點的考量

裝飾項目有一個額外的可以被覆寫的方法:

  • 在節點的更新時調用DryRun。它傳回一個Boolean,其取決於您的遊戲特定需求

當執行裝飾項目時,經常更加注意執行DryRun方法,因為裝飾項目經常傳回Success or Failure,其 直接 取決於您DryRun是否傳回True or False。所以執行OnUpdate方法來更改這個是不常見的需要,但是它也有可能是需要的。

針對服務節點的API

  • 在執行服務的時候調用OnUpdate,其取決於視覺編輯器上定義的間隔。

節點資料

有些節點可能需要有其自己的整數和/或FP資料,其應被新增到遊戲狀態,並且它只能被節點自己來更新。

因為這對於某些重要的節點來說是很常見的,BTAgent元件已經有一個儲存空間來儲存這些特定節點資料。

舉例而言:

  • 複合節點需要儲存目前被執行的下層索引;
  • WaitLeaf節點需要儲存結束等待的時間值;

相同的方式,您可能需要有一些資料在需要在運行階段更改的節點之中。

但請記得,節點是 資料資產,所以您 在運行階段不能改變其欄位。您需要將資料儲存為幀資料,然後從那裡更改它。

針對整數及FP欄位,透過使用BTDataIndex類型可以很輕易地完成它。這個架構是在視覺編輯器上在編譯流程中預先內嵌的,並且保證您在您的節點資產上有的每個BTDataIndex,都將有一個獨特的索引值。

如果您識別到您的節點需要這類可變更的資料,您只需跟隨這個步驟:

  • 以一個暗示性的名稱來建立BTDataIndex類型的一個新的欄位,這樣您就知道該索引將代表的資料。舉例而言,在WaitLeaf程式碼上,欄位宣告是:public BTDataIndex EndTimeIndex;,因為在運行階段時該特定節點需要讀取/寫入結束時間;
  • Init方法上,您將透過執行:btAgent->AddFPData()btAgent->AddIntData();,來配置資料到BT代理。您將在參數中告知您希望儲存的初始值;
  • 為了從BT代理讀取該資料,請執行:p.BtAgent->GetFPData(frame, EndTimeIndex.Index),其中編輯時間索引只是我們已經組織WaitLeaf節點的範例;
  • 為了在BT代理上寫入資料,請執行:p.BtAgent->SetFPData(frame, endTimeValue, EndTimeIndex.Index);

回應式裝飾項目編碼

如同一個前述的主題所說明,如果有一個裝飾項目觀察黑板輸入項目,可以註冊它成為一個回應式裝飾項目,這樣不論被觀察的輸入項目何時發生更改,裝飾項目將被重新檢查,可能會中止目前的執行。

從程式碼的角度, 跟隨這些步驟以使用回應式裝飾項目:

  • 在一個裝飾項目層級的OnEnter方法上,在 每個所需的黑板輸入項目 上註冊裝飾項目,其取決於您希望觀察哪個輸入項目:

Unknown

// --> Sample from BTBlackboardCompare

    // We let the user define, on the Visual Editor, which Blackboard entries
    // shall be observed by this Decorator
    public AIBlackboardValueKey BlackboardKeyA;
    public AIBlackboardValueKey BlackboardKeyB;

    public override void OnEnter(BTParams p)
    {
      base.OnEnter(p);

      // Whenever we enter this Decorator...
      // We register it as a Reactive Decorator so, whenever the entries are changed,
      // the DryRun is executed again, possibly aborting the current execution
      p.Blackboard->RegisterReactiveDecorator(p.Frame, BlackboardKeyA.Key, this);
      p.Blackboard->RegisterReactiveDecorator(p.Frame, BlackboardKeyB.Key, this);
    }
  • OnExit上,取消註冊裝飾項目:

Unknown

// --> Sample from BTBlackboardCompare

    public override void OnExit(BTParams p)
    {
      base.OnExit(p);

      // Whenever the execution goes higher, it means that this Decorator isn't in the current subtree anymore
      // So we unregister this Decorator from the Reactive list. This means that if the Blackboard entries
      // get changed, this Decorator will not react anymore
      p.Blackboard->UnregisterReactiveDecorator(p.Frame, BlackboardKeyA.Key, this);
      p.Blackboard->UnregisterReactiveDecorator(p.Frame, BlackboardKeyB.Key, this);
    }
  • 不論何時您更改您希望觸發回應式裝飾項目回應的黑板輸入項目:

Unknown

blackboard->Set(f, "SomeKey", someValue)->TriggerDecorators(p);

定義欄位值

如需取得更多關於設定值到動作/決策欄位時,您有的替代方法的資訊,請參見此處:定義欄位值

AI參數

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

AI內容

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

機器人SDK系統

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

偵錯工具

機器人SDK附有其自己的偵錯工具。它讓開發人員能夠在運行階段選擇任何BT代理,並且看見在視覺編輯器上的醒目顯示的最近的代理的工作流程。這裡是一個偵錯工具的範例,其在機器人SDK範例專案上工作:

debugger graph
  • 藍色 = 目前執行的子樹。藍色連結顯示了到目前為止的路徑,而最深藍的藍色節點是目前正在運行的節點;
  • 綠色 = 在應用程式的該點的每個成功的子樹。請注意一個複合節點將只在其下層相應地成功時,才會成為綠色(序列需要所有成功的下層,選取器需要至少一個成功的下層);
  • 紅色 = 在應用程式的該點的每個不成功的子樹;
  • 灰色 = 沒有造訪的分支,並且晚一點可能造訪。

使用偵錯工具

這是一個逐步的步驟,以在您的專案上使用偵錯工具:

  1. 在您的SystemSetup.cs檔案上啟用BotSDKDebuggerSystem。使用這個特定的系統是可選擇性的,也就是如果您希望在其他地方有偵錯邏輯,您可以 在已驗證幀,在您的自訂系統中調用BotSDKDebuggerSystem.OnVerifiedFrame?.Invoke(f);
  2. 在視覺編輯器上,在頂層面板按一下偵錯圖示。當圖示成為綠色時,偵錯它將 啟用
debug active

現在,有兩種方法來選擇將被偵錯的實體。它可以被關聯到一個選取的遊戲物件,或它可以在一個偵測器視窗上被選擇。您可以選擇上述其中一個。或兩者:

從一個遊戲物件偵錯:

  1. 選擇您的預製件/實體原型,其代表一個有著BTAgent作為一個元件的Quantum實體;

  2. 新增BotSDKDebugger到它;

  3. 在運行階段,開啟機器人SDK視窗,選擇已新增BotSDKDebugger的遊戲物件。這樣就行了!偵錯應該已經開始工作;

從一個偵錯工具偵測器視窗來偵錯:

  1. 在模擬側,您需要註冊代理實體到偵錯工具視窗。可以調用這個來完成:

    BotSDKDebuggerSystem.AddToDebugger(entitiRef, (optional) customLabel)

    針對已偵錯實體的顯示的預設名稱跟隨這個模式:Entity XX | AIAssetName。但是如果您希望提供一個自訂名稱到偵錯輸入項目,您可以使用customLabel參數。它可以是您希望的任何名稱。

    也可以建立階層。只需在自訂標籤上使用分隔符號/,它將在偵錯工具視窗上建立階層,其可被摺疊、擴展等等;

  2. 在Unity上,按一下在偵錯工具啟用按鈕右側的按鈕。它開啟一個新的視窗,其顯示所有已註冊實體。選擇一個您希望偵錯的實體,這樣就完成了。

debug window
debug hierarchy

舉例而言,一些用於上述範例GIF的自訂標籤有:Monster 1, Monster 2, Blue Team/Commander, Blue Team/Warriors/Foo, Blue Team/Warriors/Fuz and Blue Team/Wizards/Bar

重要事項: 當啟用偵錯工具,它將配置記憶體以儲存偵錯所需的資料,如果您正在 從編輯器遊玩,其 可能減慢 遊戲。所以,如果您正在從Unity之內分析應用程式,分析的一部分可能被關聯到偵錯工具,所以請考慮在分析期間停用它。

附註:偵錯工具視窗也將顯示 沒有一個實體檢視 的實體,所以這是您可以找到它以偵錯它們的BT的方式;

附註2:目前,不可以偵錯沒有連接到一個實體的代理,比如處於DSL全域的代理。這將只在進一步的版本中新增。

視覺編輯器註解

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

更改編譯匯出資料夾

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

選擇已儲存的歷史大小

可以更改儲存在機器人SDK檔案的歷史輸入項目的數量。請參見這裡以取得更多相關的資訊:更改歷史儲存計數

Back to top