Blackboard
介紹
Blackboard 是 Bot SDK 核心中一個非常實用的工具。
它是一個 Quantum 元件,主要用於作為資料存儲,任何其他 Quantum 邏輯都可以從中讀取和寫入資訊。它分為三個主要部分:
AIBlackboardComponent是一個可以新增到實體的 Quantum 元件。它具有運行時存儲,存儲在遊戲模擬期間可以更改的資料;AIBlackboard資產是在 Unity 中創建的,具有將應用於元件的資料佈局(條目類型和鍵);AIBlackboardInitializer是一個資產,存儲 Blackboard 條目在首次初始化時應具有的初始值。使用初始化器是可選的;
為什麼使用 Blackboard
儘管將資料存儲在 Blackboard 中與將資料存儲在常規 Quantum 元件中非常相似,但將 Blackboard 與 Bot SDK 一起使用還具有一些額外的優勢:
- Bot SDK 視覺編輯器與 Blackboard 資產集成,允許用戶直接在編輯器窗口中定義其條目和初始值,這使得開發人員可以快速進行更改,甚至遊戲設計師也可以直接使用;
- 編輯器還具有將 Blackboard 節點拖放到 AI 圖中並將其與其他節點(如 HFSM 操作和 BT 葉節點等)連接的功能。這使得透過編輯器直接引用資料條目變得非常容易;
Blackboard 的缺點
使用 Blackboard 時,請考慮以下幾點:
- Blackboard 上的每個條目都是一個
union,因此每個條目在運行時內存中的大小等於聯合支援的最大類型的大小,即大小為8位元的AssetRef類型。當同時使用 許多 Blackboard 時,即使大多數條目是布林值(大小 =1 byte),實際消耗的大小仍為1位元。如果幀大小成為瓶頸,可以考慮將一些變量移出 Blackboard; - Blackboard 主要用於在運行時更改的變量。如果使用的任何變量不應該更改,則最好將此類資料存儲在其他 Quantum 資產中,以避免此類資料作為 Blackboard 運行時資料的一部分在幀中創建;
基數
Blackboard 資產是唯讀的,旨在被任意數量的實體重用,以定義其 Blackboard 元件佈局。
因此,資產本身應該被實體引用,每個實體在元件初始化後都會創建自己的運行時可變資料。
基數為 [1..n]:對於每個 Blackboard 資產,有n個代理將引用該資產。
簡單的使用示例
考慮一個在遊戲地圖中跑動並收集硬幣的實體,一旦它收集到3個硬幣,它就會停止並進入空閒狀態。對於該實體的 AI 來說,跟踪收集的硬幣數量顯然是有幫助的。
為此,可以在 Blackboard 中創建一個名為CollectedCoinsAmonut的新int條目。
然後,每當實體收集到一個新硬幣時,它將 Blackboard 上的值增加1,並檢查存儲的新值是否已經達到3。此檢查可以作為 AI 決策過程的一部分,例如每幀進行一次,因為從 Blackboard 中輪詢資料是基於字典查找的快速操作。
由於每個具有 Blackboard 元件的實體都有自己的運行時資料副本,因此一個實體甚至可以讀取另一個實體的 Blackboard,或者一個單獨的系統可以讀取每個代理的值,依此類推。
視覺編輯器中的 Blackboard
視覺編輯器已經帶有 Blackboard 的子選單。
它名為 Blackboard Variables,位於左側面板中:
按下 + 按鈕以創建新的 Blackboard 變量。
雙擊 條目以進行編輯它。
也可以在 右鍵選單 中找到其他選項。
在創建/編輯新條目時,定義:
- 變量
Name,內部用於生成鍵,用於在字典中存儲創建變量; - 變量
Type,可以從下拉選單中選擇一組預定義的支持類型; HasDefault勾選框用於告知變量是否在設置時初始化為預設值;- 要使用的
Default值。
現在由用戶在開發過程中決定實體 AI 需要哪些 Blackboard 條目。
PS: 可以在 Blackboard 條目上使用 滑鼠右鍵 來調用上下文選單。
目前 Blackboard 支持以下類型:
- 布林值;
- 位元;
- 整數;
- FP;
- Vector2;
- Vector3;
- 實體引用;
- 資產引用。
定義 Blackboard 後,在編譯 AI 文檔時會生成兩個額外的 Quantum 資產,預設情況下會輸出到文件夾 Assets/Resources/DB/CircuitExport/Blackboard_Assets。這些資產是:
AIBlackboardAsset具有類型和鍵佈局;AIBlackboardInitializer,如果適用,還存儲條目的初始值。
PS: 兩個資產相互引用,這使得初始化元件的代碼更簡單(代碼部分中的示例)。
Blackboard節點
定義變量後,可以將其拖放到圖中以創建 Blackboard 節點。這些節點始終有兩個輸出槽:Key和Value。
Key槽用於鏈接到類型為AIBlackboardValueKey的欄位,這些欄位可用於在獲取/設置變量的鍵時替換硬編碼字串。當然,刪除硬編碼鍵,代碼變得更加靈活和可靠。
讓我們從Quantum代碼的角度分析,根據使用的是硬編碼字串鍵還是 Blackboard 節點的鍵,應如何使用獲取/設置方法:
C#
// -- Using hardcoded keys --
var bbComponent = f.Unsafe.GetPointer<AIBlackboardComponent>(entityRef);
// Reading
var value = bbComponent->GetInteger(frame, "someKey");
// Writing
bbComponent->Set(frame, "someKey", value);
// -- Using keys from Blackboard nodes --
public AIBlackboardValueKey PickupsKey;
// Reading
var value = bbComponent->GetInteger(frame, PickupsKey.Key);
// Writing
bbComponent->Set(frame, PickupsKey.Key, value);
聲明該新字段後,可以直接在視覺編輯器中將其與 Blackboard 節點的Key槽連接:
除了使用所解釋的Key槽外,還可以連結Value槽來定義相同類型的欄位(一個整數黑板變數連結到某些節點上的整數欄位,如Actions、BTLeaf、Response Curves等)。左側面板上定義的Default值是將使用的值(內嵌到目標節點資產中)。
Blackboard Quantum代碼
初始化黑板元件
初始化黑板元件的重要部分是引用在視覺編輯器上編譯AI檔案後創建的AIBlackboardInitializer資產。
然後,在模擬程式碼上,使用以下命令初始化元件:
C#
// -- Blackboard setup
// First, create the blackboard component (or have it created on the Entity Prototype)
var blackboardComponent = new AIBlackboardComponent();
// Find the Blackboard Initializer asset
var bbInitializerAsset = f.FindAsset<AIBlackboardInitializer>(blackboardAsset.BlackboardInitializer.Id);
// Call the static initialization method passing the blackboard component and the asset
AIBlackboardInitializer.InitializeBlackboard(f, &blackboardComponent, bbInitializerAsset);
// Set the blackboard into to the entity
f.Set(littleGuyEntity, blackboardComponent);
就是這樣。一旦初始化完成,它就可以使用其API從黑板上讀取/寫入了:
C#
// There is one method for each specific blackboard type (int, byte, FP, boolean, FP vectors and entityRef)
blackboardComponent->GetInteger(frame, key);
// For the setter method, there are different overrides depending on the type of data passed as the value
blackboardComponent->Set(frame, key, value);
使用實體原型
還可以使用實體原型中的元件以Unity編輯器引用黑板資源。新增AIBlackboardComponent並定義Board欄位。然後,如果需要,在初始化步驟的模擬中使用它。
處置黑板元件
在銷毀使用Blackboard元件的實體時,釋放該元件以避免記憶體洩漏 非常重要。
要處置黑板記憶體,請使用blackboardComponent->Free(frame);
使用元件回調進行初始化和清除
SDK附帶的BotSDKSystem有一個示例,說明如何使用OnComponentAdded和OnComponentRemoved回調來初始化/釋放AIBlackboardComponent。
PS.: Bot SDK已經附帶了一些示例代碼,演示了如何使用Blackboard進行讀取/寫入,位於:BotSDK/Samples,並檢查檔案IncreaseBlackboardInt.cs、SetBlackboardInt.cs和HFSM.CheckBlackboardInt.cs