总览
Chooser 可以理解成 UE5.8 里一套“可编辑的决策表”。你把角色、武器、目标距离、输入标签、上一段技能、GameplayTag、随机上下文等信息喂进去,它按表格里的列逐步筛掉不匹配的行,再返回一个对象、类、资产,或者只写出一组输出参数。
它最适合处理这种问题:同一个玩法入口,在不同上下文下要选不同结果。比如轻攻击键按下后,双刀角色应该接第二段斩击,长枪角色应该突刺,空中状态应该下劈,目标太远应该前冲,玩家自定义了连招槽位时还要尊重玩家选择,同时不能绕过冷却、蓝耗、武器类型和解锁条件。
先给一句准确定义
UChooserTable 是表;FChooserEvaluationContext 是运行时输入和输出上下文;FChooserColumnBase 子类负责过滤、评分或写输出;每行的 Result 是 FObjectChooserBase 的实现,可以是资产、类、嵌套 Chooser、Proxy 查询等。运行时入口是 UChooserTable::EvaluateChooser,蓝图常用 UChooserFunctionLibrary 包装。
专题分篇目录
| 篇章 | 你会学到什么 | 读完能做什么 |
|---|---|---|
| 一 | 先做一张能选择下一段技能的 Chooser | 用输入 Tag、上一段技能、距离和武器类型选出 Ability 或动画 |
| 二 | Chooser 到底是什么,和 if/else、DataTable、StateTree 怎么分工 | 知道什么时候该用 Chooser,什么时候别用 |
| 三 | Schema、Context 和参数,先把输入喂对 | 会设计 Context Struct、对象参数、读写参数和属性绑定 |
| 四 | 列、过滤、评分、随机和输出 | 会配置 Bool、Enum、Float、GameplayTag、Object、Randomize、Output 列 |
| 五 | Result、Fallback、多结果和对象/类/资产选择 | 会返回 Ability Class、Montage、DataAsset,也会处理没命中 |
| 六 | 蓝图与 C++ 运行时调用 | 会构造 FChooserEvaluationContext,调用单结果、多结果和输出参数 |
| 七 | 动画系统里怎么用 | 会把 Chooser 接到 Animation Blueprint、Chooser Player、Pose Search、UAF |
| 八 | 玩家编辑技能连招完整案例 | 会做玩家改键/改连招 UI、SaveGame、GAS 验证和 Chooser 决策 |
| 九 | ProxyTable、嵌套 Chooser 和模块化内容 | 会做皮肤/武器/角色包替换,减少硬引用和大表复制 |
| 十 | 调试、性能、Cook 和生产规范 | 会用调试面板、Trace/Rewind、Cook 数据和检查清单上线 |
它适合解决什么
适合:动画资产选择、技能下一段选择、武器表现选择、AI 行为入口选择、掉落表变体、UI 提示变体、相机 Rig 选择、音效/震屏/特效选择、角色皮肤替换、运营活动内容替换。
不适合:长时间运行的流程控制、异步任务编排、网络权威状态机、复杂行为树、玩家直接编辑源码级表格。长期状态更适合 StateTree/GAS/Gameplay Task;Chooser 更像“在这个瞬间,根据上下文选一个结果”。
和玩家编辑技能连招的关系
这里要立一个边界:不要把 UChooserTable 当成玩家可编辑 UI 的直接存储格式。玩家应该编辑一个更安全、更小的连招配置,比如“轻攻击槽 1 放旋斩,槽 2 放挑斩,空中轻攻击放下劈”。这份配置进 SaveGame 或服务器档案;运行时把配置、输入、上一段、武器、距离、角色 Tags 一起喂给 Chooser。Chooser 再决定最终能不能出、出哪一个 Ability、用哪段 Montage、附带什么镜头/音效参数。
这样做的好处是:玩家有自由度,但不会绕过项目规则。冷却、资源、解锁、武器限制、空中状态、距离要求仍然由 GAS、StateTree、Movement 和 Chooser 表共同约束。
总体架构
Enhanced Input
-> Combo Input Buffer
-> Player Combo Profile / SaveGame
-> FComboChooserContext
-> UChooserTable
-> Ability Class / Montage / Output Struct
-> GAS TryActivateAbility + Animation / Camera / FX
Chooser 在这条链路里的职责是“解析”。它不负责监听按键,不负责保存玩家配置,不负责执行技能,也不负责动画播放全过程。它只负责根据输入上下文,把候选结果选出来。
源码依据
Chooser.uplugin 描述它用于构建动态资产选择逻辑,包含 Runtime 的 Chooser 和 ProxyTable,以及 Editor/Uncooked 模块。UChooserTable 持有 ColumnsStructs、CookedResults、FallbackResult 和编辑器期的 ResultsStructs。FChooserEvaluationContext 保存对象参数、结构体参数、输出数组和随机流。UChooserTable::EvaluateChooser 会用列逐步过滤候选行,命中后先执行输出列,再调用 Result 的 ChooseMulti。
使用案例
本专题会贯穿一个角色动作游戏案例:玩家可以在 UI 里编辑轻攻击、重攻击、闪避派生、空中派生的连招槽。输入系统只产生 Input.Attack.Light 之类的标签;玩家档案记录槽位偏好;Chooser 表按武器、上一段、目标距离、空中状态、玩家偏好、冷却和随机权重选出下一段 Ability 或 Montage;GAS 最后做权威激活和资源消耗。
架构分析
Chooser 的价值不是替代 GAS、StateTree 或动画蓝图,而是把“某个瞬间的分支选择”从代码散落处集中起来。它把设计师常改的条件放到表格里,把程序要保证的类型、安全、运行时调用和缓存留在代码里。越是动作游戏、角色动画和模块化内容,越容易出现几十个局部分支,Chooser 可以把它们整理成可查、可测、可调的决策资产。
常见坑
- 让玩家直接编辑
UChooserTable,结果版本升级、Cook、同步和作弊校验都变复杂。 - 把长流程塞进 Chooser,最后表格变成隐藏状态机。
- Context 设计太大,所有表都依赖同一个巨大角色对象,复用和测试都困难。
- 表里只写 Happy Path,没有 Fallback,线上遇到异常上下文直接返回空。
- 只在动画里用 Chooser,却忘了 Gameplay/GAS 侧也要做合法性验证。
源码路径索引
Engine/Plugins/Chooser/Chooser.upluginEngine/Plugins/Chooser/Source/Chooser/Public/Chooser.hEngine/Plugins/Chooser/Source/Chooser/Public/IObjectChooser.hEngine/Plugins/Chooser/Source/Chooser/Public/IChooserColumn.hEngine/Plugins/Chooser/Source/Chooser/Public/ChooserFunctionLibrary.hEngine/Plugins/Chooser/Source/ProxyTable/Public/ProxyTable.hEngine/Plugins/Experimental/UAF/UAFChooser/Source/UAFChooser/Private/RigUnit_EvaluateChooser.cpp