ai-behavior-trees-utility-ai

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Behavior Trees & Utility AI

行为树与Utility AI

Two complementary ways to structure NPC decision-making, plus how to combine them. A behavior tree (BT) expresses structured, prioritized, reactive logic as a tree that is "ticked" each step. Utility AI answers "how much do I want each option right now?" by scoring actions with normalized curves and picking the best. Ship believable agents by using a BT for structure and Utility AI where graded trade-offs matter.
This skill is the implementation companion to
game-ai
(which helps you choose between FSM / BT / steering / pathfinding). Read
game-ai
to pick a model; read this to build the runtime.
两种互补的NPC决策逻辑构建方式,以及如何将二者结合。**行为树(BT)**将结构化、优先级明确的响应式逻辑表达为一棵树,每一步都会对其进行"tick"(遍历执行)。Utility AI则通过归一化曲线为动作打分,选出最优选项,以此回答"我现在有多想要每个选项?"的问题。通过使用行为树构建结构,在需要梯度权衡的场景使用Utility AI,即可打造出真实可信的智能体。
本技能是
game-ai
实现配套技能
game-ai
帮助你在FSM/行为树/转向算法/寻路之间做选择)。先阅读
game-ai
选择合适的模型,再阅读本技能来构建运行时。

When to use

适用场景

  • Use to build a reusable BT runtime: a
    Blackboard
    ,
    Node
    base, action/condition leaves,
    Sequence
    /
    Selector
    /
    Parallel
    composites, and decorators (Inverter, Cooldown, Repeat).
  • Use to build a Utility AI decider: response curves, considerations, and an evaluator that scores and selects actions (max, softmax, or weighted-random for variety).
  • Use to build hybrid AI — a BT whose leaf delegates the "which attack / which target" choice to a utility evaluator.
When not to use: to choose between FSM, BT, steering, or pathfinding, and for A*/navmesh routing, use
game-ai
. For Unreal's asset-based
BehaviorTree
/
Blackboard
,
BTTask
/
BTService
and
AIController
, use
unreal-behavior-trees
. For the navmesh agent that moves the NPC, use
unity-navmesh
or the engine's navigation node.
  • 用于构建可复用的BT运行时:包含
    Blackboard
    Node
    基类、动作/条件叶节点、
    Sequence
    /
    Selector
    /
    Parallel
    组合节点,以及装饰器(反转器、冷却器、重复器)。
  • 用于构建Utility AI决策器:包含响应曲线、考量因素,以及对动作进行打分和选择的评估器(最大值选择、softmax选择或加权随机选择以增加多样性)。
  • 用于构建混合AI——行为树的叶节点将"选择哪种攻击/哪个目标"的决策委托给Utility评估器。
不适用场景:若需在FSM、行为树、转向算法或寻路之间做选择,或者处理A*/导航网格路由,请使用
game-ai
。针对Unreal中基于资源的
BehaviorTree
/
Blackboard
BTTask
/
BTService
AIController
,请使用
unreal-behavior-trees
。用于控制NPC移动的导航网格智能体,请使用
unity-navmesh
或引擎自带的导航节点。

Core workflow

核心工作流程

  1. Pick the model. Structured, prioritized, interruptible behavior → BT. Continuous "score every option" decisions (targeting, needs, item choice) → Utility. Both → hybrid.
  2. Design the Blackboard first. One typed key/value store per agent is the shared memory that decouples nodes; leaves read/write it and never hold references to each other.
  3. Write leaves. Conditions return
    Success
    /
    Failure
    immediately; actions return
    Running
    across frames until they finish. Keep leaves small and side-effect-explicit.
  4. Compose.
    Selector
    = OR/fallback (first non-failure wins);
    Sequence
    = AND (stop at first non-success);
    Parallel
    for concurrent branches. Wrap with decorators for policy (invert, cooldown, repeat, force-success).
  5. For Utility: enumerate considerations, map each raw fact through a normalized 0..1 curve, combine (weighted product with compensation, or weighted sum), then select the max — add hysteresis so agents don't flip-flop on ties.
  6. Tick deliberately. Tick the tree/evaluator once per decision step (often slower than render). Preserve
    Running
    state between ticks; verify by drawing the active path and the per-action scores on screen while tuning.
  1. 选择模型。结构化、优先级明确、可中断的行为 → 行为树。持续"为所有选项打分"的决策(目标选择、需求判断、物品选择)→ Utility AI。两者都需要 → 混合模型
  2. 先设计Blackboard。每个智能体拥有一个带类型的键值存储作为共享内存,实现节点解耦;叶节点仅对其进行读写,彼此之间绝不持有引用。
  3. 编写叶节点条件节点立即返回
    Success
    /
    Failure
    动作节点在多帧中返回
    Running
    直到完成。叶节点要保持精简,副作用需明确。
  4. 组合节点
    Selector
    =逻辑或/回退(第一个非失败的子节点胜出);
    Sequence
    =逻辑与(遇到第一个非成功的子节点即停止);
    Parallel
    用于并发分支。使用装饰器包装节点以实现策略(反转、冷却、重复、强制成功)。
  5. 针对Utility AI:枚举考量因素,将每个原始事实通过归一化0..1曲线映射,组合结果(带补偿的加权乘积或加权求和),然后选择得分最高的选项——添加滞后机制,避免智能体在平局时反复切换。
  6. 谨慎执行tick操作。每一个决策步骤对树/评估器执行一次tick(通常比渲染速度慢)。在tick之间保留
    Running
    状态;调优时可通过在屏幕上绘制当前激活路径和每个动作的分数来验证。

