You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE5.1 Enhanced Input System:如何实现角色移动的按键抵消逻辑?

UE5.1.1 Enhanced Input 实现方向键抵消效果

我在UE5.1.1的第一人称射击项目中使用Enhanced Input系统,发现与旧输入系统不同:按住W和S这类相反方向键时,二者不会相互抵消,而是Input Mapping Context中最后列出的按键优先生效——比如同时按W和S时角色会向后移动。

我需要实现同一Input Action的多按键按下时互相抵消的效果(例如同时按四个方向键返回(0, 0))。尝试在Move回调中累加输入值,但回调仅针对最后列出的按键触发一次,无法实现抵消。奇怪的是返回的FVector2D同时包含X轴(W&S)和Y轴(A&D)的轴向值,说明多按键已被处理,但同一轴上的后按键会覆盖之前的值。

相关代码如下:

// Called every frame
void AShooterCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    // Handle movement:
    
    // Prevent speed increase on diagonals
    CurrentMovementInput = CurrentMovementInput.GetSafeNormal();
    
    // Forward movement (X)
    AddMovementInput(GetActorForwardVector() * CurrentMovementInput.X);
    // Strafing movement (Y)
    AddMovementInput(GetActorRightVector() * CurrentMovementInput.Y);

    // Reset current movement input ready for next frame
    CurrentMovementInput = FVector2d::ZeroVector;
}

// Called to bind functionality to input
void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up input mapping context
    if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(GetLocalViewingPlayerController()->GetLocalPlayer()))
    {
        if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
        {
            if (!ShooterInputMappingContext.IsNull())
            {
                InputSystem->AddMappingContext(ShooterInputMappingContext.LoadSynchronous(), 1);
            }
        }
    }

    // Action bindings
    UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PlayerInputComponent);

    Input->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AShooterCharacter::MoveCallback);
    Input->BindAction(LookAction, ETriggerEvent::Triggered, this, &AShooterCharacter::LookCallback);
}

void AShooterCharacter::MoveCallback(const FInputActionInstance& Instance)
{
    FVector2D AxisValues = Instance.GetValue().Get<FVector2D>();

    // Add onto current movement input so that opposite inputs cancel each other?
    CurrentMovementInput += AxisValues;
}

解决方法

方法1:修改Input Action的轴行为(最简单)

Enhanced Input默认采用覆盖式计算轴值,只需修改输入动作的设置即可实现累加抵消:

  1. 打开你的MoveAction资源
  2. 在Axis Settings面板中,将Axis Behavior从Value改为Sum
  3. 此时同一轴的多个输入会自动累加(如W的+1和S的-1相加为0),直接使用原代码即可生效

方法2:修复回调绑定与逻辑

原代码使用ETriggerEvent::Triggered,该事件仅在输入状态变化时触发一次,无法捕获完整的多按键状态。改为绑定Updated事件,并配合Sum轴行为:

  1. 按方法1修改MoveAction的Axis Behavior为Sum
  2. 修改绑定事件类型:
Input->BindAction(MoveAction, ETriggerEvent::Updated, this, &AShooterCharacter::MoveCallback);
  1. 简化MoveCallback逻辑(因为UE已自动累加抵消):
void AShooterCharacter::MoveCallback(const FInputActionInstance& Instance)
{
    CurrentMovementInput = Instance.GetValue().Get<FVector2D>();
}

Tick函数保持不变,即可实现方向键抵消效果。

方法3:手动检测按键状态(自定义性更强)

若需要更精细的控制,可直接绑定单个按键的按下/释放事件,手动计算输入值:

  1. 在角色类头文件添加状态变量:
UPROPERTY()
bool bWPressed = false;
UPROPERTY()
bool bSPressed = false;
UPROPERTY()
bool bAPressed = false;
UPROPERTY()
bool bDPressed = false;
  1. 在SetupPlayerInputComponent中绑定单个按键的事件(需为W/S/A/D分别创建Input Action):
// 绑定W键
Input->BindAction(WAction, ETriggerEvent::Started, this, &AShooterCharacter::OnWStart);
Input->BindAction(WAction, ETriggerEvent::Completed, this, &AShooterCharacter::OnWEnd);
// 绑定S键
Input->BindAction(SAction, ETriggerEvent::Started, this, &AShooterCharacter::OnSStart);
Input->BindAction(SAction, ETriggerEvent::Completed, this, &AShooterCharacter::OnSEnd);
// 绑定A键
Input->BindAction(AAction, ETriggerEvent::Started, this, &AShooterCharacter::OnAStart);
Input->BindAction(AAction, ETriggerEvent::Completed, this, &AShooterCharacter::OnAEnd);
// 绑定D键
Input->BindAction(DAction, ETriggerEvent::Started, this, &AShooterCharacter::OnDStart);
Input->BindAction(DAction, ETriggerEvent::Completed, this, &AShooterCharacter::OnDEnd);
  1. 实现按键状态回调:
void AShooterCharacter::OnWStart() { bWPressed = true; }
void AShooterCharacter::OnWEnd() { bWPressed = false; }
void AShooterCharacter::OnSStart() { bSPressed = true; }
void AShooterCharacter::OnSEnd() { bSPressed = false; }
void AShooterCharacter::OnAStart() { bAPressed = true; }
void AShooterCharacter::OnAEnd() { bAPressed = false; }
void AShooterCharacter::OnDStart() { bDPressed = true; }
void AShooterCharacter::OnDEnd() { bDPressed = false; }
  1. 修改Tick函数计算输入:
void AShooterCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    float XInput = 0.f;
    XInput += bWPressed ? 1.f : 0.f;
    XInput -= bSPressed ? 1.f : 0.f;

    float YInput = 0.f;
    YInput += bDPressed ? 1.f : 0.f;
    YInput -= bAPressed ? 1.f : 0.f;

    CurrentMovementInput = FVector2D(XInput, YInput).GetSafeNormal();
    
    AddMovementInput(GetActorForwardVector() * CurrentMovementInput.X);
    AddMovementInput(GetActorRightVector() * CurrentMovementInput.Y);
}

内容的提问来源于stack exchange,提问作者Joe Bevis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:45:35