Add move input processor

This commit is contained in:
2026-04-26 00:49:21 +08:00
parent 794fcbb8a9
commit 281db9a375
6 changed files with 186 additions and 1 deletions

View File

@@ -2,3 +2,4 @@
DefaultMappingPriority=0
bRouteInputThroughGenericInputSystem=True
bBlockGameplayInputWhenUIFocused=True
DefaultMoveInputProcessorClass="/Script/PHY.PHYInputProcessor_Move"

View File

@@ -0,0 +1,83 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Input/PHYInputProcessor_Move.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYInputProcessor_Move)
#include "Characters/PHYPlayerCharacter.h"
#include "GIPS_InputSystemComponent.h"
#include "PHYGameplayTags.h"
#include "Player/PHYPlayerController.h"
UPHYInputProcessor_Move::UPHYInputProcessor_Move()
{
InputTags.AddTag(PHYGameplayTags::Input_Move);
TriggerEvents = {
ETriggerEvent::Started,
ETriggerEvent::Triggered,
ETriggerEvent::Ongoing,
ETriggerEvent::Completed,
ETriggerEvent::Canceled
};
}
bool UPHYInputProcessor_Move::CheckCanHandleInput_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag, const ETriggerEvent TriggerEvent) const
{
(void)ActionData;
(void)TriggerEvent;
if (!IC || InputTag != PHYGameplayTags::Input_Move)
{
return false;
}
const APHYPlayerCharacter* PlayerCharacter = Cast<APHYPlayerCharacter>(IC->GetControlledPawn());
return PlayerCharacter && PlayerCharacter->GetController<APHYPlayerController>();
}
void UPHYInputProcessor_Move::HandleInputTriggered_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const
{
(void)InputTag;
RouteMoveInput(IC, ActionData, ETriggerEvent::Triggered);
}
void UPHYInputProcessor_Move::HandleInputStarted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const
{
(void)InputTag;
RouteMoveInput(IC, ActionData, ETriggerEvent::Started);
}
void UPHYInputProcessor_Move::HandleInputOngoing_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const
{
(void)InputTag;
RouteMoveInput(IC, ActionData, ETriggerEvent::Ongoing);
}
void UPHYInputProcessor_Move::HandleInputCanceled_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const
{
(void)InputTag;
RouteMoveInput(IC, ActionData, ETriggerEvent::Canceled);
}
void UPHYInputProcessor_Move::HandleInputCompleted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const
{
(void)InputTag;
RouteMoveInput(IC, ActionData, ETriggerEvent::Completed);
}
FString UPHYInputProcessor_Move::GetEditorFriendlyName_Implementation() const
{
return TEXT("PHY Move");
}
bool UPHYInputProcessor_Move::RouteMoveInput(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) const
{
if (!IC)
{
return false;
}
APHYPlayerCharacter* PlayerCharacter = Cast<APHYPlayerCharacter>(IC->GetControlledPawn());
APHYPlayerController* PlayerController = PlayerCharacter ? PlayerCharacter->GetController<APHYPlayerController>() : nullptr;
return PlayerController ? PlayerController->RouteMoveInputFromProcessor(ActionData, TriggerEvent) : false;
}

View File

