一句话理解:树是一种没有环的层级结构。Unity 的 Transform 层级、UI 树、技能树和行为树,都可以用“节点 + 子节点”建模。
树的基本概念
- Root:没有父节点的入口。
- Parent / Child:父子关系。
- Leaf:没有子节点。
- Depth:节点距离根的层数。
- Subtree:某节点及其全部后代。
一棵普通树不允许形成环;每个非根节点通常只有一个父节点。如果节点能有多个父节点或形成回路,它更接近图。
一个安全的通用节点
公开
IReadOnlyList,避免外部绕过父子关系规则直接修改内部 List。DFS:先走到底
递归 DFS 简洁,但层级异常深时可能栈溢出。迭代版本更稳:
适合遍历完整子树、序列化、层级查找和行为树 Tick。
BFS:按层访问
BFS 适合寻找离根最近的满足条件节点、按层布局 UI 和计算深度。
Unity Transform 本身就是树
不要在每帧反复调用深层
Transform.Find。初始化时缓存组件引用,或建立 ID 到节点的索引。技能树与行为树
技能树
技能树常常不是真正的树:一个技能可能依赖多个前置技能,此时结构是有向无环图(DAG)。若硬套单父节点,会丢失依赖关系。
行为树
Selector、Sequence 是组合节点,Action、Condition 是叶子。行为树强调每帧执行语义;树结构只是承载节点关系。
UI 树
UGUI 和 UI Toolkit 都有层级。批量激活、样式传播和布局遍历会沿树执行,过深层级会增加重建与遍历成本。
扁平化存储
对象节点易读,但每个节点对象会带来引用追踪和缓存不友好。大量静态树可扁平化:
连续数组更适合 Burst、序列化和批量遍历。编辑器阶段可使用对象树,构建时烘焙为扁平数组。
复杂度
- 遍历整棵树:O(n)
- 已知父节点添加子节点:通常 O(1)
- 未建索引时按值查找:O(n)
- 沿父链计算深度:O(h)
- 平衡二叉搜索树查询:O(log n),但普通 Unity 层级树不保证平衡
常见坑
- 创建循环父子关系。
- 把技能依赖图误当作普通树。
- 递归处理来自外部数据的超深结构。
- 每帧从根扫描寻找一个节点。
- 在遍历 Children 时直接修改同一集合。
- 为性能敏感数据创建海量小节点对象。