68 KiB
Behavior Designer Pro v2.1.12 技术评估与使用手册
版本: Behavior Designer Pro 2.1.12
作者: Opsive
架构范式: ECS 调度引擎 + MonoBehaviour/DOTS 双模 Task 混合架构
Unity 要求: 2022.3+
依赖:com.opsive.shared2.0.0、com.opsive.graphdesigner2.0.0、com.unity.burst1.8.17、com.unity.entities1.3.8
许可: Unity Asset Store EULA
包路径:Packages/com.opsive.behaviordesigner/
官方文档: https://opsive.com/support/documentation/behavior-designer-pro/
命名空间:BehaviorDesigner.Runtime、BehaviorDesigner.Runtime.Tasks
目录
- 概述与设计哲学
- 架构总览
- 核心组件
- ECS/DOTS 集成架构
- System Group 执行层级
- 核心 ECS 系统
- Task 系统架构
- Composite 任务 (组合节点)
- Decorator 任务 (装饰节点)
- Action 任务 (行为节点)
- Conditional 任务 (条件节点)
- Event 系统 (事件节点)
- Conditional Abort 机制
- Subtree 系统
- SharedVariable 系统
- 序列化与持久化
- Editor 工具链
- 性能分析
- 与 BaseGames 架构集成方案
- 优缺点总结
- 总结与建议
1. 概述与设计哲学
1.1 什么是 Behavior Designer
Behavior Designer 是 Unity 生态中最成熟的行为树 (Behavior Tree) 插件之一。v2.x Pro 版本进行了重大架构升级:
核心特性:采用 ECS 作为内部调度引擎(树遍历、分支管理、条件中断均由 Burst 编译的 ECS System 驱动),同时提供 MonoBehaviour Task 和 ECS Task 两种编程模型。自定义业务逻辑通常使用传统 MonoBehaviour Task(
Task基类),可直接访问GameObject、Transform、协程等 Unity 原生 API;而内置 Composite/Decorator 节点及高性能场景使用纯 ECS Task(ECSTask<T,C>基类),享受 Burst + Job 并行优化。两种 Task 可在同一棵行为树中混合使用。
行为树是 AI 决策的标准范式,通过树形结构组织:
- Composite (组合) — 控制子节点执行顺序 (Sequence/Selector/Parallel)
- Decorator (装饰) — 修饰子节点行为 (Inverter/Repeater/Cooldown)
- Action (行为) — 执行具体操作 (移动/攻击/等待)
- Conditional (条件) — 检查条件 (距离/Tag/碰撞)
1.2 v2.x vs v1.x 关键差异
| 维度 | v1.x (经典) | v2.x Pro (混合架构) |
|---|---|---|
| 运行时核心 | 纯 MonoBehaviour 驱动 | ECS World 调度 + MonoBehaviour/ECS 双模 Task |
| 执行引擎 | 主线程递归遍历 | ECS SystemGroup 调度 + Burst 编译 (Composite/Decorator);MonoBehaviour Task 仍由 TaskObjectSystem 在主线程执行 |
| Task 数据 | C# 对象 (GC) | ECS Task → IBufferElementData (无 GC);MonoBehaviour Task → C# 对象 (堆分配) |
| 并行能力 | 无 | ECS Task 可 IJobEntity 多树并行;MonoBehaviour Task 为主线程 |
| 可视化编辑 | 内置窗口 | 基于 GraphDesigner 新编辑器 |
| Subtree | ExternalBehaviorTree | Subtree ScriptableObject (Subgraph 属性) |
| Variable | SharedVariable | SharedVariable + ECS 兼容 |
| 序列化 | Unity 序列化 | Opsive 自定义序列化 |
| 自定义 Task | 继承 Task 基类 | 继承 Task (MonoBehaviour 模式) 或 ECSTask (DOTS 模式) |
1.3 核心设计原则
| 原则 | 说明 |
|---|---|
| 数据驱动 | 行为树资产独立于代码,策划可通过编辑器配置 |
| ECS 调度 + 双模 Task | 核心树遍历由 ECS SystemGroup 驱动(Burst 编译),业务逻辑支持 MonoBehaviour Task 和 ECS Task 两种编程模型 |
| MonoBehaviour 友好 | 自定义 Task 继承 Task 基类即可访问 GameObject/Transform/协程等,无需 ECS 知识 |
| 可组合 | Subtree 支持行为树模块化复用 |
| 可中断 | Conditional Abort 实现实时条件重评估 |
| 可扩展 | 自定义 Task 只需继承 Action/Conditional 基类 + 覆写 OnUpdate() |
2. 架构总览
2.1 整体架构图
┌──────────────────────────────────────────────────────┐
│ Editor │
│ ┌──────────────────────────────────────────────────┐│
│ │ BehaviorMainWindow (GraphDesigner 编辑器) ││
│ │ ├─ 可视化行为树编辑 ││
│ │ ├─ 节点拖拽/连线/参数配置 ││
│ │ └─ TransitionLibrary 编辑 ││
│ └──────────────────────────────────────────────────┘│
│ Opsive.BehaviorDesigner.Editor.dll │
└──────────────────────────────────────────────────────┘
│ 序列化
▼
┌──────────────────────────────────────────────────────┐
│ Runtime │
│ ┌────────────┐ ┌─────────────┐ ┌──────────────┐│
│ │ BehaviorTree│ │ Subtree │ │BehaviorTree ││
│ │ (MonoBehav) │ │ (SO Asset) │ │ Data ││
│ └──────┬─────┘ └──────┬──────┘ └──────┬───────┘│
│ │ │ │ │
│ └────────────────┼───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────┐│
│ │ ECS World ││
│ │ Entity + TaskComponent[] + BranchComponent[] ││
│ │ + EvaluationComponent + Flag Components ││
│ │ ││
│ │ BehaviorTreeSystemGroup ││
│ │ ├─ BeforeTraversalSystemGroup ││
│ │ │ └─ ReevaluateSystem ││
│ │ ├─ InterruptSystemGroup ││
│ │ │ └─ ConditionalAbortsInvokerSystem ││
│ │ └─ TraversalSystemGroup ││
│ │ ├─ EvaluationSystem ││
│ │ ├─ TraversalTaskSystemGroup ││
│ │ │ └─ [Task-specific Systems] ││
│ │ └─ DetermineEvaluationSystem ││
│ └──────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────┘
2.2 运行时目录结构
Packages/com.opsive.behaviordesigner/
├── Runtime/
│ ├── BehaviorTree.cs # MonoBehaviour 主控组件
│ ├── BehaviorTreeData.cs # 序列化数据容器
│ ├── BehaviorTreeDataStructures.cs # 辅助数据结构
│ ├── Subtree.cs # ScriptableObject 子树资产
│ ├── Components/
│ │ ├── BehaviorTreeComponents.cs # ECS 组件 (TaskComponent, BranchComponent 等)
│ │ └── BakedBehaviorTree.cs # ECS Baking 支持
│ ├── Groups/
│ │ ├── BehaviorTreeSystemGroup.cs # 根系统组
│ │ ├── BeforeTraversalSystemGroup.cs
│ │ ├── TraversalSystemGroup.cs # 遍历系统组(含循环逻辑)
│ │ └── TaskSystemGroup.cs
│ ├── Systems/
│ │ ├── TraversalSystems.cs # EvaluationSystem, DetermineEvaluationSystem
│ │ ├── BeforeTraversalSystems.cs # ReevaluateSystem, ConditionalAbortsInvokerSystem
│ │ ├── TaskObjectSystem.cs # GameObject Task 执行系统
│ │ └── CleanupSystem.cs # 清理系统
│ ├── Tasks/
│ │ ├── Task.cs # GameObject Task 基类
│ │ ├── ECSTask.cs # ECS Task 基类
│ │ ├── TaskStatus.cs # 状态枚举
│ │ ├── TaskInterfaces.cs # 接口定义
│ │ ├── ConditionalAbortType.cs # 条件中断类型
│ │ ├── StackedTask.cs # 堆叠任务
│ │ ├── TaskCoroutine.cs # 协程封装
│ │ ├── TaskDelegateBase.cs # 委托任务
│ │ ├── PlaceholderTasks.cs # 占位符
│ │ ├── UnknownTasks.cs # 未知任务处理
│ │ ├── ISubtreeReference.cs # 子树引用接口
│ │ ├── Composites/ (9 类型)
│ │ │ ├── CompositeNode.cs # 基类
│ │ │ ├── Sequence.cs # 顺序: AND 逻辑
│ │ │ ├── Selector.cs # 选择: OR 逻辑
│ │ │ ├── Parallel.cs # 并行
│ │ │ ├── ParallelSelector.cs # 并行选择
│ │ │ ├── PrioritySelector.cs # 优先级选择
│ │ │ ├── RandomSelector.cs # 随机选择
│ │ │ ├── RandomSequence.cs # 随机顺序
│ │ │ └── UtilitySelector.cs # 效用选择
│ │ ├── Decorators/ (15 类型)
│ │ │ ├── DecoratorNode.cs # 基类
│ │ │ ├── Inverter.cs # 取反
│ │ │ ├── Repeater.cs # 重复执行
│ │ │ ├── Cooldown.cs # 冷却
│ │ │ ├── Iterator.cs # 迭代
│ │ │ ├── ReturnSuccess/Failure.cs # 强制返回状态
│ │ │ ├── UntilSuccess/Failure.cs # 持续到目标状态
│ │ │ ├── ConditionalEvaluator.cs # 条件评估
│ │ │ ├── PriorityEvaluator.cs # 优先级评估
│ │ │ ├── PriorityVariableEvaluator.cs
│ │ │ ├── UtilityEvaluator.cs # 效用评估
│ │ │ ├── UtilityCurveEvaluator.cs # 效用曲线
│ │ │ └── UtilityVariableEvaluator.cs
│ │ ├── Actions/ (40+ 类型)
│ │ │ ├── Action.cs / ActionNode.cs
│ │ │ ├── Wait.cs, Idle.cs, Log.cs, LogValue.cs
│ │ │ ├── SendEvent.cs, SetSubtree.cs
│ │ │ ├── SubtreeReference.cs, SubtreeReferenceSelector.cs
│ │ │ ├── ReturnStatus.cs, PerformInterruption.cs
│ │ │ ├── Start/Stop/RestartBehaviorTree.cs
│ │ │ ├── StackedAction.cs
│ │ │ ├── TargetBehaviorTree/GameObjectAction.cs
│ │ │ ├── Conversions/ (15+ 类型转换)
│ │ │ ├── IList/ (8 集合操作)
│ │ │ ├── Math/ (13 数学运算)
│ │ │ └── UnityObjects/ (3 Unity 对象操作)
│ │ ├── Conditionals/ (28+ 类型)
│ │ │ ├── Conditional.cs / ConditionalNode.cs
│ │ │ ├── HasReceivedEvent.cs, HasValue.cs
│ │ │ ├── IsBehaviorTreeActive.cs, RandomProbability.cs
│ │ │ ├── StackedConditional.cs
│ │ │ ├── Math/ (6 比较操作)
│ │ │ └── Physics/ (8 碰撞/触发检测)
│ │ ├── Events/ (11 类型)
│ │ │ ├── EventNode.cs, Start.cs
│ │ │ ├── OnReceivedEvent.cs, OnInterrupt.cs
│ │ │ └── OnCollision/Trigger Enter/Exit 2D/3D
│ │ └── Templates/
│ │ ├── ECSNodes.cs # ECS Task 模板
│ │ └── GameObjectNodes.cs # GameObject Task 模板
│ └── Utility/
│ ├── TraversalUtility.cs # 树遍历工具
│ ├── ComponentUtility.cs # 组件管理工具
│ ├── SaveManager.cs # 存档管理
│ └── Types.cs # 类型工具
├── Editor/
│ ├── Opsive.BehaviorDesigner.Editor.dll # 编辑器 (预编译 DLL)
│ ├── Managers/ # 窗口/集成/欢迎屏幕
│ ├── NodeViews/ # 节点 UI 渲染
│ ├── Icons/ # 编辑器图标
│ └── Styles/ # USS 样式
└── Samples~/ # 示例场景和脚本
2.3 依赖关系图
com.opsive.behaviordesigner (本包)
├── com.opsive.shared (v2.0.0)
│ ├── 序列化系统 (Serialization)
│ ├── SharedVariable 系统
│ └── 反射工具
├── com.opsive.graphdesigner (v2.0.0)
│ ├── IGraph, IGraphComponent 接口
│ ├── IEventNode, ILogicNode 接口
│ └── 图编辑器框架
├── com.unity.entities (v1.3.8)
│ ├── World, Entity, EntityManager
│ ├── ISystem, IJobEntity
│ └── IComponentData, IBufferElementData
└── com.unity.burst (v1.8.17)
└── [BurstCompile] 优化
3. 核心组件
3.1 BehaviorTree (MonoBehaviour)
主入口组件,挂载在 GameObject 上,管理行为树的生命周期:
public class BehaviorTree : MonoBehaviour, IGraph, IGraphComponent, ISharedVariableContainer
{
// ─── 配置 ───
string m_GraphName; // 行为树名称
int m_Index; // 用户指定 ID
BehaviorTreeData m_Data; // 序列化数据
bool m_StartWhenEnabled; // 启用时自动开始
bool m_PauseWhenDisabled; // 禁用时暂停而非停止
// ─── 更新模式 ───
UpdateMode m_UpdateMode; // EveryFrame | Manual
EvaluationType m_EvaluationType; // EntireTree | Count
int m_MaxEvaluationCount; // Count 模式下每帧最大评估数
// ─── ECS 关联 ───
World m_World; // ECS World 引用
Entity m_Entity; // 关联的 ECS Entity
// ─── Subtree ───
Subtree m_Subtree; // 可选的外部子树引用
// ─── 静态注册表 ───
static Dictionary<Entity, BehaviorTree> s_BehaviorTreeByEntity;
static int BehaviorTreeCount;
// ─── 生命周期方法 ───
void StartBehavior(World, Entity, startBranchType);
void StartBranch(World, Entity, eventTaskType);
void InitializeTree(World, Entity);
void InitializeBranch(World, Entity, eventTask);
// ─── 序列化 ───
void Serialize();
void Deserialize(bool force);
// ─── 查找 ───
T FindTask<T>(); // 找到第一个匹配类型的 Task
void FindTasks<T>(T[] array); // 找到所有匹配类型
Task GetTask(int runtimeIndex); // 按运行时索引获取
// ─── 静态工具 ───
static BehaviorTree GetBehaviorTree(Entity entity);
// ─── 事件 ───
Action OnBehaviorTreeStarted;
Action<bool> OnBehaviorTreeStopped;
Action OnBehaviorTreeDestroyed;
// ─── 物理事件转发 ───
Action<Collision> OnBehaviorTreeCollisionEnter;
Action<Collision> OnBehaviorTreeCollisionExit;
Action<Collision2D> OnBehaviorTreeCollisionEnter2D;
Action<Collision2D> OnBehaviorTreeCollisionExit2D;
Action<Collider> OnBehaviorTreeTriggerEnter;
Action<Collider> OnBehaviorTreeTriggerExit;
Action<Collider2D> OnBehaviorTreeTriggerEnter2D;
Action<Collider2D> OnBehaviorTreeTriggerExit2D;
}
3.2 BehaviorTreeData — 序列化数据
public class BehaviorTreeData : ISerializable
{
ITreeLogicNode[] m_Tasks; // 逻辑节点数组
IEventNode[] m_EventTasks; // 事件节点数组
SharedVariable[] m_SharedVariables; // 共享变量
ushort[] m_DisabledLogicNodes; // 禁用的逻辑节点索引
ushort[] m_DisabledEventNodes; // 禁用的事件节点索引
int m_UniqueID; // 唯一数据 ID
int m_RuntimeUniqueID; // 运行时 ID
// 变量名 → SharedVariable 映射
Dictionary<VariableAssignment, SharedVariable> m_VariableByNameMap;
// 节点管理
void AddNode(ITreeLogicNode node);
void RemoveNode(ITreeLogicNode node);
void AddNode(IEventNode node);
void RemoveNode(IEventNode node);
// 序列化
void Serialize();
void Deserialize(...);
}
3.3 Subtree — ScriptableObject 子树
public class Subtree : ScriptableObject, IGraph, ISharedVariableContainer
{
BehaviorTreeData Data;
bool Pooled; // 是否池化复用
void Serialize();
void Deserialize(...);
void DeserializeSharedVariables(bool force);
void Clone(IGraph other); // 深拷贝
// 节点/事件管理
void AddNode(ITreeLogicNode);
void RemoveNode(ITreeLogicNode);
ITreeLogicNode GetNode(Type type);
IEventNode GetEventNode(Type type);
// 变量
T GetVariable<T>(string name);
void SetVariableValue<T>(string name, T value);
}
3.4 UpdateMode & EvaluationType
public enum UpdateMode
{
EveryFrame, // 每帧自动评估
Manual // 手动调用 Tick()
}
public enum EvaluationType : byte
{
EntireTree, // 评估整棵树直到找到 Running 节点
Count // 每帧最多评估 N 个节点 (性能限制)
}
4. ECS/DOTS 集成架构
4.1 核心 ECS 组件
TaskComponent (每个 Task 节点的运行时数据)
public struct TaskComponent : IBufferElementData
{
public ushort Index; // 树中的逻辑索引
public ushort ParentIndex; // 父节点索引
public ushort SiblingIndex; // 下一个兄弟节点索引
public ushort BranchIndex; // 所属分支索引
public ComponentType FlagComponentType; // 标记此 Task 活跃的 Flag 组件类型
public bool Disabled; // 是否被禁用
public TaskStatus Status; // 当前执行状态
public bool CanReevaluate; // 是否参与条件重评估
public bool Reevaluate; // 当前是否正在被重评估
}
BranchComponent (执行分支状态)
public struct BranchComponent : IBufferElementData
{
public ushort ActiveIndex; // 当前活跃 Task 索引
public ushort NextIndex; // 下一个要执行的 Task
public ushort LastActiveIndex; // 上一个活跃 Task
public ComponentType ActiveFlagComponentType; // 当前活跃 Task 的 Flag
public InterruptType InterruptType; // 中断类型
public ushort InterruptIndex; // 触发中断的 Task 索引
public bool CanExecute; // 本帧是否可执行
}
Flag 组件 (控制 Task 执行的标签组件)
每种 Task 类型有对应的 Flag 组件 (IComponentData, IEnableableComponent):
| Flag | 控制对象 |
|---|---|
EvaluateFlag |
树是否需要评估 |
EnabledFlag |
树是否启用 |
InterruptFlag |
分支是否需要中断 |
InterruptedFlag |
分支是否已被中断 |
SequenceFlag |
Sequence 节点活跃 |
SelectorFlag |
Selector 节点活跃 |
ParallelFlag |
Parallel 节点活跃 |
InverterFlag |
Inverter 节点活跃 |
TaskObjectFlag |
GameObject Task 活跃 |
| ... | 其他 Task 类型各有独立 Flag |
核心思想:通过 Flag 组件的启用/禁用控制哪些系统需要执行,避免不必要的系统调度。
EvaluationComponent (位掩码评估跟踪)
根据树中 Task 数量选择不同大小的变体:
| 变体 | 最大 Task 数 | 数据大小 |
|---|---|---|
EvaluationComponent32 |
< 192 | 32 字节 |
EvaluationComponent64 |
< 448 | 64 字节 |
EvaluationComponent128 |
< 960 | 128 字节 |
EvaluationComponent512 |
< 4,032 | 512 字节 |
EvaluationComponent4096 |
< 32,704 | 4,096 字节 |
每个 Task 在位掩码中占 1 bit,用 FixedList*Bytes<ulong> 存储。
ReevaluateTaskComponent (条件中断数据)
public struct ReevaluateTaskComponent : IBufferElementData
{
public ushort Index; // Task 索引
public ConditionalAbortType AbortType; // 中断类型
public ComponentType ReevaluateFlagComponentType; // 重评估 Flag
public ushort LowerPriorityLowerIndex; // 低优先级范围下界
public ushort LowerPriorityUpperIndex; // 低优先级范围上界
public ushort SelfPriorityUpperIndex; // 自身优先级范围
public ReevaluateStatus ReevaluateStatus; // Active/Inactive/Dirty
public TaskStatus OriginalStatus; // 重评估前的原始状态
}
InterruptType
public enum InterruptType : byte
{
None, // 无中断
Branch, // 条件中断/效用触发
ImmediateSuccess, // 立即成功中断
ImmediateFailure // 立即失败中断
}
4.2 Baking 支持
public class BakedBehaviorTree : IComponentData
{
public int StartEventConnectedIndex;
public bool StartEvaluation;
public string[] ReevaluateTaskSystems; // 重评估系统类型名
public string[] InterruptTaskSystems; // 中断系统类型名
public string[] TraversalTaskSystems; // 遍历系统类型名
public ulong[] TagStableTypeHashes; // Flag 组件类型哈希
public ulong[] ReevaluateFlagStableTypeHashes;
}
StartBakedBehaviorTreeSystem 负责将 Baked 数据还原为运行时组件。
5. System Group 执行层级
5.1 完整执行顺序
SimulationSystemGroup
└── BehaviorTreeSystemGroup (根)
├── BeforeTraversalSystemGroup (OrderFirst=true)
│ ├── ReevaluateTaskSystemGroup
│ │ └── [各 Task 类型的重评估系统]
│ └── [其他预遍历系统]
│
├── InterruptSystemGroup
│ ├── ReevaluateSystem ← 标记需要重评估的 Task
│ ├── ConditionalAbortsInvokerSystem ← 比较重评估结果,触发中断
│ ├── InterruptSystem ← 执行中断
│ ├── InterruptedCleanupSystem (可选) ← 清理中断标志
│ └── InterruptTaskSystemGroup (UpdateAfter=InterruptSystem)
│ └── [各 Task 类型的中断处理系统]
│
└── TraversalSystemGroup (UpdateAfter=InterruptSystemGroup)
├── EvaluationSystem ← Phase 1: 遍历树,激活/停用节点
│
├── TraversalTaskSystemGroup ← Phase 2: 执行活跃 Task
│ ├── OnPreUpdate() callback
│ ├── [各 Task 类型的执行系统]
│ │ ├── SequenceTaskSystem (Burst)
│ │ ├── SelectorTaskSystem (Burst)
│ │ ├── ParallelTaskSystem (Burst)
│ │ ├── InverterTaskSystem (Burst)
│ │ ├── TaskObjectSystem ← GameObject Task 执行
│ │ └── ...
│ └── OnPostUpdate() callback
│
├── DetermineEvaluationSystem ← Phase 3: 检查是否需要继续
│
└── EvaluationCleanupSystem (OrderLast=true) ← Phase 4: 重置标志
5.2 System Group 类说明
| 类 | 职责 |
|---|---|
BehaviorTreeSystemGroup |
根组,位于 SimulationSystemGroup 内。无活跃行为树时自动禁用 |
BeforeTraversalSystemGroup |
预处理:条件重评估。OrderFirst=true 确保最先执行 |
TraversalSystemGroup |
核心遍历循环:执行 Task → 评估 → 判断是否继续 → 循环 |
TraversalTaskSystemGroup |
实际 Task 执行,提供 OnPreUpdate/OnPostUpdate 扩展点 |
遍历循环机制:TraversalSystemGroup 实现内部循环 — 如果 DetermineEvaluationSystem.Evaluate == true(仍有 Running 叶子节点),则重复执行 EvaluationSystem + TraversalTaskSystemGroup + DetermineEvaluationSystem,直到所有分支稳定。
6. 核心 ECS 系统
6.1 EvaluationSystem
[BurstCompile]
public partial struct EvaluationJob : IJobEntity
{
// 对每个分支:
// 1. 检查活跃 Task 状态是否变为 Success/Failure → 回溯到父节点
// 2. 如果 NextIndex != ActiveIndex → 切换活跃 Task
// - 禁用旧 Task 的 Flag 组件
// - 启用新 Task 的 Flag 组件
// - 设置 TaskComponent.Status = Queued
// 3. 处理禁用节点 (跳过)
// 4. 重置子节点状态
}
6.2 DetermineEvaluationSystem
// 检查是否有叶子 Task 处于 Running 状态
// 使用 5 种 EvaluationComponent 大小变体的 Job 并行查询
// 输出:
// Active = true → 树仍在运行
// Evaluate = true → 需要继续评估循环
6.3 ReevaluateSystem
// 处理 Conditional Abort:
// 1. 遍历 ReevaluateTaskComponent 缓冲区
// 2. 检查 Task 是否满足重评估条件 (abort type + 范围)
// 3. 设置 ReevaluateStatus = Active
// 4. 启用重评估 Flag
// 5. 记录原始状态用于后续比较
6.4 ConditionalAbortsInvokerSystem
// 比较重评估后的 Task 状态与原始状态:
// 如果状态发生变化 → 触发 InterruptFlag → 设置 BranchComponent.InterruptType
6.5 TaskObjectSystem
// 执行 GameObject-based Task 的生命周期:
// 1. Queued → OnStart() → Running
// 2. Running → OnUpdate() → 返回 TaskStatus
// 3. Success/Failure → OnEnd()
//
// 对于 ITaskObjectParentNode:
// 使用 NextChildIndex 确定下一个子节点
// 父节点返回 Success/Failure 时中断所有子节点
6.6 EvaluationCleanupSystem
[BurstCompile]
// 每帧遍历结束后:
// - 启用 EvaluateFlag (若 EnabledFlag 启用)
// - 重置 BranchComponent.CanExecute = true
// - 重置 BranchComponent.LastActiveIndex = ushort.MaxValue
7. Task 系统架构
7.1 TaskStatus 枚举
public enum TaskStatus : byte
{
Inactive, // 未激活
Queued, // 已排队,下次 Update 开始执行
Running, // 正在执行
Success, // 执行成功
Failure // 执行失败
}
7.2 Task 基类 (GameObject-based)
public class Task
{
// ─── 引用 ───
GameObject m_GameObject;
Transform m_Transform;
BehaviorTree m_BehaviorTree;
ushort m_RuntimeIndex;
TaskStatus m_Status;
// ─── 生命周期 ───
virtual void Reset(); // 重置 Task 值
virtual void Initialize(BehaviorTree, int index); // 初始化
virtual void OnAwake(); // 初始化后
virtual void OnBehaviorTreeStarted(); // 行为树启动
virtual TaskStatus OnStart(); // Task 开始 (Queued → Running)
virtual TaskStatus OnUpdate(); // 每帧更新 (Running)
virtual void OnEnd(); // Task 结束 (Success/Failure)
// ─── 物理回调 ───
virtual bool ReceiveCollisionEnterCallback => false;
virtual void OnCollisionEnter(Collision collision);
// ... 2D 版本同理
// ─── 协程支持 ───
Coroutine StartCoroutine(string methodName);
Coroutine StartCoroutine(IEnumerator routine);
void StopCoroutine(string methodName);
void StopAllCoroutines();
}
7.3 ECSTask<TSystem, TBufferElement> (ECS-based)
public abstract class ECSTask<TSystem, TBufferElement>
where TSystem : ISystem
where TBufferElement : unmanaged, IBufferElementData
{
// 派生具体类型:
// ECSActionTask<TSystem, TComponent> : IAction
// ECSCompositeTask<TSystem, TComponent> : IComposite, IParentNode
// ECSConditionalTask<TSystem, TComponent> : IConditional
// ECSDecoratorTask<TSystem, TComponent> : IDecorator, IParentNode
abstract ComponentType Flag { get; }
abstract TBufferElement GetBufferElement();
}
7.4 双模式 Task 体系
| 模式 | 基类 | 数据存储 | 执行系统 | 性能 | 适用场景 |
|---|---|---|---|---|---|
| GameObject Task | Task / ActionNode |
C# 对象 (堆) | TaskObjectSystem |
一般 | 需访问 MonoBehaviour、自定义逻辑 |
| ECS Task | ECSTask<T,C> |
IBufferElementData (ECS) |
Burst 编译 ISystem |
最优 | 纯数据逻辑、大量实体 |
7.5 Task 接口体系
// ─── 类型标记 ───
IAction // 行为节点
IComposite // 组合节点
IConditional // 条件节点 ([ReflectedType(typeof(bool))])
IDecorator // 装饰节点
IConditionalReevaluation // 可重评估
// ─── 核心接口 ───
IAuthoringTask // ECS 创作接口
ComponentType Flag { get; }
Type SystemType { get; }
int AddBufferElement(World, Entity, GameObject);
void ClearBufferElement(World, Entity);
IReevaluateResponder // 条件重评估
ComponentType ReevaluateFlag { get; }
Type ReevaluateSystemType { get; }
IInterruptResponder // 中断响应
Type InterruptSystemType { get; }
// ─── 节点层级 ───
ITreeLogicNode // 逻辑节点基接口
IParentNode // 有子节点
IParallelNode // 并行执行子节点
IContainerNode // 堆叠容器
IEventNode // 事件入口
// ─── Task Object ───
ITaskObjectParentNode // GameObject 模式下的父节点
ushort NextChildIndex { get; }
7.6 StackedTask
允许在单个节点中堆叠多个 Task(类似行为栈):
public class StackedTask
{
Task[] m_Tasks; // 堆叠的 Task 数组
ComparisonType m_ComparisonType; // Sequence (AND) | Selector (OR)
ushort m_ActiveIndex; // 当前活跃 Task 索引
enum ComparisonType { Sequence, Selector }
void Add(object taskOrMethod);
void Remove(int index);
}
7.7 TaskCoroutine 协程支持
public class TaskCoroutine
{
Coroutine Coroutine;
void RunCoroutine(); // 执行完整协程
void Stop(); // 停止协程
delegate void TaskCoroutineEnded(TaskCoroutine, string name);
}
7.8 TaskDelegate 系统
支持方法代理到 Task 的绑定:
TaskDelegate // 无参无返回
TaskDelegate<T1..T10> // 1-10 参数,无返回
TaskValueDelegate<TReturn> // 无参有返回
TaskValueDelegate<T1..T10, TReturn> // 1-10 参数有返回
8. Composite 任务 (组合节点)
组合节点控制子节点的执行顺序和逻辑组合方式。
8.1 类型总览
| 类型 | 逻辑 | 子节点执行 | 典型用途 |
|---|---|---|---|
| Sequence | AND | 从左到右,遇 Failure 即停 | 完整行动链 (检测→移动→攻击) |
| Selector | OR | 从左到右,遇 Success 即停 | 行为选择 (攻击 | 追击 | 巡逻) |
| Parallel | 全部 | 同时执行,任一 Failure 则 Failure | 边走边瞄准 |
| ParallelSelector | 全部 | 同时执行,任一 Success 则 Success | 多种方式尝试 |
| PrioritySelector | 优先级 | 按优先值排序执行 | 动态优先级决策 |
| UtilitySelector | 效用 | 按效用分数选择 | 效用 AI |
| RandomSelector | 随机 | 随机顺序执行选择 | 随机行为 |
| RandomSequence | 随机 | 随机顺序执行顺序 | 随机化巡逻 |
8.2 Sequence (顺序节点)
// ECS 实现:
public struct SequenceComponent : IBufferElementData
{
public ushort Index;
public ushort ActiveChildIndex;
}
// Burst 编译系统:
[BurstCompile]
public partial struct SequenceTaskSystem : ISystem { ... }
// 逻辑:
// 1. 子节点 Success → 执行下一个子节点
// 2. 子节点 Failure → Sequence 返回 Failure
// 3. 所有子节点 Success → Sequence 返回 Success
// 4. 支持 ConditionalAbort (IConditionalAbortParent)
8.3 Selector (选择节点)
// 逻辑:
// 1. 子节点 Success → Selector 返回 Success
// 2. 子节点 Failure → 执行下一个子节点
// 3. 所有子节点 Failure → Selector 返回 Failure
// 4. 支持 ConditionalAbort
8.4 Parallel (并行节点)
public struct ParallelComponent : IBufferElementData
{
public ushort Index;
}
// 特殊机制:
// - 每个子节点获得独立的 BranchComponent (独立执行分支)
// - 初始化时添加中断组件
// - 任一子节点 Failure → 中断所有其他子节点 → Parallel Failure
// - 所有子节点 Success → Parallel Success
8.5 Composite 基类
public abstract class CompositeNode : Task, ITreeLogicNode, IParentNode,
IComposite, ITaskObjectParentNode
{
ushort Index { get; set; }
ushort ParentIndex { get; set; }
ushort SiblingIndex { get; set; }
ushort RuntimeIndex { get; set; }
virtual int MaxChildCount => int.MaxValue;
virtual ushort NextChildIndex => (ushort)(RuntimeIndex + 1);
}
9. Decorator 任务 (装饰节点)
装饰节点包装单个子节点,修改其行为。
9.1 类型总览
| 类型 | 行为 | 典型用途 |
|---|---|---|
| Inverter | 取反子节点状态 (Success↔Failure) | 否定条件 |
| Repeater | 重复执行子节点 N 次 | 多次攻击 |
| Cooldown | 冷却期间返回 Failure | 技能冷却 |
| Iterator | 遍历列表执行子节点 | 遍历目标 |
| ReturnSuccess | 强制返回 Success | 忽略失败 |
| ReturnFailure | 强制返回 Failure | 强制中止 |
| UntilSuccess | 重复直到 Success | 等待成功 |
| UntilFailure | 重复直到 Failure | 等待失败 |
| ConditionalEvaluator | 条件满足才执行子节点 | 条件守卫 |
| PriorityEvaluator | 按优先级评估子节点 | 动态优先级 |
| PriorityVariableEvaluator | 变量驱动的优先级评估 | 变量优先级 |
| UtilityEvaluator | 按效用分数评估 | 效用 AI |
| UtilityCurveEvaluator | 曲线驱动的效用评估 | 平滑效用 |
| UtilityVariableEvaluator | 变量驱动的效用评估 | 变量效用 |
9.2 Inverter (取反器)
public struct InverterComponent : IBufferElementData
{
public ushort Index;
}
// Flag: InverterFlag
// System: InverterTaskSystem (Burst)
//
// 逻辑:
// - 子节点 Success → Inverter Failure
// - 子节点 Failure → Inverter Success
// - 子节点 Running → Inverter Running
9.3 Decorator 基类
public abstract class DecoratorNode : Task, ITreeLogicNode, IDecorator,
IParentNode, ITaskObjectParentNode
{
int MaxChildCount => 1; // 只允许一个子节点
ushort NextChildIndex => (ushort)(RuntimeIndex + 1);
}
10. Action 任务 (行为节点)
行为节点是行为树的叶子节点,执行具体操作。
10.1 内置 Action 分类
流程控制
| Task | 功能 |
|---|---|
Wait |
等待指定时长 |
Idle |
空操作,立即返回 Success |
Log |
输出日志 |
LogValue |
输出变量值 |
ReturnStatus |
返回指定状态 |
PerformInterruption |
手动触发中断 |
行为树控制
| Task | 功能 |
|---|---|
StartBehaviorTree |
启动另一棵行为树 |
StopBehaviorTree |
停止另一棵行为树 |
RestartBehaviorTree |
重启行为树 |
TargetBehaviorTreeAction |
作用于目标行为树 |
TargetGameObjectAction |
作用于目标 GameObject |
事件与子树
| Task | 功能 |
|---|---|
SendEvent |
发送命名事件 |
SetSubtree |
设置活跃子树 |
SubtreeReference |
引用子树 |
SubtreeReferenceSelector |
选择性引用子树 |
数学运算
| Task | 功能 |
|---|---|
BoolFlip |
布尔取反 |
BoolOperator |
AND/OR/XOR |
FloatOperator |
加/减/乘/除 float |
IntOperator |
加/减/乘/除 int |
RandomBool/Float/Integer |
随机值 |
SetBool/Float/Int/String |
设置变量 |
SetVector2/Vector3 |
设置向量 |
集合操作
| Task | 功能 |
|---|---|
AddGameObjectToArray/List |
添加到集合 |
RemoveGameObjectFromArray/List |
从集合移除 |
SelectGameObjectFromArray/List |
按索引选择 |
RandomGameObjectFromArray/List |
随机选择 |
类型转换
| Task | 功能 |
|---|---|
ConvertBoolToFloat/Int/String |
Bool 转换 |
ConvertFloatToInt/String/Bool |
Float 转换 |
ConvertIntToFloat/String |
Int 转换 |
ConvertStringToBool/Float/Int |
String 转换 |
ConvertGameObjectToTransform |
GO ↔ Transform |
Unity 对象
| Task | 功能 |
|---|---|
SetEnabled |
启用/禁用 GameObject |
SetGameObject |
设置 GameObject 变量 |
WaitForAnimatorState |
等待 Animator 状态 |
10.2 自定义 Action 编写示例
[TaskCategory("MyGame")]
[TaskDescription("向目标移动")]
public class MoveToTarget : Action
{
[SerializeField] private SharedGameObject _target;
[SerializeField] private SharedFloat _speed;
[SerializeField] private SharedFloat _stopDistance;
public override void OnStart()
{
// 初始化
}
public override TaskStatus OnUpdate()
{
if (_target.Value == null) return TaskStatus.Failure;
float dist = Vector2.Distance(
transform.position, _target.Value.transform.position);
if (dist <= _stopDistance.Value)
return TaskStatus.Success;
Vector2 dir = (_target.Value.transform.position - transform.position).normalized;
transform.position += (Vector3)(dir * _speed.Value * Time.deltaTime);
return TaskStatus.Running;
}
}
11. Conditional 任务 (条件节点)
条件节点检查运行时条件,返回 Success (true) 或 Failure (false)。
11.1 内置条件分类
基础条件
| Task | 功能 |
|---|---|
HasReceivedEvent |
是否收到指定事件 |
HasValue |
变量是否有值 |
IsBehaviorTreeActive |
行为树是否活跃 |
RandomProbability |
随机概率检查 |
StackedConditional |
堆叠多个条件 |
比较条件
| Task | 功能 |
|---|---|
BoolComparison |
布尔比较 |
FloatComparison |
浮点比较 (==, <, >, <=, >=, !=) |
IntComparison |
整数比较 |
Vector2Comparison |
向量距离比较 |
Vector3Comparison |
3D 向量距离比较 |
GameObjectComparison |
对象引用比较 |
物理条件
| Task | 功能 |
|---|---|
HasEnteredCollision |
是否发生 3D 碰撞进入 |
HasExitedCollision |
是否发生 3D 碰撞退出 |
HasEnteredCollision2D |
2D 碰撞进入 |
HasExitedCollision2D |
2D 碰撞退出 |
HasEnteredTrigger |
3D 触发器进入 |
HasExitedTrigger |
3D 触发器退出 |
HasEnteredTrigger2D |
2D 触发器进入 |
HasExitedTrigger2D |
2D 触发器退出 |
11.2 条件重评估
条件节点实现 IConditionalReevaluation,支持 Conditional Abort 机制:
public abstract class ConditionalNode : Task, ITreeLogicNode,
IConditional, IConditionalReevaluation
{
// 默认 OnReevaluateUpdate() 调用 OnUpdate()
virtual TaskStatus OnReevaluateUpdate() => OnUpdate();
}
12. Event 系统 (事件节点)
Event 节点是行为树的入口点,定义分支的触发条件。
12.1 EventNode 基类
public abstract class EventNode
{
ushort ConnectedIndex; // 连接的第一个逻辑节点索引
BehaviorTree BehaviorTree; // 父树引用
void Initialize(IGraph graph);
}
12.2 内置事件类型
| Event | 触发时机 |
|---|---|
Start |
行为树启动时 (默认入口) |
OnReceivedEvent |
收到命名事件时 |
OnInterrupt |
分支被中断时 |
OnCollisionEnter |
3D 碰撞进入 |
OnCollisionExit |
3D 碰撞退出 |
OnCollisionEnter2D |
2D 碰撞进入 |
OnCollisionExit2D |
2D 碰撞退出 |
OnTriggerEnter |
3D 触发器进入 |
OnTriggerExit |
3D 触发器退出 |
OnTriggerEnter2D |
2D 触发器进入 |
OnTriggerExit2D |
2D 触发器退出 |
12.3 多分支执行
每个 Event 节点创建一个独立的 Branch。多个 Event 可以同时触发,意味着行为树可以有多个并发执行分支。
BehaviorTree
├── Start Event → Branch 0
│ └── Selector [主行为逻辑]
├── OnReceivedEvent("Alert") Event → Branch 1
│ └── Sequence [警报响应]
├── OnCollisionEnter2D Event → Branch 2
│ └── Sequence [碰撞处理]
└── OnInterrupt Event → Branch 3
└── Sequence [中断恢复]
13. Conditional Abort 机制
Conditional Abort 是行为树中实现实时响应的核心机制。
13.1 ConditionalAbortType
public enum ConditionalAbortType : byte
{
None, // 不中断
Self, // 中断当前组合内的执行
LowerPriority, // 中断右侧低优先级兄弟
Both // Self + LowerPriority
}
13.2 中断范围图解
Selector (LowerPriority Abort)
├── Sequence [高优先级 - 战斗]
│ ├── IsEnemyVisible ← 条件 (ConditionalAbort = LowerPriority)
│ └── AttackEnemy
│
└── Sequence [低优先级 - 巡逻] ← 可被中断
├── HasPatrolRoute
└── Patrol
场景:
1. 初始无敌人 → IsEnemyVisible=Failure → 跳到 Patrol
2. 巡逻中,IsEnemyVisible 被周期性重评估
3. 发现敌人 → IsEnemyVisible=Success → 中断 Patrol 分支
4. 切换到 AttackEnemy
Sequence (Self Abort)
├── IsHealthAbove50 ← 条件 (ConditionalAbort = Self)
└── AggressiveAttack
场景:
1. 初始血量 > 50% → 执行 AggressiveAttack
2. 受伤血量 < 50% → IsHealthAbove50 重评估=Failure
3. Self 中断 → 停止 AggressiveAttack → Sequence Failure
13.3 执行流程
1. BeforeTraversalSystemGroup:
ReevaluateSystem:
├─ 遍历所有 ReevaluateTaskComponent
├─ 检查 AbortType 和范围
├─ 标记需要重评估的条件
└─ 启用重评估 Flag
2. 各 Task 重评估系统执行:
└─ 调用 task.OnReevaluateUpdate() 或 ECS 重评估 Job
3. InterruptSystemGroup:
ConditionalAbortsInvokerSystem:
├─ 比较重评估结果与原始状态
├─ 如果变化 → 设置 InterruptFlag
└─ 设置 InterruptType = Branch
InterruptSystem:
├─ 在被中断的分支上调用 OnEnd()
└─ 设置新的执行起点
13.4 Abort 范围计算
- Self: 只能中断当前 Composite 的子节点范围 (
[taskIndex, SelfPriorityUpperIndex]) - LowerPriority: 中断右侧兄弟子树 (
[LowerPriorityLowerIndex, LowerPriorityUpperIndex]) - Both: 合并两者范围
14. Subtree 系统
14.1 概念
Subtree 允许将行为树的一部分存储为 ScriptableObject 资产,实现模块化复用。
主行为树
├── Selector
│ ├── Sequence [Combat]
│ │ ├── IsEnemyNear
│ │ └── SubtreeReference → CombatSubtree.asset
│ └── Sequence [Patrol]
│ └── SubtreeReference → PatrolSubtree.asset
CombatSubtree.asset (独立文件):
├── Start Event
└── Selector
├── Sequence [近战]
│ └── MeleeAttack
└── Sequence [远程]
└── RangedAttack
14.2 数据结构
// 子树注入数据
struct SubtreeAssignment
{
int ReferenceIndex; // SubtreeNodesReference 索引
ushort NodeIndex; // ISubtreeReference Task 索引
int SubtreeIndex; // 子树索引
Subtree Subtree; // 实际子树引用
ushort IndexOffset; // 索引偏移 (多子树累加)
ushort ParentIndex, SiblingIndex, NodeCount;
}
// 子树节点引用
struct SubtreeNodesReference
{
ISubtreeReference SubtreeReference; // 引用 Task
ushort NodeIndex; // 节点索引
ushort NodeCount; // 子树节点总数
Subtree[] Subtrees; // 加载的子树
ITreeLogicNode[][] Nodes; // 反序列化的节点
}
14.3 关键 Action 节点
| 节点 | 功能 |
|---|---|
SubtreeReference |
静态引用一棵子树 |
SubtreeReferenceSelector |
动态选择引用哪棵子树 |
SetSubtree |
运行时切换活跃子树 |
14.4 变量覆写
子树可以有自己的 SharedVariable,注入主树时支持变量覆写 — 主树的变量值覆盖子树同名变量。
15. SharedVariable 系统
15.1 概念
SharedVariable 是行为树节点之间共享数据的机制。每个变量有名称和作用域。
15.2 作用域 (Sharing Scope)
| 作用域 | 可见范围 | 存储位置 |
|---|---|---|
Graph |
当前行为树/子树 | BehaviorTreeData |
GameObject |
同 GameObject 上所有 BT | SharedVariableContainer |
Scene |
当前场景所有 BT | SceneVariable |
Global |
全局所有 BT | GlobalVariable |
15.3 内置 SharedVariable 类型
| 类型 | 包装值 |
|---|---|
SharedBool |
bool |
SharedFloat |
float |
SharedInt |
int |
SharedString |
string |
SharedVector2 |
Vector2 |
SharedVector3 |
Vector3 |
SharedGameObject |
GameObject |
SharedTransform |
Transform |
SharedObject |
object (任意引用) |
15.4 使用模式
// 在自定义 Task 中声明
public class MyTask : Action
{
public SharedGameObject Target; // Inspector 中可配置
public SharedFloat Speed;
public override TaskStatus OnUpdate()
{
// 读取
var targetGO = Target.Value;
float speed = Speed.Value;
// 写入
Speed.Value = 10f;
return TaskStatus.Running;
}
}
// 从外部代码设置
BehaviorTree bt = GetComponent<BehaviorTree>();
bt.SetVariableValue("Target", playerGameObject);
bt.SetVariableValue("Speed", 5f);
16. 序列化与持久化
16.1 序列化系统
Behavior Designer 使用 Opsive 自定义序列化系统(非 Unity 内置序列化):
BehaviorTreeData
├── m_TaskData: Serialization[] // 逻辑节点序列化数据
├── m_EventTaskData: Serialization[] // 事件节点序列化数据
├── m_SharedVariableData: Serialization[] // 变量序列化数据
├── m_DisabledEventNodesData: Serialization[]
└── m_DisabledLogicNodesData: Serialization[]
16.2 序列化流程
编辑时:
Editor → BehaviorTreeData.Serialize() → m_TaskData[], m_EventTaskData[]
运行时:
BehaviorTree.Deserialize()
→ 从 m_TaskData[] 重建 ITreeLogicNode[]
→ 从 m_EventTaskData[] 重建 IEventNode[]
→ 从 m_SharedVariableData[] 重建 SharedVariable[]
→ 解析 Task 间引用 (TaskAssignment)
→ 解析变量引用 (VariableField → VariableAssignment)
16.3 SaveManager
public class SaveManager
{
void Save(); // 保存所有实现 ISavableTask 的 Task 状态
void Load(); // 恢复已保存状态
}
17. Editor 工具链
17.1 可视化编辑器
基于 com.opsive.graphdesigner 的图形编辑器,通过 Opsive.BehaviorDesigner.Editor.dll 提供:
核心窗口: BehaviorMainWindow — 节点拖拽、连线、参数配置。
| 功能 | 描述 |
|---|---|
| 节点编辑 | 可视化拖拽 Composite/Decorator/Action/Conditional 节点 |
| 连线 | 点击连接父子关系 |
| 参数面板 | Inspector 中配置每个节点的 SharedVariable 和属性 |
| 运行时调试 | 运行时高亮活跃节点、显示 Task 状态 |
| 分组 | 将节点分组管理 |
| 注释 | 添加文本注释节点 |
17.2 NodeView 控件
| 控件 | 用途 |
|---|---|
EventNodeViewControl |
事件节点渲染 |
TaskNodeViewControl |
通用 Task 节点渲染 |
StackedTaskNodeViewControl |
堆叠 Task 渲染 |
PriorityEvaluatorNodeViewControl |
优先级评估 UI |
UtilityEvaluatorNodeViewControl |
效用评估 UI |
WaitNodeViewControl |
Wait 节点特殊 UI |
17.3 管理器
| 管理器 | 功能 |
|---|---|
AddOnsManager |
附加组件管理 |
IntegrationsManager |
第三方集成 |
SamplesManager |
示例场景 |
Startup |
编辑器初始化 |
WelcomeScreenManager |
欢迎屏幕 |
17.4 USS 样式
TaskStyles.uss — Task 节点的统一样式定义。
17.5 Editor 为预编译 DLL
重要:编辑器核心代码以 Opsive.BehaviorDesigner.Editor.dll 形式提供,无法直接查看/修改源码。运行时代码为完整源码。
18. 性能分析
18.1 Burst 编译优化
所有核心系统使用 [BurstCompile] 标记:
| 系统 | Burst | 说明 |
|---|---|---|
EvaluationSystem |
✅ | 树遍历 |
DetermineEvaluationSystem |
✅ | 评估判断 |
EvaluationCleanupSystem |
✅ | 标志清理 |
SequenceTaskSystem |
✅ | 顺序节点 |
SelectorTaskSystem |
✅ | 选择节点 |
ParallelTaskSystem |
✅ | 并行节点 |
InverterTaskSystem |
✅ | 取反节点 |
ReevaluateSystem |
✅ | 重评估 |
TaskObjectSystem |
❌ | GameObject 模式 (需要 Managed 引用) |
18.2 内存优化
| 优化 | 说明 |
|---|---|
| 位掩码评估 | 用 ulong 位掩码追踪 Task 评估状态,极致紧凑 |
| 大小自适应 | 根据 Task 数量选择 32~4096 字节变体 |
| ushort 索引 | 用 2 字节索引代替完整引用 |
| IBufferElementData | ECS 数据存储,无 GC 压力 |
| Subtree 池化 | Subtree.Pooled 支持对象池复用 |
18.3 并行执行
Job System (多线程):
├── 多个 BehaviorTree Entity 可并行处理 (IJobEntity)
├── 位掩码操作天然线程安全
└── 不同的 Task System 可以安排在不同线程
单帧内执行流:
Frame N:
[Thread 1] EvaluationJob for Entity A, B, C...
[Thread 2] EvaluationJob for Entity D, E, F...
[Main Thread] TaskObjectSystem (GameObject tasks)
18.4 扩展性限制
| 限制 | 值 | 说明 |
|---|---|---|
| 最大 Task 数 | 32,704 | 受 4096 字节 EvaluationComponent 限制 |
| Parallel 子分支 | 无限制 | 每个子节点独立分支 |
| 层级深度 | 无限制 | 但深树影响遍历性能 |
| 变量作用域 | 4 级 | Graph/GameObject/Scene/Global |
18.5 性能建议
| 场景 | 建议 |
|---|---|
| 大量简单敌人 (100+) | 使用 ECS Task 而非 GameObject Task |
| 频繁条件检查 | 合理设置 ConditionalAbort,避免每帧重评估不必要的条件 |
| 深度行为树 | 使用 EvaluationType.Count 限制每帧评估数 |
| 子树复用 | 启用 Subtree.Pooled 减少实例化 |
| 纯 ECS AI | 使用 Baked 行为树,避免 MonoBehaviour 开销 |
19. 与 BaseGames 架构集成方案
19.1 项目定位
根据 BaseGames 架构文档(00_Architecture_Overview.md、20_Enemy_AI.md):
Behavior Designer 通过 Adapter 层包装,驱动所有敌人 AI 行为决策。
业务代码永远不直接调用 Behavior Designer API,所有交互通过
IBehaviorAdapter接口代理。
19.2 防腐层设计
┌───────────────────────────────────────────────┐
│ 业务层 (Foundation / Entity) │
│ EnemyController, BossPhaseController │
│ AbilitySystem, TagContainer │
│ │
│ 通过接口交互,不引用 BehaviorDesigner 类型 │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ IBehaviorAdapter (接口) │ │
│ │ Enable() / Disable() │ │
│ │ SetVariable(name, value) │ │
│ │ SendEvent(eventName) │ │
│ └──────────┬───────────────────────┘ │
│ │ │
│ ┌──────────▼───────────────────────┐ │
│ │ BehaviorDesignerAdapter (Adapter) │ │
│ │ ├─ Enable → bt.EnableBehavior() │ │
│ │ ├─ Disable → bt.DisableBehavior()│ │
│ │ ├─ SetVariable → bt.SetVariable()│ │
│ │ └─ SendEvent → bt.SendEvent() │ │
│ └──────────┬───────────────────────┘ │
│ │ │
│ ┌──────────▼───────────────────────┐ │
│ │ BehaviorTree (B.D. 原生组件) │ │
│ │ ├─ 行为树遍历 │ │
│ │ ├─ 自定义 Task 节点 │ │
│ │ └─ SharedVariable │ │
│ └──────────────────────────────────┘ │
└───────────────────────────────────────────────┘
19.3 IBehaviorAdapter 接口
public interface IBehaviorAdapter
{
void Enable();
void Disable();
void SetVariable(string name, object value);
void SendEvent(string eventName);
}
19.4 BehaviorDesignerAdapter 实现
[RequireComponent(typeof(BehaviorTree))]
public sealed class BehaviorDesignerAdapter : MonoBehaviour, IBehaviorAdapter
{
private BehaviorTree _bt;
private void Awake() => _bt = GetComponent<BehaviorTree>();
public void Enable() => _bt.StartBehavior();
public void Disable() => _bt.StopBehavior();
public void SetVariable(string name, object value)
{
switch (value)
{
case float f: _bt.SetVariableValue(name, f); break;
case int i: _bt.SetVariableValue(name, i); break;
case bool b: _bt.SetVariableValue(name, b); break;
case GameObject go: _bt.SetVariableValue(name, go); break;
case Vector3 v: _bt.SetVariableValue(name, v); break;
}
}
public void SendEvent(string eventName) => _bt.SendEvent(eventName);
}
19.5 EnemyController 集成
[RequireComponent(typeof(ActorCore))]
public sealed class EnemyController : MonoBehaviour, IDeathListener
{
[SerializeField] private EnemyProfileSO _profile;
private void Awake()
{
// 初始化行为树
var bt = GetComponent<BehaviorTree>();
if (bt != null && _profile.BehaviorTree != null)
{
// v2.x 使用 Subgraph 属性注入 Subtree SO
bt.Subgraph = _profile.BehaviorTree;
bt.SetVariableValue("DetectionRange", _profile.DetectionRange);
bt.SetVariableValue("AttackRange", _profile.AttackRange);
bt.SetVariableValue("PatrolSpeed", _profile.PatrolSpeed);
bt.SetVariableValue("ChaseSpeed", _profile.ChaseSpeed);
}
}
public void OnOwnerDeath()
{
var bt = GetComponent<BehaviorTree>();
bt?.StopBehavior();
}
}
19.6 自定义 BT Task 节点
BaseGames 定义了 [TaskCategory("BaseGames")] 的自定义节点,桥接架构内部系统:
| Task 名 | 类型 | 功能 |
|---|---|---|
ActivateAbilityTask |
Action | 通过 AbilitySystem 激活技能 |
CheckTagTask |
Conditional | 检查 ActorCore.Tags 是否包含指定 Tag |
GrantTagAction |
Action | 向 ActorCore.Tags 添加 Tag |
RemoveTagAction |
Action | 从 ActorCore.Tags 移除 Tag |
SetMovementModeAction |
Action | 切换 IPhysicsBody 重力模式 |
NavigateToTargetTask |
Action | 通过 INavigationAdapter 寻路 |
MoveToTargetTask |
Action | 通过 IPhysicsBody 直线移动 |
IsWithinRange |
Conditional | 自定义距离检查 |
19.7 EnemyStateHandler — Tag 驱动状态切换
BT 不直接操作组件开关,而是通过 GameTag + EnemyStateHandler 间接控制:
BT Task: GrantTagAction(State.Dormant)
→ TagContainer.Add(State.Dormant)
→ EnemyStateHandler 收到 TagAddedEvent
→ 禁用 Hitbox, 导航, 行为树...(根据 StateBinding 配置)
BT Task: RemoveTagAction(State.Dormant)
→ TagContainer.Remove(State.Dormant)
→ EnemyStateHandler 收到 TagRemovedEvent
→ 恢复 Hitbox, 导航, 行为树...
19.8 BossPhaseController — 行为树阶段切换
// Boss 根据血量阈值切换不同的 Subtree:
private void TransitionToPhase(int phaseIndex)
{
_bt.StopBehavior();
_bt.Subgraph = _phases[phaseIndex].PhaseBehaviorTree; // v2.x Subtree SO
_bt.StartBehavior();
}
19.9 典型行为树结构 (敌人)
BT: SkeletonPatroller
├── Selector
│ ├── Sequence [追击] ← ConditionalAbort: LowerPriority
│ │ ├── IsWithinRange(DetectionRange) ← 条件节点 (持续重评估)
│ │ ├── NavigateToTarget(Player)
│ │ └── Sequence [攻击]
│ │ ├── IsWithinRange(AttackRange)
│ │ └── ActivateAbility: SwordSlash
│ └── NavigatePatrol(PatrolPoints) ← 低优先级 (可被中断)
19.10 敌人实体组件装配
[EnemyEntity]
├── ActorCore # 属性/技能/Hitbox/Hurtbox
├── EnemyController # 初始化和配置
├── EnemyStateHandler # Tag 驱动状态切换
├── BehaviorTree # Behavior Designer 原生组件
├── BehaviorDesignerAdapter # IBehaviorAdapter 实现
├── NavAgent # PathBerserker2d 寻路
├── NavAgentAdapter # INavigationAdapter 实现
├── NavMovementBridge # 寻路 ↔ 物理桥接
├── NavAbilityGate # 能力 ↔ Link 桥接
├── RaycastBody2D # 物理移动
├── AnimancerComponent # 动画
├── Hitbox (ContactHitbox) # 接触伤害
└── Hurtbox # 受击判定
19.11 数据驱动配置流
EnemyProfileSO (ScriptableObject)
├── DisplayName, FactionTag
├── AttributeTemplate → AttributeSet 初始化
├── Abilities[] → AbilitySystem.GrantAbility()
├── BehaviorTree (Subtree SO) → BehaviorTree.Subgraph
├── DetectionRange, AttackRange → SharedVariable 注入
├── PatrolSpeed, ChaseSpeed → SharedVariable 注入
├── LootTable → 死亡掉落
├── HitCue, DeathCue → 反馈配置
├── InitialStateTags → 初始状态 (Dormant 等)
├── MovementMode → 移动模式 (Ground/Flying/CeilingHang)
└── AbilityLinkMappings → 导航能力桥接
20. 优缺点总结
20.1 技术评分
| 维度 | 评分 (1-10) | 说明 |
|---|---|---|
| 功能完整度 | 9 | 覆盖行为树全部标准功能 + Utility AI + Parallel + Subtree |
| API 设计 | 8 | 双模式 Task 灵活;自定义 Task 采用熟悉的 MonoBehaviour 模式,学习成本低 |
| 文档质量 | 7 | 官方文档完整,但未充分强调 MonoBehaviour Task 的主流地位 |
| 性能 | 9 | Composite/Decorator 由 Burst + ECS 驱动,核心遍历极高效;MonoBehaviour Task 主线程执行,性能可接受 |
| 易用性 | 9 | 可视化编辑器直观,自定义 Task 只需继承 Action/Conditional + 覆写 OnUpdate,与 v1.x 编程体验基本一致 |
| 可维护性 | 7 | Editor 为预编译 DLL 不可修改,Runtime 完整源码 |
| 与项目契合度 | 9 | 通过 Adapter 层完美集成,Tag 驱动架构天然契合;无需 ECS 知识即可开发自定义 Task |
| 综合 | 8.3 | 项目 AI 核心框架 |
20.2 核心优势
| 优势 | 说明 |
|---|---|
| 混合架构 (ECS 调度 + MonoBehaviour Task) | ECS 作为调度引擎提供高性能树遍历,自定义 Task 仍用熟悉的 MonoBehaviour 模式编写 |
| MonoBehaviour Task 为主流开发模式 | 内置 42+ 个任务中 80%+ 采用 MonoBehaviour Task,示例代码全部采用此模式,自定义业务 Task 无需 ECS 知识 |
| Burst 编译核心遍历 | Composite/Decorator 等树结构节点全部 ECS + Burst 编译,零 GC |
| 位掩码评估 | 极低评估开销 |
| Conditional Abort | 实时响应环境变化,无需手动管理中断逻辑 |
| Subtree 复用 | 行为模块化,Boss 阶段切换简洁 |
| SharedVariable | 灵活的数据共享机制 |
| 可视化编辑器 | 策划可参与 AI 调试和配置 |
| 事件驱动分支 | 物理/自定义事件触发独立执行分支 |
| 运行时源码 | 可调试可扩展 |
20.3 风险与缓解
| 风险 | 缓解方案 |
|---|---|
| DOTS 依赖 (com.unity.entities) | Entities 是 Unity 官方组件,长期维护有保障 |
| Editor 为 DLL | Runtime 完整开源,Editor 通过 API 扩展 |
| 第三方维护风险 | Opsive 活跃维护 10+ 年,Runtime 源码可自维护 |
| ECS 学习曲线 | 使用 GameObject Task 模式可避免直接写 ECS |
| v1→v2 API 变化 | v2 API 更现代,Subtree 替代 ExternalBehaviorTree |
20.4 与备选方案对比
| 特性 | Behavior Designer v2 | NodeCanvas | GOAP (ReGoap) | 自研 FSM |
|---|---|---|---|---|
| 行为树 | ✅ 完整 | ✅ 完整 | ❌ | ❌ |
| DOTS/ECS 调度 | ✅ 内部引擎 | ❌ | ❌ | 需自建 |
| MonoBehaviour Task | ✅ 主流模式 | ✅ | N/A | N/A |
| Burst 编译 | ✅ (Composite/Decorator) | ❌ | ❌ | 需自建 |
| 可视化编辑 | ✅ | ✅ | ✅ | ❌ |
| Utility AI | ✅ 内置 | ❌ | ✅ | 需自建 |
| Conditional Abort | ✅ | ✅ | N/A | 需自建 |
| 价格 | $90 Pro | $60 | 免费 | 免费 |
| 社区/维护 | 活跃 10+ 年 | 活跃 | 较小 | N/A |
21. 总结与建议
21.1 总体评价
Behavior Designer Pro v2.1.12 采用 ECS 作为内部调度引擎,同时提供 MonoBehaviour Task 和 ECS Task 双模式编程模型的混合架构行为树解决方案。对于 BaseGames 这一项目:
- AI 决策核心 — 所有敌人和 Boss 行为由行为树驱动
- 架构契合 — Adapter 层隔离完美符合 BaseGames 防腐层设计
- 开发友好 — 自定义 Task 采用熟悉的 MonoBehaviour 模式(继承
Action/Conditional+ 覆写OnUpdate()),无需 ECS 知识 - Tag 驱动 — BT Task(GrantTag/RemoveTag)+ EnemyStateHandler 实现声明式状态管理
- 数据驱动 — EnemyProfileSO + SharedVariable 注入,策划零代码配置敌人行为
- Boss 阶段化 — BossPhaseController 通过切换 Subtree SO 实现多阶段 AI
21.2 最佳实践
| 实践 | 建议 |
|---|---|
| Task 模式选择 | 自定义业务 Task(如 ActivateAbility、CheckTag)使用 MonoBehaviour Task(继承 Action/Conditional);仅极端性能场景考虑 ECS Task |
| Conditional Abort | 检测条件 (如 IsEnemyInRange) 放在高优先级 Sequence 首位 + LowerPriority |
| 行为树深度 | 控制在 5-8 层以内,过深用 Subtree 拆分 |
| SharedVariable 命名 | 统一命名约定:DetectionRange、Target、AttackRange |
| 自定义 Task | 统一 [TaskCategory("BaseGames")] 标签分类 |
| Adapter | 业务层只通过 IBehaviorAdapter 交互 |
| Tag 驱动 | 优先用 GrantTag/RemoveTag 间接控制,而非直接操作组件 |
| Boss 设计 | 每个阶段独立行为树文件,通过 BossPhaseController 切换 |
| 事件通信 | 使用 SendEvent/OnReceivedEvent 替代轮询 |
| 性能 | 大量小怪考虑 EvaluationType.Count 限制帧评估量 |
21.3 关键文件速查
| 用途 | 文件 | 路径 (相对 Runtime/) |
|---|---|---|
| 主入口 | BehaviorTree |
BehaviorTree.cs |
| 数据容器 | BehaviorTreeData |
BehaviorTreeData.cs |
| 子树资产 | Subtree |
Subtree.cs |
| ECS 组件 | TaskComponent / BranchComponent |
Components/BehaviorTreeComponents.cs |
| Baking | BakedBehaviorTree |
Components/BakedBehaviorTree.cs |
| Task 基类 | Task |
Tasks/Task.cs |
| ECS Task 基类 | ECSTask<T,C> |
Tasks/ECSTask.cs |
| TaskStatus | TaskStatus |
Tasks/TaskStatus.cs |
| 条件中断 | ConditionalAbortType |
Tasks/ConditionalAbortType.cs |
| 接口 | 全部 Task 接口 | Tasks/TaskInterfaces.cs |
| Sequence | Sequence |
Tasks/Composites/Sequence.cs |
| Selector | Selector |
Tasks/Composites/Selector.cs |
| Parallel | Parallel |
Tasks/Composites/Parallel.cs |
| Inverter | Inverter |
Tasks/Decorators/Inverter.cs |
| Repeater | Repeater |
Tasks/Decorators/Repeater.cs |
| Cooldown | Cooldown |
Tasks/Decorators/Cooldown.cs |
| Wait | Wait |
Tasks/Actions/Wait.cs |
| SendEvent | SendEvent |
Tasks/Actions/SendEvent.cs |
| SubtreeReference | SubtreeReference |
Tasks/Actions/SubtreeReference.cs |
| Start Event | Start |
Tasks/Events/Start.cs |
| OnReceivedEvent | OnReceivedEvent |
Tasks/Events/OnReceivedEvent.cs |
| 遍历系统 | EvaluationSystem |
Systems/TraversalSystems.cs |
| 重评估系统 | ReevaluateSystem |
Systems/BeforeTraversalSystems.cs |
| GO Task 执行 | TaskObjectSystem |
Systems/TaskObjectSystem.cs |
| 清理系统 | CleanupSystem |
Systems/CleanupSystem.cs |
| 根系统组 | BehaviorTreeSystemGroup |
Groups/BehaviorTreeSystemGroup.cs |
| 遍历系统组 | TraversalSystemGroup |
Groups/TraversalSystemGroup.cs |
| 遍历工具 | TraversalUtility |
Utility/TraversalUtility.cs |
| 组件工具 | ComponentUtility |
Utility/ComponentUtility.cs |
| 保存管理 | SaveManager |
Utility/SaveManager.cs |
| ECS 模板 | ECSNodes |
Tasks/Templates/ECSNodes.cs |
| GO 模板 | GameObjectNodes |
Tasks/Templates/GameObjectNodes.cs |
文档版本: 1.0
基于: Behavior Designer Pro v2.1.12 源码分析 + 官方文档 + BaseGames 架构文档
架构参考:Docs/Architecture/00_Architecture_Overview.md、Docs/Architecture/20_Enemy_AI.md