diff --git a/03-UnrealEngine/Gameplay/GAS/GAS Ability输入绑定.md b/03-UnrealEngine/Gameplay/GAS/GAS Ability输入绑定.md new file mode 100644 index 0000000..7931e64 --- /dev/null +++ b/03-UnrealEngine/Gameplay/GAS/GAS Ability输入绑定.md @@ -0,0 +1,111 @@ +--- +title: Untitled +date: 2024-01-29 13:23:24 +excerpt: +tags: +rating: ⭐ +--- +# 前言 +相关函数主要为: +- AbilitySystemComponent->BindToInputComponent():只绑定名称为AbilityConfirm与AbilityCancel的InputAction。 +- AbilitySystemComponent->BindAbilityActivationToInputComponent():输入InputComponent、FGameplayAbilityInputBinds、FTopLevelAssetPath(枚举类路径)、枚举ID,之后绑定GA与Input。 +- AbilitySystemComponent->SetBlockAbilityBindingsArray():设置Block列表。 + +# GAS +BindAbilityActivationToInputComponent()的绑定方式如果ASC在Character中,可以在SetupPlayerInputComponent()中进行绑定: +```c +// Bind to AbilitySystemComponent +FTopLevelAssetPath AbilityEnumAssetPath = FTopLevelAssetPath(FName("/Script/GASDocumentation"), FName("EGDAbilityInputID")); +AbilitySystemComponent->BindAbilityActivationToInputComponent(PlayerInputComponent, FGameplayAbilityInputBinds(FString("ConfirmTarget"), + FString("CancelTarget"), AbilityEnumAssetPath, static_cast(EGDAbilityInputID::Confirm), static_cast(EGDAbilityInputID::Cancel))); +``` + +其内部主要是类似这样的方式进行绑定: +```c++ +// Pressed event +{ + FInputActionBinding AB(FName(*FullStr), IE_Pressed); + AB.ActionDelegate.GetDelegateForManualSet().BindUObject(this, &UAbilitySystemComponent::AbilityLocalInputPressed, idx); + InputComponent->AddActionBinding(AB); +} + +// Released event +{ + FInputActionBinding AB(FName(*FullStr), IE_Released); + AB.ActionDelegate.GetDelegateForManualSet().BindUObject(this, &UAbilitySystemComponent::AbilityLocalInputReleased, idx); + InputComponent->AddActionBinding(AB); +} +``` + +AbilityLocalInputPressed()与AbilityLocalInputReleased()会执行: +1. 触发多播委托 +2. TryActivateAbility() 或者 AbilitySpecInputPressed()。 + +感觉可以自己实现一个BindAbilityActivationToInputComponent()的绑定逻辑,ASC自带的逻辑有点2。 +GAS使用的是**InputComponent->AddActionBinding**,而增强输入使用**PlayerEnhancedInputComponent->BindAction**。本质是一样的。 +```c++ +FInputActionBinding& BindAction( const FName ActionName, const EInputEvent KeyEvent, UserClass* Object, typename FInputActionHandlerSignature::TMethodPtr< UserClass > Func ) +{ + FInputActionBinding AB( ActionName, KeyEvent ); + AB.ActionDelegate.BindDelegate(Object, Func); + return AddActionBinding(MoveTemp(AB)); +} +``` + +## 绑定输入而不激活能力 +如果您不希望`GameplayAbilities`在按下输入时自动激活,但仍将它们绑定到输入以与 一起使用`AbilityTasks`,则可以向您的`UGameplayAbility`子类添加一个新的 bool 变量`bActivateOnInput`,该变量默认为`true`并覆盖`UAbilitySystemComponent::AbilityLocalInputPressed()`。 +```c +void UGSAbilitySystemComponent::AbilityLocalInputPressed(int32 InputID) +{ + // Consume the input if this InputID is overloaded with GenericConfirm/Cancel and the GenericConfim/Cancel callback is bound + if (IsGenericConfirmInputBound(InputID)) + { + LocalInputConfirm(); + return; + } + + if (IsGenericCancelInputBound(InputID)) + { + LocalInputCancel(); + return; + } + + // --------------------------------------------------------- + + ABILITYLIST_SCOPE_LOCK(); + for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items) + { + if (Spec.InputID == InputID) + { + if (Spec.Ability) + { + Spec.InputPressed = true; + if (Spec.IsActive()) + { + if (Spec.Ability->bReplicateInputDirectly && IsOwnerActorAuthoritative() == false) + { + ServerSetInputPressed(Spec.Handle); + } + + AbilitySpecInputPressed(Spec); + + // Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server. + InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey()); + } + else + { + UGSGameplayAbility* GA = Cast(Spec.Ability); + if (GA && GA->bActivateOnInput) + { + // Ability is not active, so try to activate it + TryActivateAbility(Spec.Handle); + } + } + } + } + } +} +``` + +# SDHGame +李兄是在状态机每个节点的StateBegin()中调用CreateDynamicSkillInputActionMappingContext()进行动态绑定的。 \ No newline at end of file