增强输入
Enhanced Input
增强输入 (Enhanced Input) 是 UE5 默认启用的输入插件,把输入拆成四层:输入动作 (Input Action) 表示“玩家想做什么”,输入映射上下文 (Input Mapping Context) 规定“哪些按键在什么情境下触发它”,输入修饰器 (Input Modifier) 预处理原始值,输入触发器 (Input Trigger) 判定是否触发。上下文可在运行时按优先级增删,从而用数据资产而非代码处理情境切换、按键冲突与改键。
四个核心概念的数据流
下图是一次按键从硬件到游戏代码的路径:原始值先经过映射上下文中该按键的修饰器链,再由触发器判定状态,最后以触发事件回调绑定在 Input Action 上的函数。
flowchart LR
K["原始输入:按键/摇杆"] --> IMC{"映射上下文<br/>按优先级选中"}
IMC --> M1[Modifier 1] --> M2[Modifier N]
M2 --> T["Trigger 判定<br/>None/Ongoing/Triggered"]
T --> IA["Input Action 值<br/>bool/1D/2D/3D"]
IA --> CB["绑定回调<br/>Started/Ongoing/Triggered/Completed/Canceled"]输入动作 (Input Action)
Input Action 是增强输入与项目代码之间的“通信链接”,概念上等同旧系统的 Action/Axis 映射名,但它是数据资产。每个 Action 应代表玩家能做的一件事(“蹲下”“开火”)。值类型决定行为:
| 值类型 | C++ 类型 | 典型用途 |
|---|---|---|
| Digital (bool) | bool | 开/关类动作(等价旧 Action 映射),如“拾取” |
| Axis1D | float | 单轴,如油门 |
| Axis2D | FVector2D | 摇杆、行走方向 |
| Axis3D | FVector | 运动控制器等复杂数据 |
触发事件有 Started、Ongoing、Triggered、Completed、Canceled 五种。例如“按住”触发器在未达时长时持续 Ongoing,提前松手则 Canceled;最常用的是 Triggered。C++ 中在 SetupPlayerInputComponent 里把 UInputComponent 转成 UEnhancedInputComponent,调用 BindAction(Action, ETriggerEvent::Triggered, this, &AFoo::Func),回调中用 Instance.GetValue().Get<FVector2D>() 等取值。输入组件挂在 Pawn/PlayerController 上的分工见 Gameplay 框架。(Enhanced Input)
输入映射上下文 (Input Mapping Context)
上下文是某个情境下可用的一组 Action 及其触发规则,层级为“Action → 可触发它的按键 → 每个按键的触发器与修饰器”。通过本地玩家的 Enhanced Input Local Player Subsystem 添加/移除,并带优先级:多个上下文映射到同一 Action 时只考虑优先级最高的那个。(Enhanced Input)
官方给出的典型用法(Enhanced Input):
- 情境切换:步行时 Ctrl 是蹲下,冲刺时 Ctrl 是滑铲,趴下时 Ctrl 是起身——各用一个上下文,切换状态时换上下文。
- 载具:通用动作放一个常驻上下文,载具动作单独一个,上车添加、下车移除。这样不合适的 Action 根本不会执行,互斥的上下文能避免输入冲突。
- 官方示例以
TSoftObjectPtr<UInputMappingContext>暴露上下文,再AddMappingContext(InputMapping.LoadSynchronous(), Priority);软引用与同步加载的取舍见 资产管理与异步加载。
玩家可映射输入配置 (Player Mappable Input Config) 是一组上下文的预设(如“默认”与“左撇子 Southpaw”),可一次性添加,并带有便于制作改键 UI 的元数据。(Enhanced Input)
输入修饰器 (Input Modifier)
修饰器是触发器之前的预处理器:调整轴顺序、死区 (Dead Zone)、转换到世界空间、灵敏度、多帧平滑等。自定义时继承 UInputModifier 并重写 ModifyRaw_Implementation(蓝图同理),返回值传给下一个修饰器或第一个触发器;因为能拿到 UPlayerInput,可以读取所属 PlayerController 和任意游戏状态。Lyra 用一个修饰器根据设置反转瞄准轴。(Enhanced Input)
经典例子是把四个一维按键(WASD)合成一个 2D 移动 Action:每个键只报告 X 轴上的 0 或 1,用 Negate 取负、用 Swizzle 把 X 换到 Y:
| 按键 | 期望解释 | 需要的修饰器 |
|---|---|---|
| W / ↑ | +Y | Swizzle (YXZ 或 ZXY) |
| A / ← | −X | Negate |
| S / ↓ | −Y | Negate + Swizzle |
| D / → | +X | 无 |
输入触发器 (Input Trigger)
触发器判定经修饰后的输入是否激活 Action:最小驱动量、短按、长按、按下/松开等;“组合键 (Chorded Action)”触发器例外,它依赖另一个 Action。默认(无触发器)时任何输入每帧都会触发。触发器分三类,组合规则如下(Enhanced Input):
| 情况 | 结果 |
|---|---|
| 无隐式、无显式 | 只要值非 0 就触发 |
| 仅显式 (Explicit) | 至少一个显式成功 |
| 仅隐式 (Implicit) | 全部隐式成功 |
| 隐式 + 显式 | 全部隐式且至少一个显式成功 |
| 阻断 (Blocker) 成功 | 强制失败,覆盖一切 |
单个触发器返回 None / Ongoing / Triggered。自定义可继承 UInputTrigger 或 UInputTriggerTimedBase(后者自身从不返回 Triggered,要在子类中决定);引擎的 UInputTriggerHold 以 HoldTimeThreshold(默认 1 秒)和 bIsOneShot 控制长按触发一次还是每帧触发。(Enhanced Input)
调试、注入与平台差异
showdebug enhancedinput显示当前映射,showdebug devices显示设备。(Enhanced Input)- 输入注入:控制台
Input.+key Gamepad_Left2D X=0.7 Y=0.5/Input.-key ...,或 C++InjectInputForAction,可用于自动化测试和调试。(Enhanced Input) - 平台设置:继承
UEnhancedInputPlatformData做按平台的上下文重定向(如 Switch 面键位置、移动端动作),写入平台DefaultInput.ini,可热修复。(Enhanced Input)
取舍与常见坑
| 要点 | 说明 |
|---|---|
| Action 表达意图而非按键 | 代码只认 Action,改键与多平台都只动数据 |
| 用上下文而不是 if 判断状态 | 不合适的动作不会触发,减少 bug |
| 优先级冲突 | 同一 Action 在多个上下文中时只取最高优先级,叠加上下文时要规划好优先级 |
| 无触发器 = 每帧触发 | 想要“按下一次”的语义需加 Pressed 等触发器 |
| 输入与网络 | 绑定到输入的可靠 RPC 可能被狂按撑爆队列,见 网络复制与 RPC |
在使用 GAS 的项目里,输入通常只负责发出“激活能力”的请求,具体条件和互斥交给能力标签处理,见 Gameplay 能力系统;在蓝图还是 C++ 中绑定的分工见 蓝图与 C++ 协作。
出处
- Enhanced Input UE 5.8 文档