unreal-behavior-trees

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Unreal Behavior Trees

Unreal Behavior Trees

Author NPC decision-making in UE5 with Behavior Trees driven by a Blackboard: structure the tree with composites, gate branches with decorators, keep state current with services, and run it from an AIController. Targets UE 5.4+.
在UE5中基于Blackboard驱动的Behavior Trees编写NPC决策逻辑:使用组合节点构建树结构,用装饰器控制分支开启,通过服务保持状态更新,并通过AIController运行行为树。适用于**UE 5.4+**版本。

When to use

使用场景

  • Use when building enemy/NPC AI: creating a
    BT_
    /
    BB_
    asset pair, structuring Selector/Sequence branches, adding decorators (conditions) and services (periodic updates), writing custom
    BTTask
    /
    BTService
    nodes, or wiring an AIController to run the tree.
  • Use when the project has Behavior Tree (
    BT_
    ) and Blackboard (
    BB_
    ) assets and an
    AAIController
    .
When not to use: the concept of AI (FSM vs BT vs steering, cross-engine) →
game-ai
. Pure navigation/pathing math is engine navmesh (BT's
MoveTo
uses it). Simple one-off logic may be cheaper as a small state machine than a full tree.
  • 适用于构建敌人/NPC AI:创建
    BT_
    /
    BB_
    资源对、构建Selector/Sequence分支、添加装饰器(条件判断)和服务(周期性更新)、编写自定义
    BTTask
    /
    BTService
    节点,或者将AIController与行为树关联运行。
  • 适用于项目中已存在Behavior Tree(
    BT_
    )、Blackboard(
    BB_
    )资源以及
    AAIController
    的场景。
不适用场景: AI概念层面的内容(有限状态机FSM vs 行为树BT vs 转向算法、跨引擎对比)→ 参考
game-ai
。纯导航/路径计算属于引擎导航网格(BT的
MoveTo
节点会用到)。简单的一次性逻辑用小型状态机实现比完整行为树更高效。

Core workflow

核心工作流程

  1. Create the pair: a Blackboard (
    BB_
    ) holds typed keys (the AI's memory:
    TargetActor
    ,
    LastKnownLocation
    ,
    bIsInvestigating
    ); a Behavior Tree (
    BT_
    ) references that Blackboard.
  2. Possess and run. An
    AAIController
    possesses the pawn and calls
    RunBehaviorTree(BT)
    , which also initializes the referenced Blackboard.
  3. Structure with composites. Selector runs children left→right until one succeeds (priority/fallback: "attack, else chase, else patrol"). Sequence runs children until one fails (do-all: "move to cover → reload → peek"). Simple Parallel runs one main task alongside a secondary.
  4. Gate branches with Decorators that read Blackboard keys (e.g. "Has Target?" guards the combat branch). Set Observer Aborts so the tree re-evaluates when the key changes.
  5. Keep the Blackboard current with Services attached to a branch — they tick periodically (e.g. update
    TargetActor
    via a sight check) only while that branch is active.
  6. Do work in Tasks, which return
    Succeeded
    ,
    Failed
    , or
    InProgress
    (latent tasks like
    MoveTo
    finish later).
  7. Verify with the Behavior Tree debugger during PIE — it highlights the running node and shows live Blackboard values, so you see exactly which branch executes.
  1. 创建资源对: Blackboard(
    BB_
    )存储带类型的键值(即AI的记忆数据:
    TargetActor
    LastKnownLocation
    bIsInvestigating
    );Behavior Tree(
    BT_
    )关联该Blackboard。
  2. 控制并运行:
    AAIController
    控制Pawn并调用
    RunBehaviorTree(BT)
    ,该方法同时会初始化行为树关联的Blackboard。
  3. 用组合节点构建结构: **Selector(选择器)**从左到右执行子节点,直到某个子节点执行成功(优先级/ fallback逻辑:“攻击,否则追击,否则巡逻”)。**Sequence(序列节点)**执行子节点直到某个子节点执行失败(全执行逻辑:“移动到掩体 → reload → 探头”)。**Simple Parallel(简单并行节点)**同时执行一个主任务和一个次要任务。
  4. 用装饰器控制分支: 装饰器读取Blackboard键值(例如“是否有目标?”作为战斗分支的守卫条件)。设置Observer Aborts(观察者中断),以便当键值变化时重新评估行为树。
  5. 用服务保持Blackboard状态更新: 将服务附加到分支上——仅当该分支处于激活状态时,服务才会周期性执行(例如通过视野检测更新
    TargetActor
    )。
  6. 在任务中执行操作: 任务返回
    Succeeded
    Failed
    InProgress
    (像
    MoveTo
    这样的延迟任务会稍后完成)。
  7. 验证调试: 在PIE(Play In Editor)模式下使用行为树调试器——它会高亮当前运行的节点并显示Blackboard的实时值,让你清晰看到哪个分支在执行。

Patterns

常见模式

1. AIController that runs the tree (C++)

1. 运行行为树的AIController(C++实现)

cpp
void AEnemyAIController::OnPossess(APawn* InPawn)
{
    Super::OnPossess(InPawn);
    if (BehaviorTree)                 // UPROPERTY(EditAnywhere) TObjectPtr<UBehaviorTree>
        RunBehaviorTree(BehaviorTree); // initializes & uses the Blackboard the BT references
}
cpp
void AEnemyAIController::OnPossess(APawn* InPawn)
{
    Super::OnPossess(InPawn);
    if (BehaviorTree)                 // UPROPERTY(EditAnywhere) TObjectPtr<UBehaviorTree>
        RunBehaviorTree(BehaviorTree); // initializes & uses the Blackboard the BT references
}

2. A priority tree (node structure)

