UE5.8 Chooser 喂饭级专题

UE5.8 Chooser 专题(二):Chooser 到底是什么,和 if/else、DataTable、StateTree 怎么分工

用动作游戏、AI、动画和掉落案例讲清 Chooser 的心智模型,避免把它误用成状态机、脚本系统或玩家编辑数据库。

总览

很多人第一次看到 Chooser,会把它理解成“可视化 if/else”或者“高级 DataTable”。这两个说法都只对一半。更准确地说:Chooser 是一个可编辑的运行时选择器,它拿到上下文后筛选候选行,返回一个结果或一组结果,并可顺手写出输出参数。

UE5.8 Chooser 专题(二):Chooser 到底是什么,和 if/else、DataTable、StateTree 怎么分工 配图
Chooser 不是状态机,也不是 DataTable 皮肤;它是运行时上下文驱动的选择器。

一句话判断

如果你的问题是“此刻应该选哪个”,优先考虑 Chooser。如果你的问题是“接下来一段时间怎么运行”,优先考虑 StateTree、Behavior Tree、Ability Task 或动画状态机。如果你的问题只是“ID 查固定配置”,DataTable/DataAsset 更简单。

和 if/else 的分工

小分支写代码很正常:

if (bIsDead)
{
    return;
}

但如果条件来自策划表、动画资产、武器类型、角色 Tag、距离、随机权重,并且每周都要调,那就不适合散在代码里。Chooser 把这些条件集中成表,程序只负责准备 Context 和执行结果。

和 DataTable 的分工

DataTable 适合按 RowName 或 ID 查一行。比如 WeaponId=RifleDamage=30。Chooser 适合按多条件选一行。比如“当前武器是 Rifle、目标距离 800、玩家蹲伏、敌人有护盾、输入是重攻击,所以选破盾射击”。

换句话说:DataTable 是 key-value/data lookup;Chooser 是 context decision。

和 StateTree 的分工

StateTree 管流程:巡逻、发现敌人、追击、攻击、撤退。Chooser 管局部选择:攻击状态里,到底选近战、投掷、射击、吼叫哪一个。两者可以很好配合:

StateTree: 进入 Attack State
  -> Task: 构造 AttackContext
  -> Chooser: 选择 AttackAbility 或 Montage
  -> GAS/Anim: 执行结果
  -> StateTree: 等待完成或失败

不要让 Chooser 负责“攻击状态何时退出”;那是状态树或 Ability 的职责。

和 GAS 的分工

GAS 是执行和权威系统:冷却、蓝耗、预测、Tag 阻塞、网络复制、AbilityTask。Chooser 只负责“从候选里建议选谁”。最终能不能激活,仍然交给 TryActivateAbilityCanActivateAbility 或项目自己的验证逻辑。

技能连招里推荐:

Chooser 选择候选 Ability
GAS 判断能不能激活
激活成功后更新连招状态
激活失败时走 Fallback 或提示 UI

和动画系统的分工

动画蓝图里也能用 Chooser,例如 Chooser Player 节点会选择 AnimationAsset,并带 FChooserPlayerSettings 控制开始时间、镜像、播放速率和 Blend。动画侧用 Chooser 很适合“同一姿态入口按速度/朝向/武器/地面状态选动画”。Gameplay 侧仍然要负责动作是否合法。

使用案例:四类问题怎么选工具

问题推荐工具原因
玩家按 Light 后下一段技能是什么Chooser + GAS多条件瞬时选择,再由 GAS 执行
Boss 从巡逻转攻击再转逃跑StateTree持续状态、条件、Task 和 Transition
武器基础伤害是多少DataAsset/DataTable纯数据查找
同一技能播放哪段 MontageChooser 或 AnimBP多条件资产选择

玩家编辑连招的正确位置

玩家编辑的是“偏好”和“槽位”,不是直接编辑表。表是项目规则,通常由开发者和策划维护;玩家配置是输入上下文的一部分。比如玩家把轻攻击第二段设为“旋斩”,Chooser 仍然会检查:是否已解锁、当前武器是否支持、是否在地面、上一段是否允许接、距离是否合适、GAS 是否能激活。

架构分析

Chooser 的表格化不是为了让所有逻辑无代码化,而是把变化频繁、需要可视化调试的选择逻辑集中出来。代码层仍然应该保留类型、上下文构建、权限、安全和执行。这个边界划清后,程序不会怕策划调表,策划也不需要等程序改一串 if/else。

常见坑

  • 把 Chooser 当完整行为树,表里开始模拟状态转移。
  • 把 DataTable 直接替换成 Chooser,导致简单 ID 查找反而复杂。
  • 让 Chooser 决定技能合法性,绕过 GAS 的冷却和消耗。
  • 一张表解决所有角色所有武器所有动作,最后没人敢改。
  • 每行 Result 都硬引用重资产,导致加载和 Cook 变重。

源码依据

FChooserColumnBase 同时支持过滤、成本、输出三类行为;UChooserTable::EvaluateChooser 对候选行逐列过滤,并在命中行时调用 Result 的 ChooseMulti。这说明 Chooser 的核心是“选择”,不是“持久运行”。RandomizeColumn 还提供带权随机,进一步说明它适合局部决策和变体选择。

源码路径索引

  • Engine/Plugins/Chooser/Source/Chooser/Public/Chooser.h
  • Engine/Plugins/Chooser/Source/Chooser/Public/IObjectChooser.h
  • Engine/Plugins/Chooser/Source/Chooser/Public/IChooserColumn.h
  • Engine/Plugins/Chooser/Source/Chooser/Private/Chooser.cpp
  • Engine/Plugins/Chooser/Source/Chooser/Internal/RandomizeColumn.h