This document is about: QUANTUM 3
SWITCH TO

Snippets

這裡提供了一些可與 Bot SDK 一起使用的實用程式碼片段。

複合型代理

有時候,在同一個實體中使用多個 AI 代理元件可能會很有用。
例如,可能有一個 HFSM 專門負責實體的移動,而另一個 HFSM 則僅負責攻擊目標。
甚至可以在同一個實體中混合使用不同的技術:也許部分工作由 HFSM 完成,另一部分則由 BT 完成。

當需要這樣的設置時,為實體提供多個記憶體儲存空間也會很有用。在 Bot SDK 中,通常(但不是強制性的)會使用 AIBlackboard 元件。

以下是一些程式碼片段,展示了如何將多個元件新增到單個實體中,以創建我們在此稱為「複合型代理」的實體:

創建複合元件

在 DSL(任何.qtn檔案)中,新增以下元件。
可以根據遊戲需求為元件命名,或將其以通用方式新增到列表中。
在這個範例中,有一個 HFSM 僅負責移動實體,另一個則負責攻擊(僅供說明):

Qtn

component CompoundAgents
{
    HFSMAgent MovementHFSMAgent;
    HFSMAgent AttackHFSMAgent;

    AIBlackboardComponent MovementBlackboard;
    AIBlackboardComponent AttackBlackboard;

    AssetRefAIBlackboardInitializer MovementBBInitializer;
    AssetRefAIBlackboardInitializer AttackBBInitializer;
}

擴展 AIContext

創建一個AIContextUser的部分實現。這裡的上下文僅為範例:「根據更新的實體,正在更新的是哪個 HFSM?該 HFSM 使用哪個 Blackboard?」等等:

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;
    }
  }
}

初始化代理與 Blackboard

這裡以 ISignalOnComponentAdded 為例,但也可以根據用戶偏好進行調整:

C#

public void OnAdded(Frame frame, EntityRef entity, CompoundAgents* compoundAgents)
{
    // Initialise Agents
    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);

    // Initialise Blackboards
    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);
}

更新所有代理

創建 AI 上下文並填充每個 HFSM 和 Blackboard,然後執行更新:

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 專用的 Blackboard

以下是一個動作的程式碼片段,該動作會寫入上下文專用的 Blackboard。請注意,它是與具體 Blackboard 無關的,因此程式碼是解耦的,無需在動作中新增大量樣板程式碼來確定應該使用哪個 Blackboard。

這裡有一個 擴展方法,可以轉換為用戶上下文類型:

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