跳到主要内容
Moyor的炼药小锅
返回手记

UE5 Enhanced Input 速记

2026年8月15日 #UE5#输入
目录

Enhanced Input 取代了旧的输入绑定。用了几年之后,把这些早该记下来的笔记补上。

增强输入系统(Enhanced Input)的核心在于将物理按键(Raw Input)与抽象意图(Input Action)彻底解耦,并通过管道化的数据流处理输入逻辑。

1. Modifier 会叠加,顺序很重要

Modifier 本质上是一个线性处理管道(Pipelined Vector Processing),输入数据会从上到下逐个通过 Modifier 函数。

推荐的标准 Modifier 链顺序

为了避免出现斜向移动手感失真或死区失效的问题,建议遵循以下排链法则:

  1. Swizzle YXZ:轴转换(如将 1D 按键输入映射到 Vector2D 的 Y 轴)。

  2. Negate:反转数值(正负号调整)。

  3. Dead Zone:死区过滤(过滤物理摇杆/按键机械抖动)。

  4. 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。顺序颠倒会导致按键的方向映射错乱。

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++ 绑定踩坑总结

  1. 模块依赖:在 .Build.cs 中必须添加 "EnhancedInput" 模块,并包含头文件:

    C++

    #include "EnhancedInputComponent.h"
    #include "EnhancedInputSubsystems.h"
    
  2. 安全的组件转型:

    C++

    if (UEnhancedInputComponent* PEI = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
    {
       PEI->BindAction(IA_Move, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
    }
    
  3. 回调函数签名选择:

    • 仅获取当前轴/按键值: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)”等游戏特定的复杂触发条件。