2. 优先级行为树(节点结构)

text
ROOT
└── Selector (try combat, else investigate, else patrol)
    ├── Sequence            [Decorator: Blackboard 'TargetActor' Is Set, Observer Aborts: Both]
    │     ├── Task: MoveTo (TargetActor)          // latent: returns InProgress then Succeeded
    │     └── Task: Attack
    ├── Sequence            [Decorator: 'LastKnownLocation' Is Set]
    │     ├── Task: MoveTo (LastKnownLocation)
    │     └── Task: Wait (3s) + clear key
    └── Task: Patrol (BTTask_FindPatrolPoint -> MoveTo)
Observer Aborts: Both
makes the combat branch interrupt patrol the instant
TargetActor
is set, and bail out when it's cleared — this is what makes the AI feel reactive.
text
ROOT
└── Selector (try combat, else investigate, else patrol)
    ├── Sequence            [Decorator: Blackboard 'TargetActor' Is Set, Observer Aborts: Both]
    │     ├── Task: MoveTo (TargetActor)          // latent: returns InProgress then Succeeded
    │     └── Task: Attack
    ├── Sequence            [Decorator: 'LastKnownLocation' Is Set]
    │     ├── Task: MoveTo (LastKnownLocation)
    │     └── Task: Wait (3s) + clear key
    └── Task: Patrol (BTTask_FindPatrolPoint -> MoveTo)
Observer Aborts: Both
设置会让战斗分支在
TargetActor
被设置的瞬间中断巡逻,当该键值被清空时退出战斗分支——这正是让AI具备响应性的关键。

3. Updating the Blackboard from code (e.g. on seeing the player)

3. 通过代码更新Blackboard(例如发现玩家时)

cpp
void AEnemyAIController::SetTarget(AActor* Target)
{
    if (UBlackboardComponent* BB = GetBlackboardComponent())
        BB->SetValueAsObject(TEXT("TargetActor"), Target);   // key name must match the BB asset
}
// Clear with BB->ClearValue(TEXT("TargetActor")); to drop back to a lower-priority branch.
cpp
void AEnemyAIController::SetTarget(AActor* Target)
{
    if (UBlackboardComponent* BB = GetBlackboardComponent())
        BB->SetValueAsObject(TEXT("TargetActor"), Target);   // key name must match the BB asset
}
// Clear with BB->ClearValue(TEXT("TargetActor")); to drop back to a lower-priority branch.

Pitfalls

常见陷阱

  • AI never starts — the pawn isn't possessed (set the Pawn's Auto Possess AI to "Placed in World or Spawned" and assign the AIController), or
    RunBehaviorTree
    was never called.
  • MoveTo
    instantly fails
    — no NavMesh in the level (add a Nav Mesh Bounds Volume), or the target is off the navmesh.
  • Branch doesn't react to changes — the gating Decorator's Observer Aborts is set to None; set it to Self/Lower Priority/Both so the tree re-evaluates when the key changes.
  • A task hangs the tree — a custom task returned
    InProgress
    and never calls
    FinishLatentTask
    . Always complete latent tasks.
  • Blackboard key typos
    SetValueAsObject("Taget", ...)
    silently does nothing; match the key name and type exactly, or use a cached
    FBlackboardKeySelector
    .
  • Sequence vs Selector confusion — Sequence = AND (stops on first failure); Selector = OR (stops on first success). Swapping them inverts the behaviour.
  • AI从未启动——Pawn未被控制(将Pawn的Auto Possess AI设置为“Placed in World or Spawned”并指定AIController),或者从未调用
    RunBehaviorTree
    方法。
  • MoveTo
    立即失败
    ——关卡中没有导航网格(添加Nav Mesh Bounds Volume),或者目标不在导航网格上。
  • 分支不响应变化——控制分支的装饰器的Observer Aborts设置为None;将其设置为Self/Lower Priority/Both,以便当键值变化时重新评估行为树。
  • 任务阻塞行为树——自定义任务返回
    InProgress
    但从未调用
    FinishLatentTask
    。延迟任务必须始终完成。
  • Blackboard键值拼写错误——
    SetValueAsObject("Taget", ...)
    会静默失败;键值名称和类型必须与Blackboard资源完全匹配,或使用缓存的
    FBlackboardKeySelector
  • 混淆Sequence和Selector——Sequence = 逻辑与(遇到第一个失败则停止);Selector = 逻辑或(遇到第一个成功则停止)。两者互换会导致行为完全相反。

References

参考资料

  • For a custom C++
    UBTTaskNode
    (instant and latent
    ExecuteTask
    returning
    EBTNodeResult
    , with a
    FBlackboardKeySelector
    ), read
    references/custom-bttask.md
    .
  • Primary docs: "Behavior Trees in Unreal Engine" (
    https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine
    ).
  • 如需了解自定义C++
    UBTTaskNode
    (即时任务和延迟任务的
    ExecuteTask
    返回
    EBTNodeResult
    ,搭配
    FBlackboardKeySelector
    ),请阅读
    references/custom-bttask.md
  • 官方主文档:“Behavior Trees in Unreal Engine” (
    https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine
    ).

Related skills

相关技能

  • game-ai
    — engine-agnostic AI design (FSM, BT, steering, pathfinding choices).
  • unreal-cpp-gameplay
    — the AIController and pawn classes in C++.
  • fps-shooter
    /
    tower-defense
    — genres that compose enemy AI.
  • game-ai
    ——与引擎无关的AI设计(有限状态机FSM、行为树BT、转向算法、路径选择)。
  • unreal-cpp-gameplay
    ——C++中的AIController和Pawn类。
  • fps-shooter
    /
    tower-defense
    ——需要组合敌人AI的游戏类型。