
1. 为什么 FPS 游戏需要“多状态树嵌套”1.1 从状态机到多状态树解决什么问题在 UE5 里做纯蓝图 FPS 游戏开发时很多新手会遇到同一个困境角色的状态越来越多比如待机、走路、跑步、跳跃、开火、换弹、瞄准、死亡、受击……如果用传统的枚举变量加分支判断蓝图会迅速膨胀。最典型的情况是你需要在“瞄准射击”和“移动跳跃”之间来回切换还要处理开火动画、准星扩散、镜头视野变化、角色速度变化这时候你会发现普通 if / Switch 已经很难维护了。多状态树State Tree是 UE5 中用来替代传统状态机的高阶状态管理方案。它把角色行为拆成一棵树每个节点代表一个状态或者一个行为模块状态之间可以嵌套、并行、条件切换。简单说普通状态机是“一个时刻只能处于一个状态”多状态树可以“一个状态内部再挂多个子状态”并且支持多个行为同时运行。比如角色可以同时处于“瞄准状态”和“移动状态”瞄准影响视角移动影响速度两者互不覆盖。在 FPS 游戏中这个能力非常关键。因为 FPS 角色的行为不是线性的而是组合的。举几个实际场景角色在瞄准时仍然可以移动、跳跃、蹲下。角色在开火时可以同时播放开火动画、触发后坐力、更新弹痕。角色在换弹时射击被锁定但移动仍然允许。角色死亡时所有行为停止但摄像机还要继续控制。如果不用多状态树这些组合逻辑很难写得干净。而 UE5 的 State Tree 插件正是为了应对这种复杂行为而设计的。1.2 本文适合哪些读者本文围绕“UE5 纯蓝图 FPS 游戏开发”展开重点讲如何通过多状态树嵌套的方法实现状态间的转换。适合以下读者已经能完成 UE5 基础蓝图操作但想突破“if 嵌套地狱”的开发者。正在做 FPS 射击类 Demo遇到状态切换混乱问题的朋友。想了解 UE5 State Tree 插件在纯蓝图项目里怎么落地的学员。对行为树有基础但想对比“行为树”和“多状态树”区别的开发者。在本篇内容中你会学会什么是 State Tree它和传统枚举状态机有什么区别。如何在 UE5 中启用 State Tree 插件。如何用纯蓝图不写 C创建一棵多状态树。如何通过嵌套状态实现“移动射击 瞄准切换 换弹锁定”的组合行为。状态转换的触发条件和优先级怎么配置。常见坑与排查思路。先说明一点State Tree 插件在 UE5 中默认没有启用需要手动开启。接下来的内容全部以蓝图实现为主适合不想碰 C 的纯蓝图开发者。2. 环境准备与版本说明2.1 UE5 版本与插件启用本文示例使用 UE5.3 及以上版本进行讲解。State Tree 插件在 UE5.0 之后逐步稳定在 UE5.3、UE5.4 中功能相对完善。如果你使用的是 UE5.1 或 UE5.2界面可能会有细微差异但核心概念一致。若你的项目版本不同请以实际界面为准。要启用 State Tree 插件按以下步骤操作打开你的 UE5 项目进入“编辑Edit”。选择“插件Plugins”菜单。在搜索框中输入 State Tree。找到 State Tree 插件勾选 Enabled。点击“重启Restart”按钮等待编辑器重启。需要注意State Tree 插件默认是实验性插件还是正式插件在不同版本中标注不同。在 UE5.3 中它已作为正式插件提供但在纯蓝图项目中它仍然需要在插件面板中手动启用。启用后你可以在内容浏览器中右键创建“State Tree”资产。如果搜索不到建议先检查项目是否是 C 项目。虽然蓝图项目也可以使用 State Tree但某些版本中编辑器对蓝图项目的插件支持略有差异。如果实在找不到可以考虑创建一个包含最少 C 代码的空项目或者直接使用 UE5 自带的 Third Person 模板项目。2.2 开发环境建议本文的完整实操流程建议按以下环境准备项目建议值UE5 版本5.3 或 5.4项目类型蓝图工程Blank / Third Person目标平台PCWindows / Mac输入方式键盘鼠标角色控制器Character 类网络要求单机即可暂不涉及多人网络同步如果你是做移动端 FPS比如微信小游戏或者手机平台State Tree 仍然可以用于逻辑管理但输入处理和 UI 交互需要额外适配。本文以 PC 端 FPS 逻辑为例移动端会在最佳实践部分简单说明。2.3 示例项目结构为了便于理解建议先搭建一个干净的测试场景。项目结构如下Content/ Characters/ BP_FPSCharacter // FPS 角色蓝图 Animations/ ABP_FPSCharacter // 动画蓝图 StateTrees/ ST_FPSCharacter // 角色多状态树 Maps/ TestFPSMap // 测试地图如果你已经有现成的 FPS 角色可以直接在其上添加 State Tree 组件。如果你是从零开始建议先创建基础角色蓝图确保角色能正常移动和跳跃再开始状态树改造。3. 多状态树核心概念与原理拆解3.1 State Tree 的基本组成State Tree 主要由三部分构成State Tree 资产State Tree Asset它是一棵独立的行为状态管理资源可以在内容浏览器中创建并编辑。一个角色可以引用一个或多个 State Tree 资产。状态节点State Node状态节点是树中的基本单元。每个节点代表一个具体状态比如“Idle待机”“Move移动”“Fire开火”“Reload换弹”“Jump跳跃”等。节点可以嵌套子节点继承父节点条件。状态转换Transitions状态转换描述一个状态在什么条件下切换到另一个状态。UE5 的 State Tree 中转换可以是“状态完成后切换Completed”也可以是“条件满足时切换Triggered by condition”。核心思想是状态树本质上是一个有层次的行为决策器。父状态决定“大类”子状态决定“子行为”。比如FPS角色状态树 ├── 生存状态 │ ├── 移动状态 │ │ ├── 行走 │ │ ├── 奔跑 │ │ └── 蹲伏 │ ├── 战斗状态 │ │ ├── 瞄准 │ │ ├── 开火 │ │ └── 换弹 │ └── 跳跃状态 └── 死亡状态这种嵌套结构比传统的“全局状态枚举 无数个if”清晰得多。因为每种组合行为都被折叠成树的局部结构而不是平铺开来的条件分支。3.2 状态转换的两种核心方式在使用纯蓝图实现多状态树时最需要理解的是转换触发机制。UE5 State Tree 中最常见的转换方式有两种。方式一状态完成后转换On Completed当一个状态执行完自己的逻辑后自动跳转到下一个状态。适合一次性行为比如“开火状态”播放完开火动画后回到“待机状态”。在蓝图中你可以设置 State Tree 节点的“State Completed”过渡条件也可以使用动态转换。方式二条件满足时转换On Condition当外部条件成立时立即切换到另一个状态。比如“按下瞄准键”时从“待机状态”切换到“瞄准状态”。条件来源可以是角色蓝图的变量、输入事件、AI 感知、动画通知等。在实际 FPS 项目中两种方式会混合使用。例如开火状态自身播放动画动画播放完后通过 Completed 转换回待机。但按下瞄准键时无论当前处于移动还是待机通过 Condition 优先切入瞄准状态。这里就引出了“优先级”问题瞄准的优先级应该高于移动但低于死亡。UE5 State Tree 通过节点顺序和转换优先级来管理这一点。树的顶层父状态负责最大粒度的判断比如“是否死亡”下层子状态负责具体行为切换。3.3 嵌套状态为什么适合 FPS传统的 Animation Blueprint 状态机AnimGraph State Machine即“动画蓝图状态机”非常适合控制动画播放但它的职责是“根据当前状态播放对应动画”并不擅长管理大量游戏逻辑条件。State Tree 的嵌套状态更适合管理“逻辑行为”。因为它的状态节点可以绑定对应的游戏逻辑比如修改移动速度、开启武器碰撞、播放音效、切换摄像机视野角度等。这些逻辑可以挂在状态节点上进入状态时执行 Enter离开状态时执行 Exit持续期间执行 Tick。在 FPS 中玩家最常见的操作组合就是按住鼠标右键瞄准。按 WASD 移动。按 Shift 奔跑。按鼠标左键开火。按 R 换弹。这些操作不是互斥的。你可以在瞄准的同时移动但奔跑时可能禁用瞄准。如果把这些组合逻辑全部写在角色蓝图的事件图表里代码会非常复杂而用 State Tree 嵌套我们可以把“瞄准”和“移动”放在同一层级的不同分支再通过转换规则限制组合。举例瞄准状态内可以嵌套移动状态表示“瞄准时仍然可以移动”。移动状态内再嵌套奔跑状态但奔跑状态的进入条件中禁用瞄准。这样两种组合被树结构自然表达。4. 纯蓝图创建多状态树完整实战4.1 创建 State Tree 资产启用插件后在内容浏览器中右键点击内容目录。选择“Artificial Intelligence人工智能”。选择“State Tree状态树”。命名为 ST_FPSCharacter。双击打开 State Tree 编辑器你会看到左栏是状态树节点面板中间是树视图右侧是节点细节面板。刚创建的 State Tree 默认只有一个 Root 节点。我们需要在 Root 节点下创建状态层级。4.2 创建基础状态节点在 State Tree 编辑器中右键 Root 节点选择“Add State添加状态”。先添加两个一级状态Alive存活状态Dead死亡状态将 Root 节点连接到这两个状态。Alive 状态作为父状态继续添加子状态Movement移动状态Combat战斗状态Jump跳跃状态在 Movement 下继续添加Walk行走Run奔跑Crouch蹲伏在 Combat 下添加Aim瞄准Fire开火Reload换弹这样我们就建立了最基本的嵌套状态树。对应结构如下Root ├── Alive │ ├── Movement │ │ ├── Walk │ │ ├── Run │ │ └── Crouch │ ├── Combat │ │ ├── Aim │ │ ├── Fire │ │ └── Reload │ └── Jump └── Dead每一个节点都可以设置进入条件Enter Condition和运行逻辑在蓝图中绑定事件。对于 FPS 角色我们通常把“角色蓝图”作为 State Tree 的运行上下文。4.3 在角色蓝图中添加 State Tree 组件打开 BP_FPSCharacter 角色蓝图点击“添加组件Add Component”。搜索 StateTree。选择 StateTree 组件并添加。在 State Tree 组件的细节面板中在 State Tree 属性中选择我们创建的 ST_FPSCharacter。在“Context Actor上下文Actor”中通常设置为 Self表示状态树引用角色本身为执行上下文。然后在角色蓝图的事件图表中编写以下蓝图逻辑在“BeginPlay”事件中调用“Start State Tree”节点。在“EndPlay”事件中调用“Stop State Tree”节点。注意这里的最小蓝图网络如下文字描述Event BeginPlay - Start State TreeTarget 是 StateTree 组件StateTree 资产指定为 ST_FPSCharacter此时运行游戏State Tree 开始执行但所有状态都没有绑定具体逻辑角色不会发生任何变化。接下来我们需要把状态节点绑定到蓝图逻辑上。4.4 用蓝图实现状态节点的 Enter / Tick / Exit在 State Tree 编辑器中选中任意状态节点右侧细节面板下面有“Evaluators”“Tasks”“Transitions”等栏目。在纯蓝图实现中常用的是“Tasks任务”。Tasks 可以绑定蓝图类中的函数。对于每个状态节点我们可以新建对应的蓝图任务类。为了简化这里介绍一种常见的纯蓝图实现方式创建一个“蓝图类Blueprint Class”父类选择 StateTreeTaskBlueprintBase。在类中重写以下事件Receive Enter进入状态时调用Receive Tick状态持续期间每帧调用Receive Exit退出状态时调用在每个事件中通过 Connected Objects 获取角色蓝图并调用自定义函数。举个例子创建蓝图类 BP_Task_Fire。在 Receive Enter 事件中Get Connected Actor (State Tree Context Actor) - Cast to BP_FPSCharacter - 调用 FireWeapon 自定义事件在 Receive Exit 事件中Get Connected Actor - Cast to BP_FPSCharacter - 调用 StopFire 自定义事件然后在 State Tree 编辑器中选中 Fire 状态节点在 Tasks 列表中添加 BP_Task_Fire。这样当状态树切换到 Fire 状态时自动调用角色的开火逻辑退出该状态时自动停止开火。4.5 状态转换条件与优先级配置现在最关键的问题来了如何配置状态转换。在 State Tree 编辑器中选中 Alive 状态节点细节面板有 Transitions 栏目。我们可以添加:Transition 1触发条件角色死亡通过条件节点判断 Health 0目标状态Dead优先级高在 Movement 和 Combat 之间也需要转换。你可以选中 Movement 状态添加 TransitionsTransition 1条件IsAiming瞄准时为 true目标状态Combat/Aim说明当玩家按下右键瞄准时从移动转换到战斗瞄准。Transition 2条件IsMoving移动输入非零时 true目标状态Movement/Walk说明当玩家按住 WASD 时从待机转换到移动。Combat 状态内Aim 状态下可以继续监听 FireInput 和 ReloadInputFrom Aim 状态条件IsFiring鼠标左键按下目标状态Combat/FireFrom Fire 状态条件动画播放完毕或 IsFiring 为 false目标状态Combat/AimFrom Aim 状态条件IsReloading按下 R目标状态Combat/ReloadFrom Reload 状态条件ReloadCompleted目标状态Combat/Aim这些条件可以来自角色蓝图中的布尔变量。State Tree 提供了 Condition 节点例如“Bool Compare布尔比较”。我们可以在 State Tree 编辑器中添加“Condition - Compare Bool”输入源选择角色蓝图中的变量。蓝图操作如下在角色蓝图中创建公开布尔变量bIsAiming、bIsFiring、bIsReloading、bIsDead。在 State Tree 状态节点中添加 Transition并创建 Compare Bool 条件。把条件中的 Input 来源绑定到角色蓝图上下文。设置目标状态。4.6 输入事件如何驱动状态转换很多新手会问State Tree 中怎么监听按键事件答案State Tree 不直接监听输入事件。输入事件在角色蓝图中被捕获然后修改对应的布尔变量或者调用状态树组件的“Send Event”发送事件节点。具体做法在 BP_FPSCharacter 的输入绑定中鼠标左键按下把 bIsFiring 设为 true同时调用 State Tree 组件的“Send Event”方法发送事件名 “FireTrigger”。鼠标右键按下把 bIsAiming 设为 true发送事件 “AimTrigger”。R 键按下把 bIsReloading 设为 true发送事件 “ReloadTrigger”。然后在 State Tree 编辑器中某些状态的转换条件可以基于“事件Event”触发而不是只基于布尔变量。使用事件触发的优势是状态树能够立即响应按键操作而不需要每帧循环判断变量是否变化。对于 FPS 射击游戏响应速度很关键所以推荐使用 Send Event 触发转换。一个最小示例流程如下鼠标左键按下 → 角色蓝图事件输入 → 设置 bIsFiring true → State Tree 组件 Send EventEventTag FireTrigger → State Tree 中 Aim 状态的转换条件判断 FireTrigger 已触发 → 切换到 Fire 状态这样开火状态转换响应迅速且逻辑结构清晰。4.7 完整的核心蓝图逻辑参考由于纯蓝图项目的节点较多这里给出关键蓝图的文字逻辑描述方便你对照自己的工程实现。角色蓝图事件图表核心逻辑Event BeginPlay - Get StateTree Component - Start State Tree Event InputAction Fire (鼠标左键) - Set bIsFiring true - Get StateTree Component - Send State Tree EventTagFireTrigger Event InputAction StopFire (鼠标左键松开) - Set bIsFiring false - 发送事件TagStopFireTrigger Event InputAction Aim (鼠标右键按下) - Set bIsAiming true - 发送事件TagAimTrigger Event InputAction StopAim (鼠标右键松开) - Set bIsAiming false - 发送事件TagStopAimTrigger Event InputAction Reload (R键按下) - Set bIsReloading true - 发送事件TagReloadTriggerFire 状态节点绑定逻辑Receive Enter - Get Context Actor - Cast to BP_FPSCharacter - Call PlayFireAnimation - Call SpawnMuzzleFlashEffect - Call WeaponLineTraceDamage Receive Tick - 可每帧检测是否继续导致伤害或处理后坐力 Receive Exit - Get Context Actor - Cast to BP_FPSCharacter - Call StopFireAnimation - Call ResetWeaponSpread瞄准与移动的嵌套逻辑Aim 状态节点内部继续嵌套 Movement 状态 Movement 状态内部可以继续使用 Walk/Run 子状态 Aim 状态节点不阻断移动 但 Movement 状态中的 Run 节点转换条件要求 bIsAiming 为 false在纯蓝图实践中为了让状态树能访问角色蓝图中的自定义事件一般将 State Tree 组件的“Context Actor”设置为 Self。StateTreeTaskBlueprintBase 中可以使用“Get Connected Actor”节点来获取上下文 Actor。5. 常见问题与排查思路在学习和使用 UE5 State Tree 的过程中会遇到一些典型问题。下面整理了一份排查表。问题现象常见原因解决思路State Tree 资产无法创建State Tree 插件未启用到插件面板勾选 State Tree 并重启编辑器角色运行后没有任何状态行为角色蓝图未调用 Start State Tree在 BeginPlay 中调用 Start State Tree并确保组件存在状态转换不生效条件绑定错误或变量未更新检查 Compare Bool 条件中的输入源是否指向角色蓝图检查变量是否在正确的时机更新输入事件触发后状态不切换未发送 State Tree Event或者事件标签不一致检查 Send State Tree Event 的事件标签与 State Tree 中 Transition 的 Event 标签必须完全一致开火逻辑重复执行Fire 状态进入多次或者未设置状态切换检查 Fire 状态是否在 Tick 中重复调用开火事件建议把开火逻辑放在 Enter 中Tick 只做后坐力等更新状态树执行但不播放动画动画蓝图没有根据变量播放对应动画状态树只负责逻辑动画播放需要在动画蓝图中检测角色变量切换动画状态编译错误StateTreeTaskBlueprintBase 找不到插件未正确启用重启编辑器或者检查项目类型是否支持该插件嵌套状态内转换混乱优先级配置不当检查各转换条件的优先级顺序最高优先级应该放在列表最上方5.1 状态转换不生效的快速排查清单如果你遇到“状态树启动了条件也对但状态就是不切换”可以按以下顺序排查确认 State Tree 插件已经启用并重启编辑器。确认 State Tree 组件已添加到角色蓝图。确认 BeginPlay 中已调用 Start State Tree。在角色蓝图中随便打印一条日志看看输入事件是否被触发。在状态转换条件中暂时使用常量 Compare Bool看是否能切换。检查 Compare Bool 的条件来源是否正确获取角色上下文。检查是否同时存在多条转换规则高优先级规则阻断了预期转换。检查 State Tree 状态节点是否已经绑定对应 Task。确认事件的标签 Tag 是否完全一致注意大小写。输出 State Tree 调试信息查看当前执行到哪个节点。5.2 如何调试多状态树UE5 的 State Tree 编辑器提供了调试面板。在 PIEPlay In Editor模式下打开 State Tree 资产可以看到当前激活的节点高亮显示。这是排查状态切换最直观的方法。如果你的 State Tree Task 没有挂载到节点上图标不会高亮。可以把状态节点的 Tick 都开启并打印日志这样可以跟踪每个状态的 Enter / Tick / Exit 调用顺序。另外可以在角色蓝图中创建公开变量“CurrentStateName”在 Task 的 Receive Enter 中赋值方便运行时在“调试Debug”面板中查看当前状态。这个方法虽然原始但非常有效。6. 最佳实践与工程建议6.1 状态树命名规范在纯蓝图项目中随着状态树规模变大命名不规范会很快让项目失控。建议遵守以下规范State Tree 资产命名为 ST_ 前缀例如 ST_FPSCharacter、ST_EnemyAI。状态节点用“动词 名词”格式例如 Aim瞄准、Fire开火、Reload换弹、CrouchWalk蹲伏行走。每个状态节点对应的 Task 蓝图命名为 BP_Task_ 前缀例如 BP_Task_Fire。条件蓝图命名为 BP_ Cond_ 前缀例如 BP_Cond_IsAiming。事件标签Event Tag使用类似 GameplayTag 的格式ST.Fire.Trigger、ST.Aim.On、ST.Reload.Start。6.2 状态逻辑与动画逻辑分离初学者最常犯的错误是把动画播放也写进状态树的 Task 里。虽然这样也能运行但会破坏职责边界。推荐做法State Tree 只管理“逻辑状态”例如是否允许开火、武器是否可切换、移动速度是多少。动画蓝图AnimBlueprint根据逻辑状态变量播放对应动画。State Tree 中只需要在 Enter / Exit 里修改角色蓝图中的动画状态变量例如“bIsFiring”、“bIsAiming”。动画蓝图通过获取角色引用读取这些变量进行动画状态机切换。这样做的好处是动画系统可以独立预览和调整不影响游戏逻辑。后期如果想让 AI 敌人也复用这套行为只需要把状态树挂到 AI 控制器上。6.3 优先级设计原则在 FPS 状态树中状态优先级建议从高到低避免低优先级状态抢占高优先级转换死亡状态优先级最高任何情况只要 HP 0立即切入。换弹状态次高因为换弹过程中通常禁用开火但要允许移动。瞄准与开火状态优先级取决于设计需求。推荐开火状态下瞄准为真所以切换顺序为Aim - Fire。移动状态优先级最低任何战斗行为都可以打断移动但移动不应该打断战斗。在 State Tree 的 Transitions 列表中越靠上的规则优先级越高。你可以通过在同一个状态节点中配置多条 Transition 来实现优先级控制。6.4 输入与事件处理建议纯蓝图项目中输入驱动事件建议集中管理编写一个“InputManager”蓝图函数库负责把输入转换为布尔状态和事件发送。所有按键事件不要分散在多个角色蓝图中后期维护会很痛苦。State Tree 的 Send Event 调用统一封装成角色蓝图中的自定义事件例如 SendStateTreeEventByName。如果要做移动端 FPS比如双指触摸开火、虚拟摇杆移动可以在移动端输入组件中把触摸事件映射到同一个变量和事件系统这样状态树无需改动。6.5 性能与网络注意事项纯蓝图 State Tree 的性能通常足够支撑单人 FPS 项目。但如果要做多人联机需要注意State Tree 的执行逻辑应尽量放在服务器端客户端只做表现同步。不要在每个客户端上各自驱动完整状态树这样会导致状态不一致。如果使用 State Tree 管理武器开火建议开火判定放在服务器客户端表现通过 RPC 同步。移动端项目要避免在 Tick 中做大量查询和广播建议把高频逻辑放在 Task 的 Tick 中但每帧只做轻量计算。这里特别说明一下本文涉及的单机状态树逻辑在多人在线 FPS 项目中通常还需要结合 Gameplay Ability System 或自定义网络同步方案。后续文章可以单独展开本文先聚焦纯蓝图单机状态转换。6.6 状态树的扩展方向当你熟悉了多状态树嵌套后可以在项目中继续扩展给 AI 敌人添加状态树让 AI 具备巡逻、警戒、追击、攻击等行为。把状态树和 GameplayTag 结合用 Tag 驱动动画播放和事件响应。给武器系统建立独立状态树管理“单发 / 连发 / 换弹 / 空仓挂机”等武器状态。把状态树用于镜头切换在“正常视角 / 瞄准视角 / 死亡视角 / 观战视角”之间平滑切换。State Tree 的优势在于它不绑定具体的角色或 AI任何 Actor 都可以挂载 State Tree 组件。FPS 角色、敌人、载具甚至 UI 逻辑都可以用同一套状态管理思路。7. 总结与下一步学习方向本篇文章从 UE5 纯蓝图 FPS 游戏开发角度详细讲解了多状态树嵌套实现状态转换的方法。重点内容包括State Tree 插件如何启用、如何创建状态树资产、如何在角色蓝图中添加 State Tree 组件、如何绑定任务类、如何配置 Transitions 完成状态切换以及常见错误的排查思路。学习到这里你已经初步掌握了State Tree 和传统枚举状态机之间的设计差异。嵌套状态如何表达 FPS 中“移动 瞄准 开火 换弹”的组合行为。Enter、Tick、Exit 三个时机分别在什么场景使用。通过 Send Event 和条件判定触发状态转换的方法。状态优先级在树结构中的配置思路。下一步可以继续学习以下方向结合动画蓝图为每个状态匹配更真实的 FPS 动画表现。尝试用 State Tree 管理敌人 AI比较它和 Behavior Tree行为树的适用场景。在武器系统中引入独立的 State Tree实现更细的武器状态机。深入学习 Event Tag 的使用构建更复杂的转换触发机制。在动手时建议先在测试地图中构造一个最小的“瞄准 - 开火 - 换弹”链条跑通后再扩展其他状态。多状态树的“嵌套”并不难理解难的是在开发中始终保持状态边界清晰。你可以试着为每个状态写一个简单的注释标注“进入条件、执行内容、退出条件”这样即使项目变大也能快速定位问题。如果本文对你有帮助收藏备用下一篇可以继续讨论 FPS 状态树与动画蓝图联动、武器系统状态管理或者多人网络同步的相关内容。