UE5.8 Unreal Animation Framework 专题系列

UE5.8 UAF 专题(五):Chooser 集成、选择表与图资产工厂

拆解 UUAFAnimChooserTable、FUAFChooserPlayerTraitSharedData、FUAFGraphChooser、变量参数、EvaluationFrequency 和基于 Chooser 的动画图选择。

总览

UAFChooser 的任务是把 Chooser 选择表接到 UAF 图资产。项目里常见需求是“根据速度、武器、姿态、地面状态、角色体型选择不同动画子图或资产”。如果把这些判断硬写进动画图,后期会变成难以维护的布尔分支。Chooser 更适合把条件和结果表格化。

UE5.8 UAF 专题(五):Chooser 集成、选择表与图资产工厂 配图
Chooser 把运行时变量映射到资产选择,UAF 再把选中的对象解释为可运行的动画图资产。

源码依据

重点文件:

  • UAFChooser/Public/UAFAnimChooser.h
  • UAFChooser/Public/ChooserPlayerTraitData.h
  • UAFChooser/Internal/ChooserParameters.h
  • UAFChooser/Internal/ObjectChooser_UAFGraph.h
  • UAFChooser/Public/UAFGraphFactoryAsset_Chooser.h
  • UAFChooser/Internal/AnimNode/UAFChooserPlayerNode.h

UUAFAnimChooserTableUChooserTable 的 UAF 专用子类,用于选择能生成 UAF AnimGraph 的资产。FUAFChooserPlayerTraitSharedData 是图里的 Chooser Player trait data,保存 Chooser 表和 EChooserEvaluationFrequency

Chooser 结果如何变成 UAF 图

FUAFGraphChooser 继承 FObjectChooserBase,DisplayName 是 UAFGraph,ResultType 是 Object。它不直接保存旧的 Asset 字段,而是用 TInstancedStruct<FUAFGraphFactoryAsset> AssetData。源码里旧 Asset_DEPRECATEDFAnimNextFactoryParams Parameters 都标了 deprecated,UE5.8 这条线明显转向“FactoryAsset 结构体”。

FUAFGraphFactoryAsset_Chooser 则反过来把 Chooser Table 包装成 UAF 图资产工厂:

USTRUCT(DisplayName="Chooser Asset")
struct FUAFGraphFactoryAsset_Chooser : public FUAFGraphFactoryAsset
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, Category = Chooser)
    TObjectPtr<const UUAFAnimChooserTable> ChooserTable;

    UPROPERTY(EditAnywhere, Category = Settings)
    EChooserEvaluationFrequency EvaluationFrequency =
        EChooserEvaluationFrequency::OnBecomeRelevant;
};

工程上可以这样理解:Chooser 的每一行结果不是“播放某个动画”这么窄,而是可以返回一个能被 UAF 解释为图的资产描述。

参数来源

ChooserParameters.h 里定义了 UAF 变量参数:

参数 读取类型 典型用途
FBoolAnimProperty bool 是否瞄准、是否在空中、是否持盾
FFloatAnimProperty float 速度、坡度、转向角、距离
FEnumAnimProperty enum/byte 移动模式、武器类型、姿态
FNameAnimProperty FName 命名状态、slot、stance

这些参数都保存 FAnimNextVariableReference Variable。所以 Chooser 表不是自己找 Character,也不是读蓝图变量,而是通过 UAF 公共变量读取输入。

Evaluation Frequency

Chooser Player 里有 EChooserEvaluationFrequency

  • OnBecomeRelevant:进入相关状态时选择一次。适合武器类型、角色体型、装备集合等不需要每帧变的条件。
  • OnUpdate 或类似每帧更新模式:适合速度区间、地面状态、短时状态。代价更高,但反应快。

默认频率要谨慎。动画系统里“每帧查表”不是不能做,但如果结果会触发图切换,就会牵涉 blending、重置、同步和性能。

项目落地

建议把 Chooser 表按职责拆开:

  1. Locomotion Chooser:速度、移动模式、坡度、转向角 -> locomotion graph。
  2. Weapon Chooser:武器类型、持握方式 -> upper body graph。
  3. Stance Chooser:站立、蹲伏、受伤、重载 -> pose layer 或 state graph。
  4. Cinematic Chooser:剧情状态、角色体型、装备 -> 特殊覆盖图。

公共变量示例:

USTRUCT(BlueprintType)
struct FProjectAnimChooserVars
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere)
    float Speed = 0.0f;

    UPROPERTY(EditAnywhere)
    bool bIsInAir = false;

    UPROPERTY(EditAnywhere)
    FName WeaponStance = TEXT("Unarmed");
};

