1822 lines
68 KiB
Markdown
1822 lines
68 KiB
Markdown
# Behavior Designer Pro v2.1.12 技术评估与使用手册
|
||
|
||
> **版本**: Behavior Designer Pro 2.1.12
|
||
> **作者**: Opsive
|
||
> **架构范式**: ECS 调度引擎 + MonoBehaviour/DOTS 双模 Task 混合架构
|
||
> **Unity 要求**: 2022.3+
|
||
> **依赖**: `com.opsive.shared` 2.0.0、`com.opsive.graphdesigner` 2.0.0、`com.unity.burst` 1.8.17、`com.unity.entities` 1.3.8
|
||
> **许可**: Unity Asset Store EULA
|
||
> **包路径**: `Packages/com.opsive.behaviordesigner/`
|
||
> **官方文档**: https://opsive.com/support/documentation/behavior-designer-pro/
|
||
> **命名空间**: `BehaviorDesigner.Runtime`、`BehaviorDesigner.Runtime.Tasks`
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [概述与设计哲学](#1-概述与设计哲学)
|
||
2. [架构总览](#2-架构总览)
|
||
3. [核心组件](#3-核心组件)
|
||
4. [ECS/DOTS 集成架构](#4-ecsdots-集成架构)
|
||
5. [System Group 执行层级](#5-system-group-执行层级)
|
||
6. [核心 ECS 系统](#6-核心-ecs-系统)
|
||
7. [Task 系统架构](#7-task-系统架构)
|
||
8. [Composite 任务 (组合节点)](#8-composite-任务-组合节点)
|
||
9. [Decorator 任务 (装饰节点)](#9-decorator-任务-装饰节点)
|
||
10. [Action 任务 (行为节点)](#10-action-任务-行为节点)
|
||
11. [Conditional 任务 (条件节点)](#11-conditional-任务-条件节点)
|
||
12. [Event 系统 (事件节点)](#12-event-系统-事件节点)
|
||
13. [Conditional Abort 机制](#13-conditional-abort-机制)
|
||
14. [Subtree 系统](#14-subtree-系统)
|
||
15. [SharedVariable 系统](#15-sharedvariable-系统)
|
||
16. [序列化与持久化](#16-序列化与持久化)
|
||
17. [Editor 工具链](#17-editor-工具链)
|
||
18. [性能分析](#18-性能分析)
|
||
19. [与 BaseGames 架构集成方案](#19-与-basegames-架构集成方案)
|
||
20. [优缺点总结](#20-优缺点总结)
|
||
21. [总结与建议](#21-总结与建议)
|
||
|
||
---
|
||
|
||
## 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 上,管理行为树的生命周期:
|
||
|
||
```csharp
|
||
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 — 序列化数据
|
||
|
||
```csharp
|
||
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 子树
|
||
|
||
```csharp
|
||
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
|
||
|
||
```csharp
|
||
public enum UpdateMode
|
||
{
|
||
EveryFrame, // 每帧自动评估
|
||
Manual // 手动调用 Tick()
|
||
}
|
||
|
||
public enum EvaluationType : byte
|
||
{
|
||
EntireTree, // 评估整棵树直到找到 Running 节点
|
||
Count // 每帧最多评估 N 个节点 (性能限制)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. ECS/DOTS 集成架构
|
||
|
||
### 4.1 核心 ECS 组件
|
||
|
||
#### TaskComponent (每个 Task 节点的运行时数据)
|
||
|
||
```csharp
|
||
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 (执行分支状态)
|
||
|
||
```csharp
|
||
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 (条件中断数据)
|
||
|
||
```csharp
|
||
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
|
||
|
||
```csharp
|
||
public enum InterruptType : byte
|
||
{
|
||
None, // 无中断
|
||
Branch, // 条件中断/效用触发
|
||
ImmediateSuccess, // 立即成功中断
|
||
ImmediateFailure // 立即失败中断
|
||
}
|
||
```
|
||
|
||
### 4.2 Baking 支持
|
||
|
||
```csharp
|
||
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
|
||
|
||
```csharp
|
||
[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
|
||
|
||
```csharp
|
||
// 检查是否有叶子 Task 处于 Running 状态
|
||
// 使用 5 种 EvaluationComponent 大小变体的 Job 并行查询
|
||
// 输出:
|
||
// Active = true → 树仍在运行
|
||
// Evaluate = true → 需要继续评估循环
|
||
```
|
||
|
||
### 6.3 ReevaluateSystem
|
||
|
||
```csharp
|
||
// 处理 Conditional Abort:
|
||
// 1. 遍历 ReevaluateTaskComponent 缓冲区
|
||
// 2. 检查 Task 是否满足重评估条件 (abort type + 范围)
|
||
// 3. 设置 ReevaluateStatus = Active
|
||
// 4. 启用重评估 Flag
|
||
// 5. 记录原始状态用于后续比较
|
||
```
|
||
|
||
### 6.4 ConditionalAbortsInvokerSystem
|
||
|
||
```csharp
|
||
// 比较重评估后的 Task 状态与原始状态:
|
||
// 如果状态发生变化 → 触发 InterruptFlag → 设置 BranchComponent.InterruptType
|
||
```
|
||
|
||
### 6.5 TaskObjectSystem
|
||
|
||
```csharp
|
||
// 执行 GameObject-based Task 的生命周期:
|
||
// 1. Queued → OnStart() → Running
|
||
// 2. Running → OnUpdate() → 返回 TaskStatus
|
||
// 3. Success/Failure → OnEnd()
|
||
//
|
||
// 对于 ITaskObjectParentNode:
|
||
// 使用 NextChildIndex 确定下一个子节点
|
||
// 父节点返回 Success/Failure 时中断所有子节点
|
||
```
|
||
|
||
### 6.6 EvaluationCleanupSystem
|
||
|
||
```csharp
|
||
[BurstCompile]
|
||
// 每帧遍历结束后:
|
||
// - 启用 EvaluateFlag (若 EnabledFlag 启用)
|
||
// - 重置 BranchComponent.CanExecute = true
|
||
// - 重置 BranchComponent.LastActiveIndex = ushort.MaxValue
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Task 系统架构
|
||
|
||
### 7.1 TaskStatus 枚举
|
||
|
||
```csharp
|
||
public enum TaskStatus : byte
|
||
{
|
||
Inactive, // 未激活
|
||
Queued, // 已排队,下次 Update 开始执行
|
||
Running, // 正在执行
|
||
Success, // 执行成功
|
||
Failure // 执行失败
|
||
}
|
||
```
|
||
|
||
### 7.2 Task 基类 (GameObject-based)
|
||
|
||
```csharp
|
||
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)
|
||
|
||
```csharp
|
||
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 接口体系
|
||
|
||
```csharp
|
||
// ─── 类型标记 ───
|
||
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(类似行为栈):
|
||
|
||
```csharp
|
||
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 协程支持
|
||
|
||
```csharp
|
||
public class TaskCoroutine
|
||
{
|
||
Coroutine Coroutine;
|
||
void RunCoroutine(); // 执行完整协程
|
||
void Stop(); // 停止协程
|
||
|
||
delegate void TaskCoroutineEnded(TaskCoroutine, string name);
|
||
}
|
||
```
|
||
|
||
### 7.8 TaskDelegate 系统
|
||
|
||
支持方法代理到 Task 的绑定:
|
||
|
||
```csharp
|
||
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 (顺序节点)
|
||
|
||
```csharp
|
||
// 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 (选择节点)
|
||
|
||
```csharp
|
||
// 逻辑:
|
||
// 1. 子节点 Success → Selector 返回 Success
|
||
// 2. 子节点 Failure → 执行下一个子节点
|
||
// 3. 所有子节点 Failure → Selector 返回 Failure
|
||
// 4. 支持 ConditionalAbort
|
||
```
|
||
|
||
### 8.4 Parallel (并行节点)
|
||
|
||
```csharp
|
||
public struct ParallelComponent : IBufferElementData
|
||
{
|
||
public ushort Index;
|
||
}
|
||
|
||
// 特殊机制:
|
||
// - 每个子节点获得独立的 BranchComponent (独立执行分支)
|
||
// - 初始化时添加中断组件
|
||
// - 任一子节点 Failure → 中断所有其他子节点 → Parallel Failure
|
||
// - 所有子节点 Success → Parallel Success
|
||
```
|
||
|
||
### 8.5 Composite 基类
|
||
|
||
```csharp
|
||
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 (取反器)
|
||
|
||
```csharp
|
||
public struct InverterComponent : IBufferElementData
|
||
{
|
||
public ushort Index;
|
||
}
|
||
|
||
// Flag: InverterFlag
|
||
// System: InverterTaskSystem (Burst)
|
||
//
|
||
// 逻辑:
|
||
// - 子节点 Success → Inverter Failure
|
||
// - 子节点 Failure → Inverter Success
|
||
// - 子节点 Running → Inverter Running
|
||
```
|
||
|
||
### 9.3 Decorator 基类
|
||
|
||
```csharp
|
||
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 编写示例
|
||
|
||
```csharp
|
||
[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 机制:
|
||
|
||
```csharp
|
||
public abstract class ConditionalNode : Task, ITreeLogicNode,
|
||
IConditional, IConditionalReevaluation
|
||
{
|
||
// 默认 OnReevaluateUpdate() 调用 OnUpdate()
|
||
virtual TaskStatus OnReevaluateUpdate() => OnUpdate();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Event 系统 (事件节点)
|
||
|
||
Event 节点是行为树的**入口点**,定义分支的触发条件。
|
||
|
||
### 12.1 EventNode 基类
|
||
|
||
```csharp
|
||
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
|
||
|
||
```csharp
|
||
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 数据结构
|
||
|
||
```csharp
|
||
// 子树注入数据
|
||
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 使用模式
|
||
|
||
```csharp
|
||
// 在自定义 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;
|
||
}
|
||
}
|
||
```
|
||
|
||
```csharp
|
||
// 从外部代码设置
|
||
BehaviorTree bt = GetComponent<BehaviorTree>();
|
||
bt.SetVariableValue("Target", playerGameObject);
|
||
bt.SetVariableValue("Speed", 5f);
|
||
```
|
||
|
||
---
|
||
|
||
## 16. 序列化与持久化
|
||
|
||
### 16.1 序列化系统
|
||
|
||
Behavior Designer 使用 Opsive 自定义序列化系统(非 Unity 内置序列化):
|
||
|
||
```csharp
|
||
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
|
||
|
||
```csharp
|
||
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 接口
|
||
|
||
```csharp
|
||
public interface IBehaviorAdapter
|
||
{
|
||
void Enable();
|
||
void Disable();
|
||
void SetVariable(string name, object value);
|
||
void SendEvent(string eventName);
|
||
}
|
||
```
|
||
|
||
### 19.4 BehaviorDesignerAdapter 实现
|
||
|
||
```csharp
|
||
[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 集成
|
||
|
||
```csharp
|
||
[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 — 行为树阶段切换
|
||
|
||
```csharp
|
||
// 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 这一项目:
|
||
|
||
1. **AI 决策核心** — 所有敌人和 Boss 行为由行为树驱动
|
||
2. **架构契合** — Adapter 层隔离完美符合 BaseGames 防腐层设计
|
||
3. **开发友好** — 自定义 Task 采用熟悉的 MonoBehaviour 模式(继承 `Action`/`Conditional` + 覆写 `OnUpdate()`),无需 ECS 知识
|
||
4. **Tag 驱动** — BT Task(GrantTag/RemoveTag)+ EnemyStateHandler 实现声明式状态管理
|
||
5. **数据驱动** — EnemyProfileSO + SharedVariable 注入,策划零代码配置敌人行为
|
||
6. **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`
|