From baeb4098c9920d7ff978fc98cadd5df295f93be7 Mon Sep 17 00:00:00 2001 From: cit110 <840418418@qq.com> Date: Sun, 26 Apr 2026 21:02:35 +0800 Subject: [PATCH] Add attribute menu input processor --- Config/DefaultPHYInput.ini | 1 + .../GameplayTags/PHYGameplayTags_Input.cpp | 1 + .../PHYInputProcessor_OpenAttributeMenu.cpp | 55 +++++++++++++++++++ .../Private/Player/PHYPlayerController.cpp | 49 +++++++++++++++++ .../UI/PHYAttributeOverviewPageWidget.cpp | 26 ++++----- .../PHYCombatDerivedAttributePageWidget.cpp | 50 ++++++++--------- .../PHYElementDerivedAttributePageWidget.cpp | 40 +++++++------- .../GameplayTags/PHYGameplayTags_Input.h | 3 + .../PHYInputProcessor_OpenAttributeMenu.h | 36 ++++++++++++ Source/PHY/Public/PHYConfigSettings.h | 4 ++ .../PHY/Public/Player/PHYPlayerController.h | 20 +++++++ 11 files changed, 227 insertions(+), 58 deletions(-) create mode 100644 Source/PHY/Private/Input/PHYInputProcessor_OpenAttributeMenu.cpp create mode 100644 Source/PHY/Public/Input/PHYInputProcessor_OpenAttributeMenu.h diff --git a/Config/DefaultPHYInput.ini b/Config/DefaultPHYInput.ini index e35487e..224d12c 100644 --- a/Config/DefaultPHYInput.ini +++ b/Config/DefaultPHYInput.ini @@ -4,3 +4,4 @@ bRouteInputThroughGenericInputSystem=True bBlockGameplayInputWhenUIFocused=True DefaultMoveInputProcessorClass="/Script/PHY.PHYInputProcessor_Move" DefaultLookInputProcessorClass="/Script/PHY.PHYInputProcessor_Look" +DefaultAttributeMenuInputProcessorClass="/Script/PHY.PHYInputProcessor_OpenAttributeMenu" diff --git a/Source/PHY/Private/GameplayTags/PHYGameplayTags_Input.cpp b/Source/PHY/Private/GameplayTags/PHYGameplayTags_Input.cpp index 4b4ae14..7d1ae2c 100644 --- a/Source/PHY/Private/GameplayTags/PHYGameplayTags_Input.cpp +++ b/Source/PHY/Private/GameplayTags/PHYGameplayTags_Input.cpp @@ -15,4 +15,5 @@ namespace PHYGameplayTags UE_DEFINE_GAMEPLAY_TAG(Input_Aim, "Input.Aim"); UE_DEFINE_GAMEPLAY_TAG(Input_LockOn, "Input.LockOn"); UE_DEFINE_GAMEPLAY_TAG(Input_Inventory_Toggle, "Input.Inventory.Toggle"); + UE_DEFINE_GAMEPLAY_TAG(Input_Menu_Attribute, "Input.Menu.Attribute"); } diff --git a/Source/PHY/Private/Input/PHYInputProcessor_OpenAttributeMenu.cpp b/Source/PHY/Private/Input/PHYInputProcessor_OpenAttributeMenu.cpp new file mode 100644 index 0000000..849d17a --- /dev/null +++ b/Source/PHY/Private/Input/PHYInputProcessor_OpenAttributeMenu.cpp @@ -0,0 +1,55 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "Input/PHYInputProcessor_OpenAttributeMenu.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYInputProcessor_OpenAttributeMenu) + +#include "Characters/PHYPlayerCharacter.h" +#include "GIPS_InputSystemComponent.h" +#include "PHYGameplayTags.h" +#include "Player/PHYPlayerController.h" + +UPHYInputProcessor_OpenAttributeMenu::UPHYInputProcessor_OpenAttributeMenu() +{ + InputTags.AddTag(PHYGameplayTags::Input_Menu_Attribute); + TriggerEvents = { + ETriggerEvent::Started + }; +} + +bool UPHYInputProcessor_OpenAttributeMenu::CheckCanHandleInput_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag, const ETriggerEvent TriggerEvent) const +{ + (void)ActionData; + + if (!IC || InputTag != PHYGameplayTags::Input_Menu_Attribute || TriggerEvent != ETriggerEvent::Started) + { + return false; + } + + const APHYPlayerCharacter* PlayerCharacter = Cast(IC->GetControlledPawn()); + const APHYPlayerController* PlayerController = PlayerCharacter ? PlayerCharacter->GetController() : nullptr; + return PlayerController && PlayerController->IsLocalController(); +} + +void UPHYInputProcessor_OpenAttributeMenu::HandleInputStarted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const FGameplayTag InputTag) const +{ + (void)InputTag; + RouteOpenAttributeMenuInput(IC, ActionData, ETriggerEvent::Started); +} + +FString UPHYInputProcessor_OpenAttributeMenu::GetEditorFriendlyName_Implementation() const +{ + return TEXT("PHY Open Attribute Menu"); +} + +bool UPHYInputProcessor_OpenAttributeMenu::RouteOpenAttributeMenuInput(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) const +{ + if (!IC) + { + return false; + } + + APHYPlayerCharacter* PlayerCharacter = Cast(IC->GetControlledPawn()); + APHYPlayerController* PlayerController = PlayerCharacter ? PlayerCharacter->GetController() : nullptr; + return PlayerController ? PlayerController->RouteOpenAttributeMenuInputFromProcessor(ActionData, TriggerEvent) : false; +} diff --git a/Source/PHY/Private/Player/PHYPlayerController.cpp b/Source/PHY/Private/Player/PHYPlayerController.cpp index de2dedb..863cf37 100644 --- a/Source/PHY/Private/Player/PHYPlayerController.cpp +++ b/Source/PHY/Private/Player/PHYPlayerController.cpp @@ -7,6 +7,7 @@ #include "Characters/PHYPlayerCharacter.h" #include "Characters/PHYCharacterSettings.h" #include "Components/SLSCharacterMovementComponent.h" +#include "Game/PHYHUD.h" #include "GIPS_InputSystemComponent.h" #include "InputActionValue.h" #include "PHYGameplayTags.h" @@ -115,6 +116,15 @@ void APHYPlayerController::OnReceivedInput(const FInputActionInstance& ActionDat return; } + if (InputTag == PHYGameplayTags::Input_Menu_Attribute) + { + if (!ConsumeAttributeMenuProcessorGuard(TriggerEvent)) + { + RouteOpenAttributeMenuInput(ActionData, TriggerEvent); + } + return; + } + if (APHYPlayerCharacter* PHYCharacter = GetPHYPlayerCharacter()) { PHYCharacter->HandleInputTag(InputTag, TriggerEvent); @@ -145,6 +155,18 @@ bool APHYPlayerController::RouteLookInputFromProcessor(const FInputActionInstanc return RouteLookInput(ActionData, TriggerEvent); } +bool APHYPlayerController::RouteOpenAttributeMenuInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) +{ + return HandleOpenAttributeMenuInput(ActionData, TriggerEvent); +} + +bool APHYPlayerController::RouteOpenAttributeMenuInputFromProcessor(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) +{ + bAttributeMenuInputHandledByProcessor = true; + LastAttributeMenuInputProcessorTriggerEvent = TriggerEvent; + return RouteOpenAttributeMenuInput(ActionData, TriggerEvent); +} + bool APHYPlayerController::HandleMoveInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) { APHYPlayerCharacter* PHYCharacter = GetPHYPlayerCharacter(); @@ -199,6 +221,33 @@ bool APHYPlayerController::ConsumeLookProcessorGuard(const ETriggerEvent Trigger return false; } +bool APHYPlayerController::ConsumeAttributeMenuProcessorGuard(const ETriggerEvent TriggerEvent) +{ + if (bAttributeMenuInputHandledByProcessor && LastAttributeMenuInputProcessorTriggerEvent == TriggerEvent) + { + bAttributeMenuInputHandledByProcessor = false; + LastAttributeMenuInputProcessorTriggerEvent = ETriggerEvent::None; + return true; + } + + bAttributeMenuInputHandledByProcessor = false; + LastAttributeMenuInputProcessorTriggerEvent = ETriggerEvent::None; + return false; +} + +bool APHYPlayerController::HandleOpenAttributeMenuInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) +{ + (void)ActionData; + + if (TriggerEvent != ETriggerEvent::Started || !IsLocalController()) + { + return false; + } + + APHYHUD* PHYHUD = GetHUD(); + return PHYHUD && PHYHUD->OpenAttributeMenu(this); +} + bool APHYPlayerController::HandleLookInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent) { CachedLookInput = IsInputReleased(TriggerEvent) ? FVector2D::ZeroVector : ExtractAxis2D(ActionData.GetValue()); diff --git a/Source/PHY/Private/UI/PHYAttributeOverviewPageWidget.cpp b/Source/PHY/Private/UI/PHYAttributeOverviewPageWidget.cpp index 0242d0a..3947d37 100644 --- a/Source/PHY/Private/UI/PHYAttributeOverviewPageWidget.cpp +++ b/Source/PHY/Private/UI/PHYAttributeOverviewPageWidget.cpp @@ -11,22 +11,22 @@ namespace { - float GetAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) + float GetOverviewAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) { return AbilitySystemComponent ? AbilitySystemComponent->GetNumericAttribute(Attribute) : 0.0f; } - FText MakeNumberText(const float Value) + FText MakeOverviewNumberText(const float Value) { return FText::FromString(FString::Printf(TEXT("%.0f"), Value)); } - FText MakePairText(const float CurrentValue, const float MaxValue) + FText MakeOverviewPairText(const float CurrentValue, const float MaxValue) { return FText::FromString(FString::Printf(TEXT("%.0f / %.0f"), FMath::Max(0.0f, CurrentValue), FMath::Max(0.0f, MaxValue))); } - void AddAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value, const bool bCanUpgrade = false) + void AddOverviewAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value, const bool bCanUpgrade = false) { if (GroupWidget) { @@ -41,15 +41,15 @@ void UPHYAttributeOverviewPageWidget::RefreshAttributes(UAbilitySystemComponent* ClearGroups(); UPHYAttributeGroupWidget* CoreGroup = AddGroup(FText::FromString(TEXT("核心属性"))); - AddAttributeRow(CoreGroup, TEXT("力量"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetStrengthAttribute())), true); - AddAttributeRow(CoreGroup, TEXT("敏捷"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetDexterityAttribute())), true); - AddAttributeRow(CoreGroup, TEXT("体质"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetVitalityAttribute())), true); - AddAttributeRow(CoreGroup, TEXT("智力"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetIntelligenceAttribute())), true); - AddAttributeRow(CoreGroup, TEXT("精神"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetSpiritAttribute())), true); - AddAttributeRow(CoreGroup, TEXT("感知"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetPerceptionAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("力量"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetStrengthAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("敏捷"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetDexterityAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("体质"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetVitalityAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("智力"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetIntelligenceAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("精神"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetSpiritAttribute())), true); + AddOverviewAttributeRow(CoreGroup, TEXT("感知"), MakeOverviewNumberText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCoreAttributeSet::GetPerceptionAttribute())), true); UPHYAttributeGroupWidget* ResourceGroup = AddGroup(FText::FromString(TEXT("战斗资源"))); - AddAttributeRow(ResourceGroup, TEXT("生命值"), MakePairText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetHealthAttribute()), GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxHealthAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("法力值"), MakePairText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetManaAttribute()), GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxManaAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("耐力值"), MakePairText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetStaminaAttribute()), GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxStaminaAttribute()))); + AddOverviewAttributeRow(ResourceGroup, TEXT("生命值"), MakeOverviewPairText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetHealthAttribute()), GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxHealthAttribute()))); + AddOverviewAttributeRow(ResourceGroup, TEXT("法力值"), MakeOverviewPairText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetManaAttribute()), GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxManaAttribute()))); + AddOverviewAttributeRow(ResourceGroup, TEXT("耐力值"), MakeOverviewPairText(GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetStaminaAttribute()), GetOverviewAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxStaminaAttribute()))); } diff --git a/Source/PHY/Private/UI/PHYCombatDerivedAttributePageWidget.cpp b/Source/PHY/Private/UI/PHYCombatDerivedAttributePageWidget.cpp index ba0a51a..9c28126 100644 --- a/Source/PHY/Private/UI/PHYCombatDerivedAttributePageWidget.cpp +++ b/Source/PHY/Private/UI/PHYCombatDerivedAttributePageWidget.cpp @@ -10,27 +10,27 @@ namespace { - float GetAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) + float GetCombatDerivedAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) { return AbilitySystemComponent ? AbilitySystemComponent->GetNumericAttribute(Attribute) : 0.0f; } - FText MakeNumberText(const float Value) + FText MakeCombatNumberText(const float Value) { return FText::FromString(FString::Printf(TEXT("%.0f"), Value)); } - FText MakePercentText(const float Value) + FText MakeCombatPercentText(const float Value) { return FText::FromString(FString::Printf(TEXT("%.1f%%"), Value * 100.0f)); } - FText MakeMultiplierText(const float Value) + FText MakeCombatMultiplierText(const float Value) { return FText::FromString(FString::Printf(TEXT("x%.2f"), Value)); } - void AddAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value) + void AddCombatAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value) { if (GroupWidget) { @@ -45,28 +45,28 @@ void UPHYCombatDerivedAttributePageWidget::RefreshAttributes(UAbilitySystemCompo ClearGroups(); UPHYAttributeGroupWidget* ResourceGroup = AddGroup(FText::FromString(TEXT("资源上限"))); - AddAttributeRow(ResourceGroup, TEXT("当前生命"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetHealthAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("生命上限"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxHealthAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("当前法力"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetManaAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("法力上限"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxManaAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("当前耐力"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetStaminaAttribute()))); - AddAttributeRow(ResourceGroup, TEXT("耐力上限"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxStaminaAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("当前生命"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetHealthAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("生命上限"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxHealthAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("当前法力"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetManaAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("法力上限"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxManaAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("当前耐力"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetStaminaAttribute()))); + AddCombatAttributeRow(ResourceGroup, TEXT("耐力上限"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMaxStaminaAttribute()))); UPHYAttributeGroupWidget* AttackGroup = AddGroup(FText::FromString(TEXT("攻击能力"))); - AddAttributeRow(AttackGroup, TEXT("物理攻击"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPhysicalAttackPowerAttribute()))); - AddAttributeRow(AttackGroup, TEXT("法术强度"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetSpellPowerAttribute()))); - AddAttributeRow(AttackGroup, TEXT("命中率"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetAccuracyAttribute()))); - AddAttributeRow(AttackGroup, TEXT("暴击率"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCriticalChanceAttribute()))); - AddAttributeRow(AttackGroup, TEXT("暴击伤害"), MakeMultiplierText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCriticalDamageAttribute()))); - AddAttributeRow(AttackGroup, TEXT("攻击速度"), MakeMultiplierText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetAttackSpeedAttribute()))); - AddAttributeRow(AttackGroup, TEXT("冷却缩减"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCooldownReductionAttribute()))); - AddAttributeRow(AttackGroup, TEXT("破防强度"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetGuardBreakPowerAttribute()))); - AddAttributeRow(AttackGroup, TEXT("韧性伤害"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPoiseDamageAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("物理攻击"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPhysicalAttackPowerAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("法术强度"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetSpellPowerAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("命中率"), MakeCombatPercentText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetAccuracyAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("暴击率"), MakeCombatPercentText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCriticalChanceAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("暴击伤害"), MakeCombatMultiplierText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCriticalDamageAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("攻击速度"), MakeCombatMultiplierText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetAttackSpeedAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("冷却缩减"), MakeCombatPercentText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetCooldownReductionAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("破防强度"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetGuardBreakPowerAttribute()))); + AddCombatAttributeRow(AttackGroup, TEXT("韧性伤害"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPoiseDamageAttribute()))); UPHYAttributeGroupWidget* DefenseGroup = AddGroup(FText::FromString(TEXT("防御能力"))); - AddAttributeRow(DefenseGroup, TEXT("护甲"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetArmorAttribute()))); - AddAttributeRow(DefenseGroup, TEXT("魔法抗性"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMagicResistanceAttribute()))); - AddAttributeRow(DefenseGroup, TEXT("闪避率"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetEvasionAttribute()))); - AddAttributeRow(DefenseGroup, TEXT("格挡强度"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetBlockPowerAttribute()))); - AddAttributeRow(DefenseGroup, TEXT("韧性"), MakeNumberText(GetAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPoiseAttribute()))); + AddCombatAttributeRow(DefenseGroup, TEXT("护甲"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetArmorAttribute()))); + AddCombatAttributeRow(DefenseGroup, TEXT("魔法抗性"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetMagicResistanceAttribute()))); + AddCombatAttributeRow(DefenseGroup, TEXT("闪避率"), MakeCombatPercentText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetEvasionAttribute()))); + AddCombatAttributeRow(DefenseGroup, TEXT("格挡强度"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetBlockPowerAttribute()))); + AddCombatAttributeRow(DefenseGroup, TEXT("韧性"), MakeCombatNumberText(GetCombatDerivedAttributeValue(AbilitySystemComponent, UPHYCombatAttributeSet::GetPoiseAttribute()))); } diff --git a/Source/PHY/Private/UI/PHYElementDerivedAttributePageWidget.cpp b/Source/PHY/Private/UI/PHYElementDerivedAttributePageWidget.cpp index 00813c6..0e9d4fc 100644 --- a/Source/PHY/Private/UI/PHYElementDerivedAttributePageWidget.cpp +++ b/Source/PHY/Private/UI/PHYElementDerivedAttributePageWidget.cpp @@ -10,17 +10,17 @@ namespace { - float GetAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) + float GetElementDerivedAttributeValue(const UAbilitySystemComponent* AbilitySystemComponent, const FGameplayAttribute& Attribute) { return AbilitySystemComponent ? AbilitySystemComponent->GetNumericAttribute(Attribute) : 0.0f; } - FText MakePercentText(const float Value) + FText MakeElementPercentText(const float Value) { return FText::FromString(FString::Printf(TEXT("%.1f%%"), Value * 100.0f)); } - void AddAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value) + void AddElementAttributeRow(UPHYAttributeGroupWidget* GroupWidget, const TCHAR* Label, const FText& Value) { if (GroupWidget) { @@ -35,23 +35,23 @@ void UPHYElementDerivedAttributePageWidget::RefreshAttributes(UAbilitySystemComp ClearGroups(); UPHYAttributeGroupWidget* BonusGroup = AddGroup(FText::FromString(TEXT("元素伤害加成"))); - AddAttributeRow(BonusGroup, TEXT("火伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetFireDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("水伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWaterDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("冰伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetIceDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("雷伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightningDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("地伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetEarthDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("风伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWindDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("光伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("暗伤加成"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetDarkDamageBonusAttribute()))); - AddAttributeRow(BonusGroup, TEXT("元素穿透"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetElementPenetrationAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("火伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetFireDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("水伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWaterDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("冰伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetIceDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("雷伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightningDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("地伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetEarthDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("风伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWindDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("光伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("暗伤加成"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetDarkDamageBonusAttribute()))); + AddElementAttributeRow(BonusGroup, TEXT("元素穿透"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetElementPenetrationAttribute()))); UPHYAttributeGroupWidget* ResistanceGroup = AddGroup(FText::FromString(TEXT("元素抗性"))); - AddAttributeRow(ResistanceGroup, TEXT("火抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetFireResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("水抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWaterResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("冰抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetIceResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("雷抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightningResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("地抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetEarthResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("风抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWindResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("光抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightResistanceAttribute()))); - AddAttributeRow(ResistanceGroup, TEXT("暗抗"), MakePercentText(GetAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetDarkResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("火抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetFireResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("水抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWaterResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("冰抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetIceResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("雷抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightningResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("地抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetEarthResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("风抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetWindResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("光抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetLightResistanceAttribute()))); + AddElementAttributeRow(ResistanceGroup, TEXT("暗抗"), MakeElementPercentText(GetElementDerivedAttributeValue(AbilitySystemComponent, UPHYElementAttributeSet::GetDarkResistanceAttribute()))); } diff --git a/Source/PHY/Public/GameplayTags/PHYGameplayTags_Input.h b/Source/PHY/Public/GameplayTags/PHYGameplayTags_Input.h index 11c9328..28b1f4e 100644 --- a/Source/PHY/Public/GameplayTags/PHYGameplayTags_Input.h +++ b/Source/PHY/Public/GameplayTags/PHYGameplayTags_Input.h @@ -38,4 +38,7 @@ namespace PHYGameplayTags /** @brief 背包开关输入。 */ UE_DECLARE_GAMEPLAY_TAG_EXTERN(Input_Inventory_Toggle); + + /** @brief 角色属性菜单开关输入。 */ + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Input_Menu_Attribute); } diff --git a/Source/PHY/Public/Input/PHYInputProcessor_OpenAttributeMenu.h b/Source/PHY/Public/Input/PHYInputProcessor_OpenAttributeMenu.h new file mode 100644 index 0000000..547a43d --- /dev/null +++ b/Source/PHY/Public/Input/PHYInputProcessor_OpenAttributeMenu.h @@ -0,0 +1,36 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "GIPS_InputProcessor.h" +#include "PHYInputProcessor_OpenAttributeMenu.generated.h" + +/** + * @brief PHY 角色属性菜单输入处理器。 + * + * 该处理器处理 `Input.Menu.Attribute`,并把本地输入路由到玩家控制器打开 Generic UI Menu 层。 + */ +UCLASS(BlueprintType, Blueprintable, EditInlineNew, DefaultToInstanced) +class PHY_API UPHYInputProcessor_OpenAttributeMenu : public UGIPS_InputProcessor +{ + GENERATED_BODY() + +public: + /** @brief 构造默认响应的输入 Tag 和触发事件。 */ + UPHYInputProcessor_OpenAttributeMenu(); + +protected: + /** @brief 检查当前输入组件是否能处理角色属性菜单输入。 */ + virtual bool CheckCanHandleInput_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag, ETriggerEvent TriggerEvent) const override; + + /** @brief 处理 Started 菜单输入。 */ + virtual void HandleInputStarted_Implementation(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, FGameplayTag InputTag) const override; + + /** @brief 返回编辑器里显示的处理器名称。 */ + virtual FString GetEditorFriendlyName_Implementation() const override; + +private: + /** @brief 将菜单输入发送给玩家控制器。 */ + bool RouteOpenAttributeMenuInput(UGIPS_InputSystemComponent* IC, const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent) const; +}; diff --git a/Source/PHY/Public/PHYConfigSettings.h b/Source/PHY/Public/PHYConfigSettings.h index cc3a4d8..bc8febf 100644 --- a/Source/PHY/Public/PHYConfigSettings.h +++ b/Source/PHY/Public/PHYConfigSettings.h @@ -66,6 +66,10 @@ public: /** @brief 默认视角输入处理器类,用于创建 GenericInputSystem 控制配置。 */ UPROPERTY(Config) TSoftClassPtr DefaultLookInputProcessorClass; + + /** @brief 默认角色属性菜单输入处理器类,用于推入 UI Menu 层。 */ + UPROPERTY(Config) + TSoftClassPtr DefaultAttributeMenuInputProcessorClass; }; /** diff --git a/Source/PHY/Public/Player/PHYPlayerController.h b/Source/PHY/Public/Player/PHYPlayerController.h index bca3b3b..ed33c73 100644 --- a/Source/PHY/Public/Player/PHYPlayerController.h +++ b/Source/PHY/Public/Player/PHYPlayerController.h @@ -59,6 +59,12 @@ public: /** @brief 从 GenericInputSystem 处理器路由视角输入,并阻止同一事件被 fallback 重复执行。 */ bool RouteLookInputFromProcessor(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent); + /** @brief 路由角色属性菜单输入。 */ + bool RouteOpenAttributeMenuInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent); + + /** @brief 从 GenericInputSystem 处理器路由角色属性菜单输入,并阻止同一事件被 fallback 重复执行。 */ + bool RouteOpenAttributeMenuInputFromProcessor(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent); + protected: /** @brief 绑定玩家角色身上的 GenericInputSystem 输入委托。 */ virtual void BindInputEvents(); @@ -73,12 +79,18 @@ protected: /** @brief 处理视角输入。 */ virtual bool HandleLookInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent); + /** @brief 处理角色属性菜单输入,本地推入 Generic UI Menu 层。 */ + virtual bool HandleOpenAttributeMenuInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent); + /** @brief 查询并消费移动处理器留下的重复执行保护。 */ virtual bool ConsumeMoveProcessorGuard(ETriggerEvent TriggerEvent); /** @brief 查询并消费视角处理器留下的重复执行保护。 */ virtual bool ConsumeLookProcessorGuard(ETriggerEvent TriggerEvent); + /** @brief 查询并消费属性菜单处理器留下的重复执行保护。 */ + virtual bool ConsumeAttributeMenuProcessorGuard(ETriggerEvent TriggerEvent); + /** @brief 当前已经绑定输入委托的角色输入组件。 */ UPROPERTY(Transient) TObjectPtr BoundInputSystemComponent; @@ -110,4 +122,12 @@ protected: /** @brief 最近一次由输入处理器处理的 Look 触发事件。 */ UPROPERTY(Transient) ETriggerEvent LastLookInputProcessorTriggerEvent = ETriggerEvent::None; + + /** @brief 输入处理器是否已经处理了最近一次属性菜单输入。 */ + UPROPERTY(Transient) + bool bAttributeMenuInputHandledByProcessor = false; + + /** @brief 最近一次由输入处理器处理的属性菜单触发事件。 */ + UPROPERTY(Transient) + ETriggerEvent LastAttributeMenuInputProcessorTriggerEvent = ETriggerEvent::None; };