Chooser 表里把 Speed 绑定到 FFloatAnimProperty,把 bIsInAir 绑定到 FBoolAnimProperty,把 WeaponStance 绑定到 FNameAnimProperty。结果列使用 UAFGraph,返回对应的 UAF Graph Factory Asset。

使用案例:Locomotion Chooser 表

一个最小 locomotion Chooser 可以只关心三个输入:GroundSpeedbIsInAirWeaponStance。表格不要一开始写得很细,先用少量稳定行验证图选择:

GroundSpeed bIsInAir WeaponStance Result
0 到 5 false Any AG_Hero_Idle
5 到 180 false Any AG_Hero_WalkRun
Any true Any AG_Hero_InAir
Any false Rifle AG_Hero_Rifle_Locomotion

操作步骤:

  1. 创建 UAF Shared Variables,至少包含 GroundSpeedbIsInAirWeaponStance
  2. 创建 UAF Anim Chooser Table,把 Shared Variables 加到 context。
  3. 添加 FFloatAnimProperty 列绑定 GroundSpeed
  4. 添加 FBoolAnimProperty 列绑定 bIsInAir
  5. 添加 FNameAnimProperty 或 enum 参数列绑定 WeaponStance
  6. 结果列使用 UAFGraph,每行返回一个 UAF Graph Factory Asset。
  7. 在 UAF Animation Graph 中放 Chooser Player,指向这张表。
  8. 初始 EvaluationFrequencyOnBecomeRelevant 验证稳定性;需要速度实时切换时再评估高频模式。

如果表格开始出现几十个速度区间,说明 Chooser 被当成 BlendSpace 用了。速度连续变化应该交给 BlendSpace、Motion Matching 或图内 blend,Chooser 只负责选择大类图。

使用案例:武器上半身图选择

武器表应该和 locomotion 表分开,避免一张表同时决定“脚怎么走”和“手怎么拿武器”:

WeaponStance bIsAiming Result
Unarmed false AG_Upper_Unarmed_Relaxed
Rifle false AG_Upper_Rifle_Hip
Rifle true AG_Upper_Rifle_Aim
GreatSword Any AG_Upper_GreatSword

这张表可以被 LayerStack 的 UpperBody 层使用。切换武器时只影响上半身层,不应该重置地面移动图。多人项目里也更容易做网络回放:WeaponStance 是离散变量,日志和 Rewind 都能看懂。

架构分析:Chooser 放在哪里

放置位置 适合场景 风险
AnimGraph 内部 Chooser Player 子图选择、资产选择、可视化调试 高频重选会触发过渡抖动
StateTree 进入状态后写变量,再由 Chooser 选图 离散状态驱动的图选择 变量写入和图切换顺序要明确
LayerStack 每层独立 Chooser 上半身、表情、受击层互不干扰 表之间可能重复条件
C++ 里手写 if/else 后设置图 紧急原型 不利于动画师维护和调试

建议原则是:Chooser 负责“大方向选择”,图内负责连续混合,StateTree 负责状态生命周期。

调试方法

排查 Chooser 问题按这个顺序:

  1. 变量是否写入了正确的 UUAFComponent 或系统实例。
  2. FAnimNextVariableReference 是否指向当前 Chooser 上下文能访问的变量资产。
  3. Chooser 参数类型是否和变量类型一致。
  4. EvaluationFrequency 是否导致结果没有重新计算。
  5. 返回对象是否能被 UAF 转成图资产。
  6. 图切换是否被 BlendStack、Injection 或上层 StateTree 覆盖。

常见坑

  • 不要在 Chooser 里塞所有动画逻辑。Chooser 只负责选择,时间推进、姿态混合和同步应留给图。
  • 不要让多个 Chooser 表同时写同一个决策变量,容易出现帧序依赖。
  • 不要把高频连续值拆成大量区间后每帧重选大图,先考虑 BlendSpace 或 Motion Matching。
  • UAF 的 Chooser 结果应该返回图资产工厂相关数据,旧 Asset_DEPRECATED 字段只是迁移兼容。
  • FUAFSharedVariablesContext 可以声明上下文变量资产,表格维护时要保证上下文完整。

源码路径索引

  • UAFChooser/Source/UAFChooser/Public/UAFAnimChooser.h
  • UAFChooser/Source/UAFChooser/Public/ChooserPlayerTraitData.h
  • UAFChooser/Source/UAFChooser/Internal/ChooserParameters.h
  • UAFChooser/Source/UAFChooser/Internal/ObjectChooser_UAFGraph.h