UE5.8 StateTree 状态树专题系列

UE5.8 StateTree 专题(八):Transition 选择、优先级和调试

讲 OnTick、OnEvent、OnStateSucceeded/Failed、GotoState、NextState、Parent、Transition Priority、父子状态选择,以及怎么调试跳错状态。

总览

StateTree 让人头疼的第一类问题是“不跳”,第二类是“跳错”。这篇专门讲 Transition。你要先知道:Transition 不是随便触发的,它有触发类型、条件、目标、优先级,还受到状态层级影响。多个 Transition 同时满足时,StateTree 会按规则选一个。

UE5.8 StateTree 专题(八):Transition 选择、优先级和调试 配图
多个 Transition 同时满足时,不是随机跳;触发类型、优先级和树上的位置都会影响选择。

触发类型先分清

Trigger 什么时候检查 守卫例子
On Tick 每次树 Tick 时 巡逻中看到玩家 -> Alert
On State Succeeded 当前状态成功完成 Wait 结束 -> Patrol
On State Failed 当前状态失败 Move To 失败 -> Search
On Event 收到事件 听到声音 -> Investigate
On Delegate 某个委托广播 Montage 结束 -> Next

新手建议:能用 OnStateSucceeded 就不要用 OnTick。OnTick 每帧检查,适合紧急打断;状态正常流程用完成触发更清楚。

优先级怎么用

EStateTreeTransitionPriority 有 Low、Normal、Medium、High、Critical。守卫案例里,发现玩家应该比巡逻完成更重要。否则刚好 Move To 成功那帧也看到玩家,树可能先走普通巡逻流程。

推荐优先级:

跳转 优先级
死亡、硬打断、被控制 Critical
发现玩家、受到攻击 High
追击丢失目标 Medium
巡逻点到达、等待结束 Normal
装饰性随机切换 Low

父子状态的影响

Transition 可以放在父状态,也可以放在子状态。父状态的 Transition 适合“所有子状态都适用”的规则,例如 Combat 下任何子状态血量为 0 都去 Dead。子状态 Transition 适合局部流程,例如 PatrolA 到 PatrolB。

如果一个规则在十个子状态都复制了一遍,优先考虑放父状态。复制越多,后期越容易漏改。

源码依据

EStateTreeTransitionTrigger 定义 OnTick、OnStateSucceeded、OnStateFailed、OnEvent、OnDelegate。EStateTreeTransitionPriority 定义 Low、Normal、Medium、High、Critical,并有比较运算。EStateTreeStateSelectionRules 定义完成状态如何重新创建、完成状态在 Transition source 前如何处理。FStateTreeExecutionContext 的 Tick 会更新任务并触发 Transition,源码还提供 Trace/Debugger 相关入口。

架构分析

Transition 是状态之间的合同。架构上建议把“全局打断”放在父状态或更高层,例如看到玩家打断巡逻;把“局部完成”放在当前状态,例如 MoveTo 成功后 NextState。这样你能从树结构上看出跳转范围,不会在每个叶子状态里复制同一批高优先级条件。

使用案例

守卫追击流程:

当前状态 Transition 条件 优先级
Patrol Goto Alert CanSeePlayer High
Alert Goto Chase CanSeePlayer Normal
Alert Goto Patrol !CanSeePlayer Normal
Chase Goto Search DistanceToPlayer > LoseSightRange Medium
Chase Goto Combat DistanceToPlayer < AttackRange High
Any Combat Child Goto Dead Health <= 0 Critical

调试时先问:这个跳转有没有被检查?条件值是什么?是否被更高优先级跳转抢走?目标状态是否可进入?

项目落地

给每个复杂 Transition 写描述,不要只靠节点名字。比如“看见玩家时从任何巡逻子状态进入 Alert,High 优先级”。调试记录里保留当前 Active State、上一次 Transition、失败 Condition 的值。对 AI 来说,能复盘“为什么它刚才没追”比能看到一堆节点更重要。

常见坑

不要把所有跳转都设成 Critical。优先级失去差异后就没有意义。不要用 OnTick 承担正常流程,它会让树每帧都处于高压判断。不要忘记目标状态也有 Enter Conditions,Transition 条件通过不代表目标状态能选中。不要在父状态和子状态写互相冲突的跳转。

源码路径索引

  • StateTreeModule/Public/StateTreeTypes.h
  • StateTreeModule/Public/StateTreeExecutionTypes.h
  • StateTreeModule/Public/Debugger/StateTreeTrace.h
  • StateTreeModule/Public/Debugger/StateTreeDebugger.h