UE5 Enhanced Input 速记
目录
Enhanced Input 取代了旧的输入绑定。用了几年之后,把这些早该记下来的笔记补上。
增强输入系统(Enhanced Input)的核心在于将物理按键(Raw Input)与抽象意图(Input Action)彻底解耦,并通过管道化的数据流处理输入逻辑。
1. Modifier 会叠加,顺序很重要
Modifier 本质上是一个线性处理管道(Pipelined Vector Processing),输入数据会从上到下逐个通过 Modifier 函数。
推荐的标准 Modifier 链顺序
为了避免出现斜向移动手感失真或死区失效的问题,建议遵循以下排链法则:
-
Swizzle YXZ:轴转换(如将 1D 按键输入映射到 Vector2D 的 Y 轴)。
-
Negate:反转数值(正负号调整)。
-
Dead Zone:死区过滤(过滤物理摇杆/按键机械抖动)。
-
Scale / FOV Scaling:数值缩放或灵敏度系数。
关键踩坑点:
-
Dead Zone 与 Scale 的位置:
-
先 Scale 后 Dead Zone(错误):若输入原始值为
0.15,经过Scale(2.0)后变为0.3。如果死区设为0.2,原本应该被过滤的微小抖动反而越过了死区门槛。 -
先 Dead Zone 后 Scale(正确):死区只对“物理设备发出的原始归一化输入(0~1)”做线性/径向截断,过滤干净后再乘以灵敏度或缩放系数。
-
-
Swizzle 与 Negate 的顺序:
- WASD 映射到 2D 向量时:
S键通过Negate翻转 Y 轴;A键需要先Swizzle YXZ(把 X 轴输入放到 Y 轴)再Negate。顺序颠倒会导致按键的方向映射错乱。
- WASD 映射到 2D 向量时:
2. 一个动作,多个触发器(Trigger 生命周期的妙用)
同一个 InputAction 可以配置多个 Trigger(Pressed、Hold、Pulse 等),在运行时通过状态机模型分发回调。
Trigger Event 事件生命周期
Plaintext
[按下按键] ──> Started ──> Ongoing (持续按住/蓄力) ──> Triggered (条件满足) ──> Completed (松开)
└── (中途松开) ──> Canceled
| 事件状态 (ETriggerEvent) | 触发时机 | 典型应用场景 |
|---|---|---|
Started | 按键刚按下/开始检测 | 播放起跳前摇音效、开启蓄力 UI |
Ongoing | 处于检测评估中(每帧调用) | 更新蓄力进度条、计算按压时长 |
Triggered | 条件完全满足(每帧或一次) | 触发攻击、持续移动输入、蓄力满释放 |
Completed | 触发达成后松开按键 | 投掷物释放、轻按(Tap)松手动作 |
Canceled | 未达到触发条件中途打断 | 蓄力未满被打断/主动取消 |
代码/蓝图设计范式
无需为“开始蓄力”、“蓄力中”、“释放蓄力”创建 3 个不同的 Input Action,仅需一个 IA_ChargeAttack,在 C++ / 蓝图回调中区分 GetTriggerEvent() 即可:
C++
void AMyCharacter::OnChargeAttack(const FInputActionInstance& ActionInstance)
{
switch (ActionInstance.GetTriggerEvent())
{
case ETriggerEvent::Started:
// 1. 播放蓄力音效 / 开启特效
break;
case ETriggerEvent::Ongoing:
// 2. 更新蓄力进度:ActionInstance.GetElapsedTime()
break;
case ETriggerEvent::Triggered:
// 3. 蓄力满,释放强力攻击
break;
case ETriggerEvent::Canceled:
// 4. 中途被打断,重置 UI 与状态
break;
}
}
3. IMC 的动态注入与优先级 (Input Mapping Context)
利用 UEnhancedInputLocalPlayerSubsystem 实现多上下文的动态叠加,是 Enhanced Input 相比旧版最强的大杀器。
优先级叠加法则
-
高优先级覆盖:当叠加多个 IMC 时,高 Priority 的 Context 会优先处理按键映射。
-
Consume Inputs (阻断输入):在 IMC 或 IA 中勾选
Consume Inputs后,若高优先级的 Context 响应了某个按键(如 UI 菜单中的E键),该按键事件将不会继续下发给低优先级的 Context(如场景互动的E键)。
典型场景优先级设计架构:
Plaintext
[Priority 10] IMC_UI / IMC_Menu (开启 Consume Inputs,阻断角色控制)
▲
[Priority 2] IMC_Aiming / IMC_Vehicle (覆写特定动作,如右键瞄准/驾车视角)
▲
[Priority 0] IMC_Default (基础移动、跳跃、视角旋转)
4. C++ 绑定踩坑总结
-
模块依赖:在
.Build.cs中必须添加"EnhancedInput"模块,并包含头文件:C++
#include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" -
安全的组件转型:
C++
if (UEnhancedInputComponent* PEI = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) { PEI->BindAction(IA_Move, ETriggerEvent::Triggered, this, &AMyCharacter::Move); } -
回调函数签名选择:
-
仅获取当前轴/按键值:
void Move(const FInputActionValue& Value); -
获取完整元数据(包含 TriggerEvent、按压时长等):
void Move(const FInputActionInstance& ActionInstance);
-
5. 进阶拓展:自定义 Modifiers & Triggers
-
自定义 Modifier:继承
UInputModifier,重写ModifyRaw_Implementation。适合实现“根据玩家视角仰角动态缩放 Pitch 灵敏度”或“开镜后的非线性曲线平滑”。 -
自定义 Trigger:继承
UInputTrigger,重写UpdateState_Implementation。适合实现“双击(Double Tap)”、“组合键(Chord Key)”等游戏特定的复杂触发条件。