Blackboard
はじめに
Blackboard は、Bot SDKに含まれているとても便利なツールです。
独自のカスタマイズされたデータを保持するために使用できるキー/値のセットです。
コンポーネントに保存されたカスタムデータを保持するのと同じような作用を持ちますが、主な違いはこれがDSLで物を作成したり再コンパイルする必要なくUnityのVisual Editorで作成されるためとても動的であるという点です。
エージェントごとに保持できるActionおよびDecisionの読み取り/書き込みメモリのようなものです。
Blackboardはデータアセットを使用して完全に定義され、Visual Editorのみを使用して作成されるため、設計者にとっても使いやすいです。
つまり、UnityプロジェクトでBlackboardを保存および整理することができます。
PS: Blackboardデータアセットは単なるメモリレイアウト定義であることを理解することが重要です。
同じメモリレイアウトを持つボット/エンティティが多数ある場合、それらはすべて同じBlackboardアセットを指すことができます。
これらのボットはそれぞれ、レイアウトに基づいて 独自のメモリ を持ちます。
シンプルな例
マップ上のいくつかのアイテムを集めるキャラクターがあるとします。
ActionとDecisionで特定のDecisionを下すために、キャラクターがすでに収集したアイテムの量を読む必要があります。
また、キャラクターがアイテムをもう一つ収集した際、アイテム数を増やす必要があります。
このために、整数型のItemsAmount
という名前のエントリをBlackboardに作成し、ActionおよびDecisionコードで管理します。
すべてのエンティティにはランタイム時に作成される独自のblackboardメモリがあります。一つのエンティティがほかのエンティティのblackboardメモリを読み込むこともできるということです。blackboardメモリは1つだけでは なく、全てのエージェント間で共有されるものです。つまり、エージェントごとに一つ となります。
Visual EditorのBlackboard
Visual EditorにはすでにBlackboardのサブメニューが付属しています。
Blackboard Variablesという名前で、左側のパネルからアクセスできます。
+ ボタンを押して、新しいBlackboard変数を作成することができます。
新しいエントリの作成・編集を行う際は、以下を定義します。
- 変数の
Name
。blackboardアセット上、内部でKeyとして使用され変数の値を取り出します; - 変数の
Type
。ドロップダウンメニューから検索します; HasDefault
チェックボックス。設定上この変数がデフォルト値に初期化されるかされないか通知するのに使用されます。;- 使用される
Default
値。
多くの型を持つ沢山のエントリを持つことができます。それらのすべてがデフォルト値を持つ必要はありません:
現在Blackboardが対応しているタイプは以下の通りです。
Boolean;
Byte;
Integer;
FP;
Vector2;
Vector3;
Entity Ref.
これで、プロジェクトをコンパイルするたびに、フォルダAssets/Resources/DB/CircuitExport/Blackboard_Assets
に2つの追加のデータアセットが自動的に作成されます。
- コンパイル済みHFSMによって定義されたエントリをもつ Blackboard アセット。
- コンパイル済みHFSMによって定義されたエントリとデフォルト値をもつ Blackboard Initializer アセット。
アセットはお互いに関連づいています。一つ目のアセットは単にレイアウトで、二つ目のアセットはblackboardが初期化される際に挿入する値を定義しています。
これらはすでに情報の読み取り/書き込みに使用できます。
Blackboardノード
変数がある場合、グラフにドラッグ&ドロップしてノードを作成できます。これらのノードには常にKey
とValue
という、2つのアウトバウンドスロットがあります。
Key
スロットはAIBlackboardValueKey
種類のフィールドにリンクするため使用されます。このフィールドは、取得・設定する変数のキーを通知するときにハードコードされた文字列を置き換えるのに使用します。そしてもちろん、ハードコードされたキーを削除することで、コードはよりリライアブルになり、柔軟性も上がります。
ハードコードされたキーを使用している場合、またはBlackboardノードのキーを使用している場合それぞれのGet/Setメソッドの使用法についてQuantumコードの観点から分析してみましょう。
C#
// -- Using hardcoded keys: --
var bbComponent = f.Unsafe.GetPointer<AIBlackboardComponent>(entityRef);
// To read
var value = bbComponent->GetInteger(frame, "someKey");
// To write
bbComponent->Set(frame, "someKey", value);
// -- Using keys from Blackboard nodes: --
public AIBlackboardValueKey PickupsKey;
// To read
var value = bbComponent->GetInteger(frame, PickupsKey.Key);
// To write
bbComponent->Set(frame, PickupsKey.Key, value);
この新しいフィールドが宣言されると、Visual Editorへ移動して、Blackboard Nodeの Key
スロットをつなげることができます。例:
Key
スロットをこのように使用する他、Value
スロットをつなげて同じ種類のフィールドを定義することも可能です(Action/Decision上で整数フィールドにリンクされている整数のblackboard変数など)。左のパネルで定義されているDefault
値はアセットにベイクする値となります。
Blackboardおよびそのノードを使用するタイミング
いつでも好きな時に使用して、ランタイム中に変更する可能性のあるデータのプレエンティティを保管します。変わることのない値を定義する必要がある場合は、代わりにコンスタントパネルを使用してみてください。
Blackboard Quantumコード
Blackboardコンポーネントを初期化します
blackboardコンポーネントを初期化するのに大切なことは、Visual Editorで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>(runtimeConfig.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を使用してBlackboardから読み取り・書き込みを行うことができるようになります。
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);
Blackboardコンポーネントの破棄
Blackboardコンポーネントを使用するエンティティを破棄する場合には、メモリリークを避けるため、コンポーネントを解放することが重要です。
Blackboardメモリを破棄するには、blackboardComponent->Free(frame);
を使用します。
PS.: バージョン1.0 RC2以降のBotSDK には既にActions/Decisionsのサンプルが搭載されています。quantum_code
ソリューションで、BotSDK/Samples
フォルダを開き、IncreaseBlackboardInt.cs
、SetBlackboardInt.cs
、 HFSM.CheckBlackboardInt.cs
のファイルを確認してください。