总览
输入系统上线后最怕“只有玩家知道它坏了”。你需要能回答:当前 Local Player 装了哪些 Mapping Context?哪个 Action 正在 Triggered?玩家改键保存到哪个 Profile?这个键为什么被另一个 Context 吃掉?多人时谁拥有这次输入?
网络边界
Enhanced Input 是本地输入系统。客户端按键只说明玩家意图,不能当服务器事实。多人游戏里常见流程是:客户端本地响应输入,发 Server RPC 或激活 Ability,服务器验证距离、冷却、状态、资源和目标合法性。
不要把“客户端说我按下攻击”当作伤害依据。输入只发起行为,行为是否成立由服务器 gameplay 系统判断。
本地多人
UEnhancedInputLocalPlayerSubsystem 是每个 Local Player 一份。分屏项目不能把所有 Context 和 User Settings 都挂到 Player 0。每个玩家的 Controller、LocalPlayer、Subsystem、UserSettings、Profile 都应该独立。
调试时用屏幕打印 LocalPlayer Index、Active Profile、Applied Context 列表。很多“P2 控制不了角色”的问题,实际是 Context 加到了 P1 的 Subsystem 上。
输入注入
Subsystem 和 PlayerInput 支持输入注入:
Subsystem->InjectInputForAction(MoveAction, FInputActionValue(FVector2D(0.0f, 1.0f)), {}, {});
Subsystem->StartContinuousInputInjectionForAction(MoveAction, FInputActionValue(FVector2D(0.0f, 1.0f)), {}, {});
Subsystem->StopContinuousInputInjectionForAction(MoveAction);
这适合自动化测试、Replay 工具、AI 接管玩家、教学引导。不要把它当作弊入口暴露给普通客户端。
调试命令
UE5.8 EnhancedInput 的 Config/Input.ini 注册了自动补全命令:
ShowDebug EnhancedInput
ShowDebug WorldSubsystemInput
ShowDebug InputSettings
ShowDebug EnhancedInput 看当前 Mapping Context、Action、Trigger、Modifier。ShowDebug InputSettings 看玩家可改键和 User Settings。WorldSubsystemInput 用于实验性 World Subsystem。
UE5.8 源码里还带 Experimental PlayerInputDebugger 插件,依赖 EnhancedInput,可以作为编辑器调试窗口辅助观察输入。
自动化测试思路
Enhanced Input 自己的测试给了很好的模板:InputBindingTest.cpp 验证按键触发、模拟轴值、多键同 Action、输入组件栈优先级和消费;InputPlayerMappableKeysTests.cpp 验证注册 IMC、MapPlayerKey、UnMap、Reset、Multiple Profiles。
项目里可以做三类回归:
- 角色基础输入:Move/Look/Jump/Interact。
- 改键流程:保存、读取、重置、冲突提示。
- Context 切换:菜单、载具、死亡、过场、分屏。
生产命名规范
建议统一:
- Input Action:
IA_Move、IA_Look、IA_Interact。 - Mapping Context:
IMC_Default、IMC_Menu、IMC_Vehicle。 - MappingName:
Input.Move.Forward、Input.Combat.Fire。 - GameplayTag Input Mode:
Input.Mode.Gameplay、Input.Mode.Menu。 - UI Action:
IA_UIConfirm、IA_UICancel、IA_UINavigate。
命名要同时服务代码、设置页和玩家显示。IA_E 这种名字上线后很快会变成债。
性能和重建
Add/Remove Context 会请求重建 Control Mappings。不要每帧 Add/Remove。一次状态切换里如果要加多个 Context,避免每个都 bForceImmediately=true。Modifier 和 Trigger 也别滥用 bShouldAlwaysTick,源码注释明确说这会影响性能,只适合特定自定义 Trigger。
上线检查清单
- 所有 gameplay 输入都有 IA 语义名,不用物理按键命名。
- Context 分层清楚,UI 和 Gameplay 不互相漏输入。
- 可改键 Action 都有唯一 Player Mappable MappingName。
- 改键前做 Query 冲突检测。
- User Settings 能保存、读取、重置、Profile 切换。
- 手柄 Move/Look 有死区和单独灵敏度。
- 暂停下只有 UI Action 触发。
- 本地多人每个 Local Player 独立 Subsystem 和 Profile。
- 服务器验证输入发起的 gameplay 行为。
- 开发包里知道怎么使用 ShowDebug EnhancedInput 和 InputSettings。
常见坑
- Context 生命周期不成对,加了不移除。
- 改键界面只在单人测过,分屏 P2 改了 P1 的键。
- 自动化测试只测默认键位,没有测玩家改键。
- Debug 命令不知道,问题全靠猜。
- 把输入层和能力/状态机/角色状态写死耦合,后续菜单、载具、过场越改越乱。
源码依据
EnhancedInput/Config/Input.ini 注册 ShowDebug 命令。IEnhancedInputSubsystemInterface 提供输入注入和连续注入 API。UEnhancedPlayerInput 保存 ActionInstanceData、AppliedInputContextData、EnhancedActionMappings 和 CurrentInputMode。PlayerInputDebugger.uplugin 位于 Experimental 插件并依赖 EnhancedInput。InputEditor 的自动化测试覆盖绑定、输入栈、可改键和多 Profile。
源码路径索引
EnhancedInput/Config/Input.iniEnhancedInput/Public/EnhancedInputSubsystems.hEnhancedInput/Public/EnhancedPlayerInput.hEnhancedInput/Public/EnhancedInputLibrary.hExperimental/PlayerInputDebugger/PlayerInputDebugger.upluginEnhancedInput/Source/InputEditor/Private/Tests/InputBindingTest.cppEnhancedInput/Source/InputEditor/Private/Tests/InputPlayerMappableKeysTests.cpp