@@ -96,7 +96,10 @@ void APHYPlayerController::OnReceivedInput(const FInputActionInstance& ActionDat
{
if (InputTag == PHYGameplayTags::Input_Move)
{
HandleMoveInput(ActionData, TriggerEvent);
if (!ConsumeMoveProcessorGuard(TriggerEvent))
{
RouteMoveInput(ActionData, TriggerEvent);
}
return;
}
@@ -112,6 +115,18 @@ void APHYPlayerController::OnReceivedInput(const FInputActionInstance& ActionDat
}
}
bool APHYPlayerController::RouteMoveInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
{
return HandleMoveInput(ActionData, TriggerEvent);
}
bool APHYPlayerController::RouteMoveInputFromProcessor(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
{
bMoveInputHandledByProcessor = true;
LastMoveInputProcessorTriggerEvent = TriggerEvent;
return RouteMoveInput(ActionData, TriggerEvent);
}
bool APHYPlayerController::HandleMoveInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
{
APHYPlayerCharacter* PHYCharacter = GetPHYPlayerCharacter();
@@ -140,6 +155,20 @@ bool APHYPlayerController::HandleMoveInput(const FInputActionInstance& ActionDat
return true;
}
bool APHYPlayerController::ConsumeMoveProcessorGuard(const ETriggerEvent TriggerEvent)
{
if (bMoveInputHandledByProcessor && LastMoveInputProcessorTriggerEvent == TriggerEvent)
{
bMoveInputHandledByProcessor = false;
LastMoveInputProcessorTriggerEvent = ETriggerEvent::None;
return true;
}
bMoveInputHandledByProcessor = false;
LastMoveInputProcessorTriggerEvent = ETriggerEvent::None;
return false;
}
bool APHYPlayerController::HandleLookInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
{
CachedLookInput = IsInputReleased(TriggerEvent) ? FVector2D::ZeroVector : ExtractAxis2D(ActionData.GetValue());

View File

@@ -0,0 +1,48 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GIPS_InputProcessor.h"
#include "PHYInputProcessor_Move.generated.h"
/**
* @brief PHY 移动输入处理器。
*
* 该处理器处理 `Input.Move`,并把二维输入值路由到当前玩家控制器和玩家角色。
*/
UCLASS(BlueprintType, Blueprintable, EditInlineNew, DefaultToInstanced)
class PHY_API UPHYInputProcessor_Move : public UGIPS_InputProcessor
{
GENERATED_BODY()
public:
/** @brief 构造默认响应的输入 Tag 和触发事件。 */
UPHYInputProcessor_Move();
protected:
/** @brief 检查当前输入组件是否能处理移动输入。 */
virtual bool CheckCanHandleInput_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag, ETriggerEvent TriggerEvent) const override;
/** @brief 处理 Triggered 移动输入。 */
virtual void HandleInputTriggered_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override;
/** @brief 处理 Started 移动输入。 */
virtual void HandleInputStarted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override;
/** @brief 处理 Ongoing 移动输入。 */
virtual void HandleInputOngoing_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override;
/** @brief 处理 Canceled 移动输入。 */
virtual void HandleInputCanceled_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override;
/** @brief 处理 Completed 移动输入。 */
virtual void HandleInputCompleted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override;
/** @brief 返回编辑器里显示的处理器名称。 */
virtual FString GetEditorFriendlyName_Implementation() const override;
private:
/** @brief 将移动输入发送给玩家控制器。 */
bool RouteMoveInput(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent) const;
};

View File

@@ -4,8 +4,11 @@
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UObject/SoftObjectPtr.h"
#include "PHYConfigSettings.generated.h"
class UGIPS_InputProcessor;
/**
* @brief PHY 项目核心配置。
*/
@@ -52,6 +55,10 @@ public:
/** @brief UI 聚焦时是否阻断 Gameplay 输入。 */
UPROPERTY(Config)
bool bBlockGameplayInputWhenUIFocused = true;
/** @brief 默认移动输入处理器类,用于创建 GenericInputSystem 控制配置。 */
UPROPERTY(Config)
TSoftClassPtr<UGIPS_InputProcessor> DefaultMoveInputProcessorClass;
};
/**

View File

@@ -50,6 +50,12 @@ public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Input")
FVector GetCachedMovementControlInput() const { return FVector(CachedMovementInput.X, CachedMovementInput.Y, 0.0f); }
/** @brief 从输入处理器或控制器 fallback 路由移动输入。 */
bool RouteMoveInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent);
/** @brief 从 GenericInputSystem 处理器路由移动输入,并阻止同一事件被广播 fallback 重复执行。 */
bool RouteMoveInputFromProcessor(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent);
protected:
/** @brief 绑定 GenericInputSystem 输入委托。 */
virtual void BindInputEvents();
@@ -64,6 +70,9 @@ protected:
/** @brief 处理视角输入。 */
virtual bool HandleLookInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent);
/** @brief 查询并消费移动处理器留下的重复执行保护。 */
virtual bool ConsumeMoveProcessorGuard(ETriggerEvent TriggerEvent);
/** @brief GenericInputSystem 路由组件。 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Input")
TObjectPtr<UGIPS_InputSystemComponent> InputSystemComponent;
@@ -83,4 +92,12 @@ protected:
/** @brief UGC 相机管理器读取的旋转输入缓存。 */
UPROPERTY(Transient)
FRotator CachedRotationInput = FRotator::ZeroRotator;
/** @brief 输入处理器是否已经处理了最近一次 Move 输入。 */
UPROPERTY(Transient)
bool bMoveInputHandledByProcessor = false;
/** @brief 最近一次由输入处理器处理的 Move 触发事件。 */
UPROPERTY(Transient)
ETriggerEvent LastMoveInputProcessorTriggerEvent = ETriggerEvent::None;
};