Loading...
Loading...
Compare original and translation side by side
.agents/ue-project-context.mdStateTreeModuleGameplayStateTreeModuleMassEntityMassAIBehavior.agents/ue-project-context.mdStateTreeModuleGameplayStateTreeModuleMassEntityMassAIBehaviorUStateTreeComponentUStateTreeComponentUStateTreeUStateTree (UDataAsset)
├── UStateTreeSchema ← defines allowed context/external data
├── States[] ← hierarchical state tree
│ ├── Tasks[] ← work performed while state is active
│ ├── Transitions[] ← rules for leaving this state
│ └── Conditions[] ← gates on transitions
├── Evaluators[] ← global data providers (tick before transitions)
└── Parameters ← FInstancedPropertyBag default inputs| Class | Role |
|---|---|
| Data asset — call |
| Per-tick context — constructed each frame, NOT persisted |
| Persistent runtime state — survives across ticks |
| Actor component that manages tree lifecycle |
| |
StateTreeModuleGameplayStateTreeModuleFStateTreeInstanceData InstanceData; // persists across frames
// Each tick:
FStateTreeExecutionContext Context(Owner, *StateTree, InstanceData);
Context.Tick(DeltaTime);FStateTreeInstanceDataUStateTreeUStateTree (UDataAsset)
├── UStateTreeSchema ← 定义允许的上下文/外部数据
├── States[] ← 分层状态树
│ ├── Tasks[] ← 状态激活时执行的操作
│ ├── Transitions[] ← 离开此状态的规则
│ └── Conditions[] ← 状态转换的前置条件
├── Evaluators[] ← 全局数据提供器(在转换前执行Tick)
└── Parameters ← FInstancedPropertyBag默认输入| 类 | 作用 |
|---|---|
| 数据资产——执行前需调用 |
| 每帧上下文——每帧构造,不持久化 |
| 持久化运行时状态——跨帧保留 |
| 管理树生命周期的Actor组件 |
| 运行状态: |
StateTreeModuleGameplayStateTreeModuleFStateTreeInstanceData InstanceData; // 跨帧持久化
// 每帧:
FStateTreeExecutionContext Context(Owner, *StateTree, InstanceData);
Context.Tick(DeltaTime);FStateTreeInstanceData| Schema | Context Provided | Use Case |
|---|---|---|
| Actor + BrainComponent | General actor logic |
| Above + | AI behavior |
| Mass entity context | Mass Entity processing |
UStateTreeComponentSchemaContextActorClassTSubclassOf<AActor>UStateTreeAIComponentSchemaAIControllerClassTSubclassOf<AAIController>| Schema | 提供的上下文 | 用例 |
|---|---|---|
| Actor + BrainComponent | 通用Actor逻辑 |
| 上述内容 + | AI行为 |
| Mass实体上下文 | Mass Entity处理 |
UStateTreeComponentSchemaContextActorClassTSubclassOf<AActor>UStateTreeAIComponentSchemaAIControllerClassTSubclassOf<AAIController>UStateTreeSchemaUCLASS()
class UMyGameSchema : public UStateTreeSchema
{
GENERATED_BODY()
public:
virtual bool IsStructAllowed(const UScriptStruct* InStruct) const override;
virtual bool IsExternalItemAllowed(const UStruct& InStruct) const override;
virtual TConstArrayView<FStateTreeExternalDataDesc> GetContextDataDescs() const override;
#if WITH_EDITOR
virtual bool AllowEvaluators() const override { return true; }
virtual bool AllowMultipleTasks() const override { return true; }
virtual bool AllowGlobalParameters() const override { return true; }
#endif // WITH_EDITOR
};GetContextDataDescs()UStateTreeSchemaUCLASS()
class UMyGameSchema : public UStateTreeSchema
{
GENERATED_BODY()
public:
virtual bool IsStructAllowed(const UScriptStruct* InStruct) const override;
virtual bool IsExternalItemAllowed(const UStruct& InStruct) const override;
virtual TConstArrayView<FStateTreeExternalDataDesc> GetContextDataDescs() const override;
#if WITH_EDITOR
virtual bool AllowEvaluators() const override { return true; }
virtual bool AllowMultipleTasks() const override { return true; }
virtual bool AllowGlobalParameters() const override { return true; }
#endif // WITH_EDITOR
};GetContextDataDescs()const| Virtual | Returns | Called When |
|---|---|---|
| | State becomes active |
| | State is exited |
| | Each frame (if |
| | Child state completes (REVERSE order) |
| | Only if |
const| 虚函数 | 返回值 | 调用时机 |
|---|---|---|
| | 状态激活时 |
| | 状态退出时 |
| | 每帧(若 |
| | 子状态完成时(逆序) |
| | 仅当 |
| Flag | Default | Purpose |
|---|---|---|
| | Exit+Enter when transitioning to same state |
| | Enable per-frame Tick calls |
| | Tick only when events are pending |
| | Refresh property bindings each tick |
| | Enable |
bShouldCallTick = falseEnterStateExitState| 标志 | 默认值 | 用途 |
|---|---|---|
| | 转换到相同状态时执行Exit+Enter |
| | 启用每帧Tick调用 |
| | 仅当有事件待处理时执行Tick |
| | 每帧刷新属性绑定 |
| | 启用 |
EnterStateExitStatebShouldCallTick = falseconsttypedef FInstanceDataTypeUSTRUCT()
struct FMyTaskInstanceData
{
GENERATED_BODY()
float ElapsedTime = 0.f;
};
USTRUCT(meta=(DisplayName="My Custom Task"))
struct FMyTask : public FStateTreeTaskBase
{
GENERATED_BODY()
typedef FMyTaskInstanceData FInstanceDataType; // required — framework allocates storage
virtual EStateTreeRunStatus EnterState(FStateTreeExecutionContext& Context,
const FStateTreeTransitionResult& Transition) const override
{
FInstanceDataType& Data = Context.GetInstanceData(*this);
Data.ElapsedTime = 0.f;
return EStateTreeRunStatus::Running;
}
virtual EStateTreeRunStatus Tick(FStateTreeExecutionContext& Context,
float DeltaTime) const override
{
FInstanceDataType& Data = Context.GetInstanceData(*this);
Data.ElapsedTime += DeltaTime;
return Data.ElapsedTime >= Duration
? EStateTreeRunStatus::Succeeded : EStateTreeRunStatus::Running;
}
UPROPERTY(EditAnywhere, Category = "Parameter")
float Duration = 2.0f;
};references/state-tree-patterns.mdconsttypedef FInstanceDataTypeUSTRUCT()
struct FMyTaskInstanceData
{
GENERATED_BODY()
float ElapsedTime = 0.f;
};
USTRUCT(meta=(DisplayName="My Custom Task"))
struct FMyTask : public FStateTreeTaskBase
{
GENERATED_BODY()
typedef FMyTaskInstanceData FInstanceDataType; // 必须——框架会分配存储
virtual EStateTreeRunStatus EnterState(FStateTreeExecutionContext& Context,
const FStateTreeTransitionResult& Transition) const override
{
FInstanceDataType& Data = Context.GetInstanceData(*this);
Data.ElapsedTime = 0.f;
return EStateTreeRunStatus::Running;
}
virtual EStateTreeRunStatus Tick(FStateTreeExecutionContext& Context,
float DeltaTime) const override
{
FInstanceDataType& Data = Context.GetInstanceData(*this);
Data.ElapsedTime += DeltaTime;
return Data.ElapsedTime >= Duration
? EStateTreeRunStatus::Succeeded : EStateTreeRunStatus::Running;
}
UPROPERTY(EditAnywhere, Category = "Parameter")
float Duration = 2.0f;
};references/state-tree-patterns.mdAllowMultipleTasks()FailedSucceededAllowMultipleTasks()FailedSucceededUSTRUCT(meta=(Hidden))
struct FStateTreeConditionBase : public FStateTreeNodeBase
{
virtual bool TestCondition(FStateTreeExecutionContext& Context) const; // default: false
EStateTreeExpressionOperand Operand = EStateTreeExpressionOperand::And;
int8 DeltaIndent = 0; // indent level for logical grouping
EStateTreeConditionEvaluationMode EvaluationMode = EStateTreeConditionEvaluationMode::Evaluated;
};AndOrCopyDeltaIndent(A AND B) OR (C AND D)FStateTreeCompareIntConditionFStateTreeCompareFloatConditionFStateTreeCompareEnumConditionFGameplayTagMatchConditionFStateTreeObjectIsValidConditionFStateTreeCompareDistanceConditionUSTRUCT(meta=(Hidden))
struct FStateTreeConditionBase : public FStateTreeNodeBase
{
virtual bool TestCondition(FStateTreeExecutionContext& Context) const; // 默认:false
EStateTreeExpressionOperand Operand = EStateTreeExpressionOperand::And;
int8 DeltaIndent = 0; // 逻辑分组的缩进级别
EStateTreeConditionEvaluationMode EvaluationMode = EStateTreeConditionEvaluationMode::Evaluated;
};AndOrCopyDeltaIndent(A AND B) OR (C AND D)FStateTreeCompareIntConditionFStateTreeCompareFloatConditionFStateTreeCompareEnumConditionFGameplayTagMatchConditionFStateTreeObjectIsValidConditionFStateTreeCompareDistanceConditionUSTRUCT(meta=(Hidden))
struct FStateTreeEvaluatorBase : public FStateTreeNodeBase
{
virtual void TreeStart(FStateTreeExecutionContext& Context) const;
virtual void TreeStop(FStateTreeExecutionContext& Context) const;
virtual void Tick(FStateTreeExecutionContext& Context, float DeltaTime) const;
// Note: DeltaTime is 0 during preselection
};FInstanceDataTypeUSTRUCT(meta=(Hidden))
struct FStateTreeEvaluatorBase : public FStateTreeNodeBase
{
virtual void TreeStart(FStateTreeExecutionContext& Context) const;
virtual void TreeStop(FStateTreeExecutionContext& Context) const;
virtual void Tick(FStateTreeExecutionContext& Context, float DeltaTime) const;
// 注意:预选期间DeltaTime为0
};FInstanceDataTypeEStateTreeTransitionTriggerENUM_CLASS_FLAGS| Trigger | Value | Fires When |
|---|---|---|
| 1 | Active state returns Succeeded |
| 2 | Active state returns Failed |
| 3 | Either Succeeded or Failed (1|2) |
| 4 | Every frame (gate with conditions) |
| 8 | Matching event in the queue |
| 16 | Bound delegate fires |
EStateTreeTransitionTriggerENUM_CLASS_FLAGS| 触发类型 | 值 | 触发时机 |
|---|---|---|
| 1 | 激活状态返回Succeeded时 |
| 2 | 激活状态返回Failed时 |
| 3 | 状态返回Succeeded或Failed时(1|2) |
| 4 | 每帧(需配合条件作为门限) |
| 8 | 队列中有匹配事件时 |
| 16 | 绑定的委托触发时 |
EStateTreeTransitionPriorityLowNormalMediumHighCritical| Property | Default | Purpose |
|---|---|---|
| | Remove event from queue when transition fires |
| | Disable without removing |
| | Force Exit+Enter even if target is current state |
EStateTreeTransitionPriorityLowNormalMediumHighCritical| 属性 | 默认值 | 用途 |
|---|---|---|
| | 转换触发时从队列中移除事件 |
| | 禁用转换但不删除 |
| | 即使目标是当前状态,也强制执行Exit+Enter |
| Type | Purpose |
|---|---|
| Normal state with tasks, conditions, transitions |
| Container for child states — no tasks of its own |
| References another state within the same tree |
| References a state in a different |
| Embeds another |
LinkedAsset| 类型 | 用途 |
|---|---|
| 带有任务、条件、转换的普通状态 |
| 子状态容器——自身无任务 |
| 引用同一树中的另一个状态 |
| 引用另一个 |
| 将另一个 |
LinkedAssetEStateTreeStateSelectionBehavior| Behavior | Effect |
|---|---|
| Enter this state directly |
| Try children top-to-bottom, first valid wins |
| Random child selection |
| Utility-based selection (highest score) |
| Weighted random by utility score |
| Follow transition chain |
FStateTreeActiveStates::MaxStates = 8EStateTreeStateSelectionBehavior| 行为 | 效果 |
|---|---|
| 直接进入此状态 |
| 从上到下尝试子状态,第一个有效的状态胜出 |
| 随机选择子状态 |
| 基于效用值选择(最高得分) |
| 按效用值加权随机选择 |
| 遵循转换链 |
FStateTreeActiveStates::MaxStates = 8FStateTreeEventFGameplayTag TagFInstancedStruct PayloadFName Origin// From outside via UStateTreeComponent
TreeComp->SendStateTreeEvent(FGameplayTag::RequestGameplayTag("AI.Alert"));
// With payload
FMyAlertData AlertData;
AlertData.ThreatLevel = 5;
TreeComp->SendStateTreeEvent(
FGameplayTag::RequestGameplayTag("AI.Alert"),
FConstStructView::Make(AlertData), TEXT("PerceptionSystem"));
// From inside a task via execution context
Context.SendEvent(Tag, FConstStructView::Make(ResultData), TEXT("MyTask"));FStateTreeEventQueueMaxActiveEvents = 64bConsumeEventOnSelect = trueFStateTreeEventFGameplayTag TagFInstancedStruct PayloadFName Origin// 通过UStateTreeComponent从外部发送
TreeComp->SendStateTreeEvent(FGameplayTag::RequestGameplayTag("AI.Alert"));
// 带负载的事件
FMyAlertData AlertData;
AlertData.ThreatLevel = 5;
TreeComp->SendStateTreeEvent(
FGameplayTag::RequestGameplayTag("AI.Alert"),
FConstStructView::Make(AlertData), TEXT("PerceptionSystem"));
// 通过执行上下文从任务内部发送
Context.SendEvent(Tag, FConstStructView::Make(ResultData), TEXT("MyTask"));FStateTreeEventQueueMaxActiveEvents = 64bConsumeEventOnSelect = true// Declare handles in your task/condition/evaluator struct
TStateTreeExternalDataHandle<FMyActorContext, EStateTreeExternalDataRequirement::Required> ActorHandle;
TStateTreeExternalDataHandle<FMySubsystemContext, EStateTreeExternalDataRequirement::Optional> SubsystemHandle;
// Link in the Link override
virtual bool Link(FStateTreeLinker& Linker) override
{
Linker.LinkExternalData(ActorHandle);
Linker.LinkExternalData(SubsystemHandle);
return true;
}
// Access at runtime
auto& ActorCtx = Context.GetExternalData(ActorHandle); // Required — reference
auto* SubsystemCtx = Context.GetExternalDataPtr(SubsystemHandle); // Optional — pointerCollectExternalData// 在任务/条件/评估器结构体中声明句柄
TStateTreeExternalDataHandle<FMyActorContext, EStateTreeExternalDataRequirement::Required> ActorHandle;
TStateTreeExternalDataHandle<FMySubsystemContext, EStateTreeExternalDataRequirement::Optional> SubsystemHandle;
// 在Link重写中关联
virtual bool Link(FStateTreeLinker& Linker) override
{
Linker.LinkExternalData(ActorHandle);
Linker.LinkExternalData(SubsystemHandle);
return true;
}
// 运行时访问
auto& ActorCtx = Context.GetExternalData(ActorHandle); // 必填——引用
auto* SubsystemCtx = Context.GetExternalDataPtr(SubsystemHandle); // 可选——指针CollectExternalDataUStateTreeComponentUBrainComponentvoid SetStateTree(UStateTree* NewStateTree);
void SetStateTreeReference(FStateTreeReference NewStateTreeRef);
void SendStateTreeEvent(const FStateTreeEvent& Event);
void SendStateTreeEvent(FGameplayTag Tag, FConstStructView Payload, FName Origin);
EStateTreeRunStatus GetStateTreeRunStatus() const;
// Delegate — fires when run status changes
FStateTreeRunStatusChanged OnStateTreeRunStatusChanged; // BlueprintAssignable
bool bStartLogicAutomatically = true; // EditAnywhereUStateTreeComponentUBrainComponentvoid SetStateTree(UStateTree* NewStateTree);
void SetStateTreeReference(FStateTreeReference NewStateTreeRef);
void SendStateTreeEvent(const FStateTreeEvent& Event);
void SendStateTreeEvent(FGameplayTag Tag, FConstStructView Payload, FName Origin);
EStateTreeRunStatus GetStateTreeRunStatus() const;
// 委托——运行状态变化时触发
FStateTreeRunStatusChanged OnStateTreeRunStatusChanged; // BlueprintAssignable
bool bStartLogicAutomatically = true; // EditAnywhereFStateTreeReferenceUStateTree*FStateTreeReference TreeRef;
TreeRef.SetStateTree(MyStateTreeAsset);
TreeRef.SyncParameters();
TreeRef.GetParameters().SetValueFloat(TEXT("AggroRange"), 1500.f);FStateTreeReferenceOverridesOverrides.AddOverride(Tag_CombatVariant, CombatTreeRef);
Overrides.RemoveOverride(Tag_CombatVariant);UStateTreeComponentSetContextRequirements(FStateTreeExecutionContext&, bool bLogErrors)CollectExternalData(...)FStateTreeReferenceUStateTree*FStateTreeReference TreeRef;
TreeRef.SetStateTree(MyStateTreeAsset);
TreeRef.SyncParameters();
TreeRef.GetParameters().SetValueFloat(TEXT("AggroRange"), 1500.f);FStateTreeReferenceOverridesOverrides.AddOverride(Tag_CombatVariant, CombatTreeRef);
Overrides.RemoveOverride(Tag_CombatVariant);UStateTreeComponentSetContextRequirements(FStateTreeExecutionContext&, bool bLogErrors)CollectExternalData(...)UStateTreeAIComponentSchemaAIControllerClassAMyAIController::AMyAIController()
{
StateTreeComp = CreateDefaultSubobject<UStateTreeComponent>(TEXT("StateTree"));
StateTreeComp->bStartLogicAutomatically = true;
}UStateTreeContextActorClassUStateTreeAIComponentSchemaAIControllerClassAMyAIController::AMyAIController()
{
StateTreeComp = CreateDefaultSubobject<UStateTreeComponent>(TEXT("StateTree"));
StateTreeComp->bStartLogicAutomatically = true;
}UStateTreeContextActorClass| Aspect | State Tree | Behavior Tree |
|---|---|---|
| Structure | Hierarchical FSM with transitions | Tree of composites, decorators, tasks |
| Data flow | Evaluators + property bindings (typed) | Blackboard (string-keyed, loosely typed) |
| Conditions | First-class on transitions | Decorators on tree nodes |
| Mass Entity | Native via | No Mass support |
| Best for | Data-driven FSMs, Mass entities, flat logic | Deep decision hierarchies, complex aborts |
| 方面 | State Tree | 行为树 |
|---|---|---|
| 结构 | 带有转换的分层FSM | 由组合节点、装饰器、任务组成的树 |
| 数据流 | 评估器 + 属性绑定(类型化) | 黑板(字符串键,弱类型) |
| 条件 | 转换的一等公民 | 树节点上的装饰器 |
| Mass Entity | 通过 | 无Mass支持 |
| 最佳适用场景 | 数据驱动FSM、Mass实体、扁平逻辑 | 深度决策层次、复杂中断逻辑 |
references/state-tree-mass-integration.mdUMassStateTreeSchemaFMassStateTreeTaskBaseUMassStateTreeSubsystemAllocateInstanceDataFreeInstanceDataUMassStateTreeProcessorFMassStateTreeExecutionContextSetEntityGetEntityGetDependencies(UE::MassBehavior::FStateTreeDependencyBuilder&)ue-mass-entityreferences/state-tree-mass-integration.mdUMassStateTreeSchemaFMassStateTreeTaskBaseUMassStateTreeSubsystemAllocateInstanceDataFreeInstanceDataUMassStateTreeProcessorFMassStateTreeExecutionContextSetEntityGetEntityGetDependencies(UE::MassBehavior::FStateTreeDependencyBuilder&)ue-mass-entity// WRONG — context is per-tick, NOT persistent
FStateTreeExecutionContext* SavedContext; // dangling after tick
// RIGHT — reconstruct each tick from persistent instance data
FStateTreeExecutionContext Context(Owner, *StateTree, InstanceData);
Context.Tick(DeltaTime);// WRONG — task structs are const at runtime
virtual EStateTreeRunStatus Tick(...) const override {
Timer += DeltaTime; // compile error — 'this' is const
}
// RIGHT — use FInstanceDataType typedef
typedef FMyInstanceData FInstanceDataType;
virtual EStateTreeRunStatus Tick(...) const override {
auto& Data = Context.GetInstanceData(*this);
Data.Timer += DeltaTime;
}TestConditionFStateTreeActiveStates::MaxStates = 8Link()bConsumeEventOnSelect = falsetrue// 错误——上下文是每帧的,**不持久化**
FStateTreeExecutionContext* SavedContext; // Tick后会悬空
// 正确——每帧从持久化实例数据重建
FStateTreeExecutionContext Context(Owner, *StateTree, InstanceData);
Context.Tick(DeltaTime);// 错误——任务结构体在运行时是const的
virtual EStateTreeRunStatus Tick(...) const override {
Timer += DeltaTime; // 编译错误——'this'是const
}
// 正确——使用FInstanceDataType typedef
typedef FMyInstanceData FInstanceDataType;
virtual EStateTreeRunStatus Tick(...) const override {
auto& Data = Context.GetInstanceData(*this);
Data.Timer += DeltaTime;
}TestConditionFStateTreeActiveStates::MaxStates = 8Link()bConsumeEventOnSelect = falsetrueue-ai-navigationue-mass-entityue-gameplay-abilitiesue-gameplay-frameworkue-actor-component-architectureUStateTreeComponentue-cpp-foundationsue-ai-navigationue-mass-entityue-gameplay-abilitiesue-gameplay-frameworkue-actor-component-architectureUStateTreeComponentue-cpp-foundations