用途
UE State Trees 面向在虚幻引擎 5.8 中编写或调试状态树(State Tree)逻辑的场景,尤其是 C++ 层面的任务、条件、求值器、考虑项、Schema、转移、事件以及 Mass 实体行为。目标引擎为 UE 5.8,文中 API 已对照 5.8 头文件验证,旧写法被列在“Deprecated — do not use”下。
主要能力
状态树是以 UStateTree 数据资产编辑的数据驱动层级状态机,从 C++ 通过执行上下文运行。运行时类型位于 StateTreeModule(插件 StateTree);面向 Actor 的组件与 Schema 位于 GameplayStateTreeModule(插件 GameplayStateTree);Mass 实体行为需要 MassAIBehavior(MassAI 插件,5.8 中为实验性)以及 MassEntity、MassCore、MassSignals。使用到的模块需加入 .Build.cs 的 PublicDependencyModuleNames。
架构上,UStateTree(UDataAsset)在执行前必须 IsReadyToRun() 为真,包含 UStateTreeSchema(限定允许的节点与上下文数据)、States(States/Groups/Linked/Subtree 层级,含 Tasks、EnterConditions、Considerations、Transitions)、Evaluators(全局数据提供者,在转移前 tick)、Parameters(FInstancedPropertyBag 全局参数)。节点是 USTRUCT 而非 UObject,每个节点虚函数都是 const;可变实例状态保存在由 FStateTreeInstanceData 拥有的独立实例数据结构中,跨帧持久化的是它,执行上下文只是在其上构建的短生命周期视图。
执行上下文在 5.8 按能力拆分:FStateTreeReadOnlyExecutionContext(GetOwner、GetWorld、GetStateTree、HasEventToProcess、IsValid、GetDebugInfo)、FStateTreeMinimalExecutionContext(增加 SendEvent、ScheduleNextTick、scheduled-tick 请求)、FStateTreeExecutionContext(增加 Start/Stop/Tick、实例数据、外部数据、FinishTask、BindDelegate)、FStateTreeWeakExecutionContext(供 lambda、潜伏动作、定时器捕获)与 FStateTreeStrongExecutionContext(通过 MakeStrongExecutionContext() 解析)。最小上下文派生自只读上下文,完整上下文派生自最小上下文。
异步完成通过捕获 FStateTreeWeakExecutionContext,在异步工作返回后调用 FinishTask(EStateTreeFinishTaskType::Succeeded);tick 内也可用 Context.FinishTask(*this, ...) 或从 Tick 返回完成状态。
Schema 声明资产可用的节点结构、类与上下文数据,IsStructAllowed 决定自定义节点是否出现在编辑器中,因此自定义节点应派生自内置 Schema 接受的 *CommonBase 结构(FStateTreeTaskCommonBase、FStateTreeConditionCommonBase、FStateTreeEvaluatorCommonBase、FStateTreeConsiderationCommonBase、FStateTreePropertyFunctionCommonBase)。内置 Schema 包括 UStateTreeComponentSchema(Actor)、UStateTreeAIComponentSchema(Actor 默认 APawn 加 AIController)、UMassStateTreeSchema(Mass 实体数据)。注意 AllowEnterConditions、AllowUtilityConsiderations、AllowEvaluators、AllowMultipleTasks、AllowGlobalParameters、AllowTasksCompletion、AllowQueuedCompilation 声明在 #if WITH_EDITOR 内;而 IsStructAllowed、IsClassAllowed、IsExternalItemAllowed、IsScheduledTickAllowed、IsStateSelectionAllowed、IsStateTypeAllowed、GetContextDataDescs 是运行时虚函数。
任务需重写所需虚函数并实现 GetInstanceDataType();仅写 using FInstanceDataType 别名为空,FStateTreeNodeBase::GetInstanceDataType() 默认返回 nullptr,编译器不预留存储。任务虚函数包括 EnterState、ExitState、StateCompleted、Tick、TriggerTransitions、GetDebugInfo(均 const)。可编辑参数通常放在实例数据上以便在编辑器中绑定。行为标志(任务构造函数中设置):bShouldStateChangeOnReselect、bShouldCallTick、bShouldCallTickOnlyOnEvents、bShouldCopyBoundPropertiesOnTick、bShouldCopyBoundPropertiesOnExitState、bShouldAffectTransitions、bConsideredForScheduling、bTaskEnabled,以及 TransitionHandlingPriority。
条件通过 FStateTreeConditionBase::TestCondition 返回 bool,默认 false,必须纯函数,因为选择阶段可能一帧多次调用;具有 Operand、DeltaIndent、EvaluationMode 成员,并接收 EnterState、ExitState、StateCompleted 以缓存工作。内置条件包含数值/枚举/名称/距离比较、随机条件、对象有效性条件以及 gameplay-tag 系列。
考虑项用于给状态打分,供父级在子级中选择;API 在头文件中标记为实验性。GetScore 为 protected,框架调用公开的 GetNormalizedScore;Operand 与 DeltaIndent 组合同级考虑项,分数仅对两种效用选择行为有意义,且 Schema 需 AllowUtilityConsiderations() 返回 true。
求值器是全局的(非逐状态),在转移与任务 tick 之前 tick,适用于多个节点读取的数据;稳定引用则用外部数据。虚函数为 TreeStart、TreeStop、Tick、GetDebugInfo;在状态预选择期间 tick 时 DeltaTime 为 0。
转移:EStateTreeTransitionTrigger 是位掩码(OnStateSucceeded 0x1、OnStateFailed 0x2、OnStateCompleted 0x1|0x2、OnTick 0x4、OnEvent 0x8、OnDelegate 0x10)。EStateTreeTransitionPriority 为 Low、Normal、Medium、High、Critical,最高优先级中第一个触发的转移胜出。转移类型包括 None、Succeeded、Failed、GotoState、Parent、NextState、NextSelectableState、NextParent、NextSelectableParent;每转移标志 bTransitionEnabled 与 bConsumeEventOnSelect 默认均为 true。C++ 中可用 Context.RequestTransition(TargetState, Priority, Fallback) 请求转移。
委托用于替代轮询:一个节点在实例数据上发布 FStateTreeDelegateDispatcher,另一个发布 FStateTreeDelegateListener,编辑器连接二者;EnterState 用 Context.BindDelegate 绑定,ExitState 必须 Context.UnbindDelegate 解绑,派发方用 Context.BroadcastDelegate。带 OnDelegate 触发器的转移会在绑定的派发器广播时触发。
状态类型 EStateTreeStateType 包括 State、Group、Linked、LinkedAsset、Subtree,其中 LinkedAsset 是共享机制,可用 FStateTreeReferenceOverrides 逐实例覆盖。选择行为 EStateTreeStateSelectionBehavior 包括 None(不能直接选择)与 TryEnterState(即使有子级也进入该状态)以及 TrySelectChildrenInOrder 等。
使用方式
按请求与代码库确定所属主题,分派到相应章节:架构与执行上下文、任务、条件、考虑项、求值器与外部数据、转移与状态类型选择、事件、委托、Schema、组件与 AI 设置、调度 tick、Mass 实体集成、异步完成。若存在 .agents/ue-project-context.md 应先阅读(模块名、约定、启用的插件、GAS/网络设置),缺失时不要停止。仅当两种合理理解会产生不同代码时才发问。
典型运行方式:在所有者上以 UPROPERTY(Transient) 保存 FStateTreeInstanceData;每 tick 构造 FStateTreeExecutionContext Context(*this, *StateTreeAsset, InstanceData),设置 SetCollectExternalDataCallback,用 FStateTreeExecutionContext::FStartParameters(如 RandomSeed)调用 Context.Start,之后各帧调用 Context.Tick(DeltaTime)。需要让其他系统先运行时,可先 TickUpdateTasks(DeltaTime) 再 TickTriggerTransitions()。
适用场景
适用于在 UE 5.8 C++ 中编写或调试 Actor、AI 控制器或 Mass 实体上的状态树逻辑,包括编写任务、条件、考虑项、求值器、Schema 与转移,以及通过委托与事件响应外部回调、降低 tick 成本或实现休眠状态树。
限制
目标引擎为 UE 5.8,API 已对照 5.8 头文件验证;旧形式被标记为废弃,不应使用。MassAIBehavior 在 5.8 中为实验性,考虑项 API 在头文件中标注为实验性,建议自定义考虑项保持小巧。上下文方法按能力拆分,应选择能通过编译的最窄上下文。Schema 中的若干 Allow* 虚函数仅在 #if WITH_EDITOR 内声明,覆写必须同样加守卫,否则游戏构建会报“does not override”。仅写 using FInstanceDataType 别名不会分配存储,必须实现 GetInstanceDataType(),否则 Context.GetInstanceData 会触发 check(Memory != nullptr)。条件必须是纯函数,因为一帧可能被多次调用。其余未在资料中说明的功能、收费、价格、平台或效果暂未提供。