スニペット
Bot SDKで使用できる便利なコードスニペットを紹介します。
Compound Agents(複合エージェント)
同じエージェント内で複数のAIエージェントコンポーネントを動作させると便利なこともあります。
例えば、あるHFSMはエンティティの移動のみを担当し、別のHFSMはターゲットに対する攻撃のみを担当する場合などです。
同じエージェント内で異なるAIモデルを混在させる(例:動作の一部をHFSMで処理し、別の部分をBTで処理する)ことも可能です。
こういった構成が必要な場合、エンティティに複数のメモリストレージを用意すると良いでしょう。Bot SDKでは、AIBlackboardコンポーネントを使用するのが一般的(必須ではない)です。
以下のコードスニペットは、単一のエンティティに複数のコンポーネントを追加して、「複合エージェント」を持つエンティティを作成する方法を示します。
複合エージェントコンポーネントの作成
DSL(任意の.qtnファイル)に、以下のコンポーネントを追加してください。
コンポーネントは、ゲーム固有の意味のある名前を付けるか、汎用的な方法でリストに追加してください。
今回の例では、エンティティの移動のみを担当するHFSMと、攻撃を担当するHFSMを用意します。
Qtn
component CompoundAgents
{
HFSMAgent MovementHFSMAgent;
HFSMAgent AttackHFSMAgent;
AIBlackboardComponent MovementBlackboard;
AIBlackboardComponent AttackBlackboard;
AssetRefAIBlackboardInitializer MovementBBInitializer;
AssetRefAIBlackboardInitializer AttackBBInitializer;
}
AIContextの拡張
AIContextUserの部分実装を作成します。今回の例におけるコンテキストは「更新されたエンティティが与えられた時、どのHFSMが更新されるのか?どのブラックボードを使用するのか?」などになります。
C#
namespace Quantum
{
public unsafe partial struct AIContextUser
{
public readonly AIBlackboardComponent* Blackboard;
public readonly HFSMAgent* HFSMAgent;
public AIContextUser(AIBlackboardComponent* blackboard, HFSMAgent* hfsmAgent)
{
Blackboard = blackboard;
HFSMAgent = hfsmAgent;
}
}
}
エージェントとブラックボードの初期化
今回の例ではISignalOnComponentAdded<CompoundAgents>内で初期化していますが、どこで行うかは開発者の自由です。
C#
public void OnAdded(Frame frame, EntityRef entity, CompoundAgents* compoundAgents)
{
// エージェントの初期化
HFSMRoot hfsmRoot = frame.FindAsset<HFSMRoot>(compoundAgents->MovementHFSMAgent.Data.Root.Id);
HFSMManager.Init(frame, &compoundAgents->MovementHFSMAgent.Data, entity, hfsmRoot);
hfsmRoot = frame.FindAsset<HFSMRoot>(compoundAgents->AttackHFSMAgent.Data.Root.Id);
HFSMManager.Init(frame, &compoundAgents->AttackHFSMAgent.Data, entity, hfsmRoot);
// ブラックボードの初期化
AIBlackboardInitializer initializer = frame.FindAsset<AIBlackboardInitializer>(compoundAgents->MovementBBInitializer.Id);
AIBlackboardInitializer.InitializeBlackboard(frame, &compoundAgents->MovementBlackboard, initializer);
initializer = frame.FindAsset<AIBlackboardInitializer>(compoundAgents->AttackBBInitializer.Id);
AIBlackboardInitializer.InitializeBlackboard(frame, &compoundAgents->AttackBlackboard, initializer);
}
各エージェントの更新
AIContextを作成し、HFSMとブラックボードをそれぞれ設定したら、更新を実行します。
C#
public override void Update(Frame frame, ref Filter filter)
{
HFSMData* movementData = &filter.CompoundAgents->MovementHFSMAgent.Data;
HFSMData* rotationData = &filter.CompoundAgents->RotationHFSMAgent.Data;
HFSMData* attackData = &filter.CompoundAgents->AttackHFSMAgent.Data;
AIContext aiContext = new AIContext();
AIContextUser movementContext = new AIContextUser(&filter.CompoundAgents->MovementHFSMAgent, &filter.CompoundAgents->MovementBlackboard);
aiContext.UserData = &userData;
HFSMManager.Update(frame, frame.DeltaTime, movementData, filter.EntityRef, ref aiContext);
AIContextUser rotationContext = new AIContextUser(&filter.CompoundAgents->RotationHFSMAgent, &filter.CompoundAgents->RotationBlackboard);
aiContext.UserData = &userData;
HFSMManager.Update(frame, frame.DeltaTime, rotationData, filter.EntityRef, ref aiContext);
AIContextUser attackContext = new AIContextUser(&filter.CompoundAgents->AttackHFSMAgent, &filter.CompoundAgents->AttackBlackboard);
aiContext.UserData = &userData;
HFSMManager.Update(frame, frame.DeltaTime, attackData, filter.EntityRef, ref aiContext);
}
AIContextからHFSM固有のブラックボードを取得
以下は、コンテキスト固有のブラックボードに書き込みを行うアクションのスニペットです。どのブラックボードでも動作するため、疎結合なコードになっています。そのため、どのブラックボードを使用するかを判断するためのボイラープレートコードを、アクションに追加する必要はありません。
ここでは、独自のコンテキスト型に変換する拡張メソッドを使用しています。
C#
namespace Quantum
{
[System.Serializable]
public unsafe class WriteBlackboardCompound : AIAction
{
public int Value;
public override void Update(Frame frame, EntityRef entity, ref AIContext aiContext)
{
aiContext.UserData().Blackboard->Set(frame, "TestInteger", Value);
}
}
}
Back to top