Architecture at a glance

架构概览

A behavior tree evaluates top-down, left-to-right; each node returns a status up to its parent:
mermaid
flowchart TD
    Root["Selector (root)"] --> Combat["Sequence: Combat"]
    Root --> Patrol["Action: Patrol"]
    Combat --> See["Condition: CanSeePlayer?"]
    Combat --> InRange{"Selector: Reach"}
    Combat --> Attack["Action: Attack (Running)"]
    InRange --> Close["Condition: InAttackRange?"]
    InRange --> MoveTo["Action: MoveToPlayer (Running)"]
Utility AI is a scoring pipeline — every candidate action is scored, then one is selected:
text
facts (distance, health, ammo…)
      │  each fact → a normalized 0..1 response curve (consideration)
score(action) = weight · combine(consideration_1 … consideration_n)   # product+compensation or sum
select: argmax  ·  or softmax / weighted-random for variety  ·  + hysteresis to avoid jitter
Status is a three-value enum shared by every node — this is the contract that makes the tree composable:
csharp
public enum Status { Success, Failure, Running }

public abstract class Node
{
    public abstract Status Tick(Blackboard bb, float dt);
    public virtual void Reset() { }   // called when a parent abandons this subtree
}
csharp
// Selector = fallback/OR: return the first child that is not Failure.
public sealed class Selector : Composite
{
    public override Status Tick(Blackboard bb, float dt)
    {
        for (; _current < Children.Count; _current++)
        {
            var s = Children[_current].Tick(bb, dt);
            if (s != Status.Failure) return s;   // Success or Running stops the scan
        }
        _current = 0;
        return Status.Failure;                    // every child failed
    }
}
The reciprocal
Sequence
(AND — stop at first non-
Success
),
Parallel
, the
Blackboard
, the leaf base classes, and every decorator are in
references/behavior-tree-core.md
.
行为树自上而下、自左向右执行;每个节点将状态返回给父节点:
mermaid
flowchart TD
    Root["Selector (root)"] --> Combat["Sequence: Combat"]
    Root --> Patrol["Action: Patrol"]
    Combat --> See["Condition: CanSeePlayer?"]
    Combat --> InRange{"Selector: Reach"}
    Combat --> Attack["Action: Attack (Running)"]
    InRange --> Close["Condition: InAttackRange?"]
    InRange --> MoveTo["Action: MoveToPlayer (Running)"]
Utility AI是一个评分流水线——每个候选动作都会被打分,然后选择其中一个:
text
facts (distance, health, ammo…)
      │  each fact → a normalized 0..1 response curve (consideration)
score(action) = weight · combine(consideration_1 … consideration_n)   # product+compensation or sum
select: argmax  ·  or softmax / weighted-random for variety  ·  + hysteresis to avoid jitter
状态是一个三值枚举,所有节点共享该枚举——这是实现树可组合性的契约:
csharp
public enum Status { Success, Failure, Running }

public abstract class Node
{
    public abstract Status Tick(Blackboard bb, float dt);
    public virtual void Reset() { }   // called when a parent abandons this subtree
}
csharp
// Selector = fallback/OR: return the first child that is not Failure.
public sealed class Selector : Composite
{
    public override Status Tick(Blackboard bb, float dt)
    {
        for (; _current < Children.Count; _current++)
        {
            var s = Children[_current].Tick(bb, dt);
            if (s != Status.Failure) return s;   // Success or Running stops the scan
        }
        _current = 0;
        return Status.Failure;                    // every child failed
    }
}
对应的
Sequence
(逻辑与——遇到第一个非
Success
的节点即停止)、
Parallel
Blackboard
、叶节点基类以及所有装饰器的代码都在
references/behavior-tree-core.md
中。

Utility scoring in one snippet

Utility评分代码片段

