接入最小命令单位
本篇做出一个可验证的 AI 单位闭环:守卫 Pawn 平时运行自己的 AI,收到移动命令后进入 Command StateTree;玩家可追加两个路点,随后插入一次紧急闪避,最后取消命令并看到原行为恢复。这个场景同时验证 Pawn 挂载限制、执行层路由、FIFO 队列和打断边界。
相关文档:先理解命令系统,字段细节见命令定义与下发参数,需要自定义后端时读命令扩展点。
前置条件
准备一个由 AAIController 控制的 Pawn 或 Character,并确认它不是玩家控制 Pawn。默认 StateTree 执行层将拒绝 Player-controlled Pawn、没有 AIController 的 Pawn,以及 Controller 上没有 StateTreeStack 的情况。
- 项目已启用 GenericAISystem 与 StateTree / GameplayStateTree 依赖。
- Pawn 的 Controller 上已有
UGAIS_StateTreeStackComponent,并配置了可用的 Command 层。 - 项目 Blackboard 已保留默认命令 Key,或已同步修改
UGAIS_DeveloperSettings与 StateTree 中的读取 Key。 - 操作命令下发逻辑在服务端运行;若来自拥有该 Pawn 的客户端,则使用对应的
Server...RPC。
UGAIS_CommandSystemComponent 必须添加在 Pawn 本身,不是 AIController、普通 Actor 或建筑 Actor。若当前测试对象是一个普通 Actor,先改为 Pawn/Character 再继续;仅把组件通过蓝图添加到 Actor 不构成受支持的配置。
1. 给 AI Pawn 添加组件
在守卫 Pawn Blueprint 的 Components 面板添加 Command System Component(UGAIS_CommandSystemComponent)。不要把它添加到 Controller Blueprint。若该单位之后还要进入小队或 Tactical Assignment,再额外添加 UGAIS_UnitComponent;本教程不依赖它。
运行 PIE 后,在服务端获取该 Pawn 的 Get CommandSystemComponent。初始时 IsIdle 应为 true,GetCurrentCommandData 为空,队列为空。这个检查能立即发现组件挂错对象或未正确初始化的问题。
2. 创建最小移动命令
创建一个 Blueprint,父类选择 Simple Command Definition,取名 Cmd_Move。Simple 适合“一个资产就是一个稳定命令”的情况;移动、交互、治疗和普通攻击通常都从它开始。
在资产中完成下面的最小配置:
分组 | 建议配置 | 目的 |
|---|---|---|
Common | | 位置请求可被接受,也允许新的移动或闪避打断。 |
Display | 填名称、图标与可选按钮槽位。 | 供 HUD 或命令界面展示;不影响执行合法性。 |
Range | 首轮可保持默认或按移动完成距离设置。 | 供 StateTree 读取距离语义。 |
Execution | 添加内联 | 采用默认的 StateTree 后端来执行命令。 |
可在 Execution 的 StateTree 字段选择一个StateTree资产,该字段是完整 FStateTreeReference,可按 StateTree 的正常方式配置默认参数。

3. 编写最小化的移动StateTree
新建一个StateTree,Schema选择StateTreeAIComponentSchema,并将资产命名为ST_Cmd_Move。

该 StateTree 非常简单,它不决定“要不要移动”。它只负责 CommandSystem 已验证的当前命令的实际执行:
1.通过StateTree context拿到自身 Pawn和Controller、
2.通过提供的BB(Blackboard) Evaluators获取接受命令期间写入到黑板组件的目标位置等信息。
3.Root节点具有Task:Timer任务,配合Duration参数,实现命令的执行超时。 4.将命令目标数据和移动参数,喂到原生的MoveToTask。
5.MoveToTask在抵达时回报成功;目标不可达、被阻挡或外部条件失败时回报失败。

