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默认采用覆盖式计算轴值,只需修改输入动作的设置即可实现累加抵消:
- 打开你的
MoveAction资源 - 在Axis Settings面板中,将
Axis Behavior从Value改为Sum - 此时同一轴的多个输入会自动累加(如W的+1和S的-1相加为0),直接使用原代码即可生效
方法2:修复回调绑定与逻辑
原代码使用ETriggerEvent::Triggered,该事件仅在输入状态变化时触发一次,无法捕获完整的多按键状态。改为绑定Updated事件,并配合Sum轴行为:
- 按方法1修改
MoveAction的Axis Behavior为Sum - 修改绑定事件类型:
Input->BindAction(MoveAction, ETriggerEvent::Updated, this, &AShooterCharacter::MoveCallback);
- 简化MoveCallback逻辑(因为UE已自动累加抵消):
void AShooterCharacter::MoveCallback(const FInputActionInstance& Instance) { CurrentMovementInput = Instance.GetValue().Get<FVector2D>(); }
Tick函数保持不变,即可实现方向键抵消效果。
方法3:手动检测按键状态(自定义性更强)
若需要更精细的控制,可直接绑定单个按键的按下/释放事件,手动计算输入值:
- 在角色类头文件添加状态变量:
UPROPERTY() bool bWPressed = false; UPROPERTY() bool bSPressed = false; UPROPERTY() bool bAPressed = false; UPROPERTY() bool bDPressed = false;
- 在
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);
- 实现按键状态回调:
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; }
- 修改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
相关产品推荐
相关产品推荐