csharp
// A consideration maps one raw fact to 0..1 through a response curve.
float Score(Blackboard bb)
{
    float distance01 = Curves.InverseLerp01(bb.Get<float>("distToPlayer"), 20f, 2f); // near = 1
    float health01   = Curves.Sigmoid(bb.Get<float>("health01"), k: 8f, mid: 0.4f);  // hurt = low
    // Product + compensation keeps a single 0 from vetoing while low values still dampen.
    return Curves.CompensatedProduct(new[] { distance01, health01 });
}
The full curve library (linear, quadratic, exponential, logistic/sigmoid, smoothstep), the
Consideration
/
UtilityAction
types, and the
UtilityEvaluator
selection strategies are in
references/utility-ai-system.md
.
csharp
// A consideration maps one raw fact to 0..1 through a response curve.
float Score(Blackboard bb)
{
    float distance01 = Curves.InverseLerp01(bb.Get<float>("distToPlayer"), 20f, 2f); // near = 1
    float health01   = Curves.Sigmoid(bb.Get<float>("health01"), k: 8f, mid: 0.4f);  // hurt = low
    // Product + compensation keeps a single 0 from vetoing while low values still dampen.
    return Curves.CompensatedProduct(new[] { distance01, health01 });
}
完整的曲线库(线性、二次、指数、逻辑/Sigmoid、平滑步进)、
Consideration
/
UtilityAction
类型以及
UtilityEvaluator
的选择策略都在
references/utility-ai-system.md
中。

Pitfalls

常见陷阱

  • Re-ticking a
    Running
    action from the root every frame restarts it.
    Return
    Running
    and resume where you left off; only
    Reset()
    a subtree when a parent actually abandons it.
  • Deep trees re-evaluated wholesale each tick waste time and cause thrash. Prefer shallow trees and conditional aborts (a higher-priority condition can interrupt a lower branch).
  • Un-normalized considerations. If one curve outputs 0..100 and another 0..1, the big one dominates. Every consideration must return 0..1.
  • Utility jitter on near-ties. Add hysteresis: give the currently-running action a small bonus so the agent commits instead of oscillating.
  • Allocating nodes, closures, or arrays every tick creates GC spikes. Build the tree once at spawn; keep per-tick work allocation-free.
  • 每帧从根节点重新tick处于
    Running
    状态的动作会导致其重启
    。返回
    Running
    并从中断处继续;只有当父节点真正放弃该子树时才调用
    Reset()
  • 每tick完整重新评估深度树会浪费时间并导致抖动。优先使用浅树和条件中断(高优先级条件可以中断低优先级分支)。
  • 未归一化的考量因素。如果一条曲线输出0..100,另一条输出0..1,那么前者会占据主导地位。所有考量因素必须返回0..1的值。
  • 平局时Utility AI的抖动。添加滞后机制:为当前运行的动作提供小幅加分,让智能体做出承诺而非反复摇摆。
  • 每tick分配节点、闭包或数组会导致GC峰值。在智能体生成时一次性构建树;确保每tick的操作无内存分配。

References

参考资料

  • references/behavior-tree-core.md
    — Blackboard,
    Node
    /leaf base classes, action & condition leaves,
    Sequence
    /
    Selector
    /
    Parallel
    , and the decorator library (full C#).
  • references/utility-ai-system.md
    — response-curve library,
    Consideration
    ,
    UtilityAction
    , and the
    UtilityEvaluator
    (argmax, softmax, weighted-random, hysteresis).
  • references/practical-examples.md
    — a guard Patrol→Combat BT, a villager needs-based Utility AI, and a hybrid agent, as drop-in templates.
  • references/best-practices-and-pitfalls.md
    — memory management, profiling, avoiding deep trees, event-driven aborts, and combining Utility AI with BTs (hybrid architecture).
  • references/behavior-tree-core.md
    —— Blackboard、
    Node
    /叶节点基类、动作与条件叶节点、
    Sequence
    /
    Selector
    /
    Parallel
    ,以及装饰器库(完整C#代码)。
  • references/utility-ai-system.md
    —— 响应曲线库、
    Consideration
    UtilityAction
    ,以及
    UtilityEvaluator
    (最大值选择、softmax、加权随机、滞后机制)。
  • references/practical-examples.md
    —— 守卫巡逻→战斗的行为树、基于需求的村民Utility AI,以及混合智能体,均可作为即插即用模板。
  • references/best-practices-and-pitfalls.md
    —— 内存管理、性能分析、避免深度树、事件驱动中断,以及Utility AI与行为树的结合(混合架构)。

Related skills

相关技能

  • game-ai
    — choose between FSM / BT / steering; A* and navmesh pathfinding.
  • unreal-behavior-trees
    — Unreal's asset-based BT/Blackboard, tasks, decorators, services.
  • unity-navmesh
    — the
    NavMeshAgent
    that carries out "move to" intents.
  • physics-tuning
    — agent radius, movement, and collision response for the motion layer.
  • tower-defense
    ,
    fps-shooter
    ,
    rpg
    — genres that compose this decision layer.
  • game-ai
    —— 在FSM/行为树/转向算法间做选择;A*和导航网格寻路。
  • unreal-behavior-trees
    —— Unreal中基于资源的BT/Blackboard、任务、装饰器、服务。
  • unity-navmesh
    —— 执行"移动到"指令的
    NavMeshAgent
  • physics-tuning
    —— 智能体半径、移动和碰撞响应的运动层调优。
  • tower-defense
    fps-shooter
    rpg
    —— 会用到该决策层的游戏类型。