6.Timer超时,也会触发Transition回报成功。
例如守卫单位可在 Command StateTree 中执行:
1读取当前 Location 命令2→ 请求移动到位置3→ 到达:完成 Succeeded4→ 导航失败/目标无效:完成 Failed
Command 层结束后,StateTreeStack 会撤销这条命令对应的路由,守卫的低优先级巡逻 StateTree 可继续运行。不要让 Command StateTree 永远停留在运行状态,否则队列永远不会推进。
4. 构造并下发第一条命令
在服务端蓝图或权威 C++ 逻辑中,构造 Location 形式的 FGAIS_CommandData:Definition 指向 Cmd_Move,bHasLocation 为 true,Location 为点击点;Simple 命令的 Index 通常保持 -1。将它传给 Pawn 的 IssueCommand。
1选择守卫 Pawn2→ Get CommandSystemComponent3→ Make Location Command Data(Move、目标位置、Index=-1)4→ Issue Command5→ 检查返回值为 Started
验证点:CurrentCommand 变为 Move,StateTreeStack 进入 Command 层,守卫开始移动。若返回 Rejected,先检查 TargetType 与载荷是否同为 Location、Execution 是否有有效 StateTree,再检查 Pawn 的 Controller/Stack 条件。
5. 验证排队与插队
继续使用同一个移动命令构造两个不同位置的请求。
- 当守卫正在移动时,对位置 B、位置 C 依次调用
EnqueueCommand。两次都应返回Queued,GetCommandQueue顺序为 B、C。 - 再构造“到医疗点”的位置请求,调用
InsertCommandAfterCurrentCommand。它不打断当前移动,但应出现在 B 之前。 - 构造“闪避到安全点”的位置请求,调用
InsertCommandBeforeCurrentCommand。因为 Move 是Cancelable,当前移动会被取消,闪避立即开始;闪避成功后,被中断的移动才有机会继续。
这正是实时战术游戏中常见的交互:Shift 追加巡逻点,临时拾取/治疗放在下一步,爆炸警告则使用前插闪避。不要把所有高优先级命令都做成 IssueCommand;它会替换当前命令并清空已有队列,适合“新意图完全覆盖旧意图”的场景。
6. 验证取消与结果
移动途中调用 CancelCommand。只有当前命令为 Cancelable 时才会返回 true;随后 Command StateTree 收到取消,CurrentCommand 清空,最近结果显示 Canceled 和对应原因,低层守卫 AI 恢复。
观察这些接口,而不是从执行层私有状态猜测结果:
观察点 | 应看到什么 |
|---|---|
| 当前命令进入、替换或清空。 |
| 排队、前插或清理后的顺序。 |
| 最近一次成功、失败或取消及原因标签。 |
GameplayDebugger CommandSystem 面板 | Current、Queue、Last、LastResult 与 ReasonTag。 |
ClearCommandQueue 只放弃等待项,适合玩家取消 Shift 路点但保留正在走的路;ClearCommands 还会尝试取消当前命令,因此会受 NonCancelable 保护。
MultiVariant:一个入口,多种 AI 行为
当“攻击”按钮需要根据选择或单位类型执行近战、远程和治疗性攻击时,创建 Multi Variant Command Definition,而不是复制三个几乎相同的 Simple 资产。为 Variants 的每项设置 DebugName、TargetType、Requirements、Display、Range 和 ExecutionDefinition;运行时 FGAIS_CommandData.Index 选择数组位置。
例如 Index 0 配置近战 Command StateTree,Index 1 配置远程 Command StateTree,Index 2 配置施法 StateTree。它们可以有不同射程、目标要求和 UI 显示。务必保持 Index 稳定:保存的命令引用、UI 和 Tactical Assignment 都用数组位置选择变体,不使用 DebugName 作为运行时身份。
什么时候不要用默认 StateTree 后端
默认 StateTree 后端通常足够:StateTree 可以组织移动、交互、动画、项目任务,也能在其中启动 Ability。只有当命令的主执行生命周期明确由其他运行时拥有时,才创建自定义 CommandExecutionDefinition,例如项目已有 Behavior Tree 任务系统,或一条命令应直接等待 GAS Ability 的完成回调。
此时仍然保留本篇的 Pawn、CommandSystem、下发和结果验证流程;变化仅在 Execution 字段选择你的适配器。自定义适配器必须在完成时回报给同一个 CommandSystem,并在取消时只清理这一次执行拥有的外部状态。
常见失败
症状 | 优先检查 |
|---|---|
组件无法正确使用或没有 CommandSystem | 是否把组件添加在 Pawn/Character,而不是 Actor 或 Controller。 |
命令接受后立刻失败,Reason 是 StateTree context | Pawn 是否非玩家控制,是否由 AAIController 控制,Controller 是否有 StateTreeStack。 |
返回 | Definition、Index、TargetType 与载荷、 |
队列不继续 | 当前执行是否确实报告成功;失败通常不会推进依赖队列。 |
前插没有发生 | 当前命令是否为 |
UI 显示已下达但服务端无变化 | 调用是否在权威端,或客户端是否真正拥有该 Pawn。 |
