UE5.8 Enhanced Input 专题系列

UE5.8 Enhanced Input 专题(二):Input Action 的值类型和事件

讲清 Boolean、Axis1D、Axis2D、Axis3D、FInputActionValue、FInputActionInstance,以及 Started、Ongoing、Triggered、Completed、Canceled 什么时候触发。

总览

UInputAction 最容易被误解的地方是:它不是“按键按下”的事件,而是一个带值、带触发规则、带运行时状态的动作。IA_Move 是二维向量,IA_Jump 是布尔,IA_Zoom 可以是一维轴,IA_AimDirection 甚至可以是三维向量。

UE5.8 Enhanced Input 专题(二):Input Action 的值类型和事件 配图
Input Action 先确定值类型,再由 Trigger 状态转换成事件。

值类型怎么选

Value Type 常见用途 C++ 读取
Boolean 跳跃、交互、开火、确认 Value.Get<bool>()
Axis1D 油门、刹车、缩放、扳机 Value.Get<float>()
Axis2D 移动、视角、菜单导航 Value.Get<FVector2D>()
Axis3D VR/飞行/调试自由移动 Value.Get<FVector>()

不要为了省事把所有 Action 都设成 Boolean。只要你需要方向、强度、模拟量、鼠标 delta,就应该用 Axis。

事件怎么理解

ETriggerEvent 不是简单的 Pressed/Released。源码里把事件定义成 Trigger State 的转换:

Event 大白话 常见用法
Started 输入开始被评估 起手音效、蓄力开始
Ongoing 正在等待触发条件 Hold 未达时长的进度条
Triggered 条件满足 移动每帧、开火、蓄力成功
Completed 从 Triggered 回到 None 松开跳跃、松开移动
Canceled Started/Ongoing 但没成功 Hold 不够时间就松手

没有 Trigger 时,Enhanced Input 使用类似 Down 的默认行为:输入超过阈值就 Triggered,松开后 Completed。

Value 和 Instance

简单动作绑定 FInputActionValue 足够:

void AMyCharacter::Move(const FInputActionValue& Value)
{
    const FVector2D Axis = Value.Get<FVector2D>();
    AddMovementInput(GetActorForwardVector(), Axis.Y);
    AddMovementInput(GetActorRightVector(), Axis.X);
}

如果你需要触发时长、当前事件、源 Action,就绑定 FInputActionInstance

void AMyCharacter::ChargeAttack(const FInputActionInstance& Instance)
{
    const float HeldSeconds = Instance.GetElapsedTime();
    const ETriggerEvent Event = Instance.GetTriggerEvent();
    const float ChargeAlpha = FMath::Clamp(HeldSeconds / 1.2f, 0.0f, 1.0f);

    UpdateChargeUI(ChargeAlpha, Event);
}

源码里 FInputActionInstance::GetValue() 还有一个重要约束:如果当前事件不是 Triggered,当前值可能会是该类型的零值。进度条更适合看 ElapsedTime 或 Trigger 自己的状态,而不是只看 Value。

使用案例:跳跃

跳跃不要绑 Triggered,因为按住空格时它可能每帧触发。更稳定的写法是:

EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);

这样“按下开始跳,松开停止跳跃延长”符合 Character 的预期。

使用案例:蓄力攻击

蓄力攻击可以给 Action 加 Hold Trigger。Started 打开 UI,Ongoing 更新进度,Triggered 发出蓄满攻击,Canceled 取消或释放普通攻击。

EIC->BindAction(ChargeAction, ETriggerEvent::Started, this, &AMyCharacter::BeginCharge);
EIC->BindAction(ChargeAction, ETriggerEvent::Ongoing, this, &AMyCharacter::UpdateCharge);
EIC->BindAction(ChargeAction, ETriggerEvent::Triggered, this, &AMyCharacter::CommitChargedAttack);
EIC->BindAction(ChargeAction, ETriggerEvent::Canceled, this, &AMyCharacter::CancelCharge);

Accumulation 行为

UInputActionAccumulationBehavior。默认 TakeHighestAbsoluteValue 会取绝对值最大的输入来源;Cumulative 会累加输入,适合 WASD 这种 W 和 S 同时按下应该互相抵消的动作。移动 Action 如果出现“W+S 仍然向前”,先看这里。

常见坑

  • Jump 用 Triggered,导致按住空格每帧调用 Jump。
  • Hold 只绑 Triggered,没有处理 Canceled,UI 卡住。
  • Axis2D Action 只绑定 Mouse X,忘了 Mouse Y,结果 Look 只有横向。
  • 同一个 Action 既给键鼠又给手柄轴,没处理灵敏度和死区差异。
  • Completed 当释放事件用在所有 Trigger 上,但某些 Trigger 的 Completed 语义和直觉不同。

源码依据

InputActionValue.h 封装 Boolean、Axis1D、Axis2D、Axis3D。InputTriggers.h 定义 ETriggerStateETriggerEvent,并注明 CompletedCanceled 的状态转换。FInputActionInstance 保存 TriggerEvent、Value、ElapsedTime、TriggeredTime、SourceAction、Triggers 和 Modifiers。

源码路径索引

  • EnhancedInput/Public/InputAction.h
  • EnhancedInput/Public/InputActionValue.h
  • EnhancedInput/Public/InputTriggers.h
  • EnhancedInput/Public/EnhancedPlayerInput.h