--- 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); } } } } } } ``` # 暂时需要使用GAS默认的枚举绑定Input的理由 GameplayAbilitySpec.h的InputPressed: ```c++ UPROPERTY(NotReplicated) uint8 InputPressed:1; ``` 该变量用于本地输入判断,可以使用自己的代码代替,但涉及到以下几个函数,工作量比较大。 - UAbilitySystemComponent - AbilityLocalInputReleased - AbilitySpecInputPressed - InternalServerTryActivateAbility - InternalTryActivateAbility - TryActivateAbility - 间接关系 - BindAbilityActivationToInputComponent - SetBlockAbilityBindingsArray - PressInputID - ReleaseInputID - UAbilityTask_WaitInputPress - UAbilityTask_WaitInputRelease 理论上是可以将其修改成增强输入的版本,只需要将枚举循环改成InputActionContext循环即可,具体逻辑在角色类中 ```c++ void AGSHeroCharacter::BindASCInput() { if (!bASCInputBound && IsValid(AbilitySystemComponent) && IsValid(InputComponent)) { AbilitySystemComponent->BindAbilityActivationToInputComponent(InputComponent, FGameplayAbilityInputBinds(FString("ConfirmTarget"), FString("CancelTarget"), FString("EGSAbilityInputID"), static_cast(EGSAbilityInputID::Confirm), static_cast(EGSAbilityInputID::Cancel))); bASCInputBound = true; } } FGameplayAbilityInputBinds(FString InConfirmTargetCommand, FString InCancelTargetCommand, FTopLevelAssetPath InEnumPathName, int32 InConfirmTargetInputID = INDEX_NONE, int32 InCancelTargetInputID = INDEX_NONE) : ConfirmTargetCommand(InConfirmTargetCommand) , CancelTargetCommand(InCancelTargetCommand) , EnumPathName(InEnumPathName) , ConfirmTargetInputID(InConfirmTargetInputID) , CancelTargetInputID(InCancelTargetInputID) { } ``` **ConfirmTarget**、**CancelTarget**需要在DefaultInput.ini中添加对应的配置(名字需要对应)。 **EGSAbilityInputID**为枚举类名称,**EGSAbilityInputID::Confirm**与**EGSAbilityInputID::Cancel**为枚举的index需要与GameplayAbilitySpec中的AbilityInputID对应。具体是在GiveAbility中进行,参考[[#GASShooter中给Ability注册按键ID]]。 之后还需要在URPGGameplayAbility中将枚举**ERPGAbilityInputID**修改成 ```c++ UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "RPGGameplayAbility|Input") ERPGAbilityInputID AbilityInputID = ERPGAbilityInputID::None; ``` ## GASShooter中给Ability注册按键ID ```c++ void AGSCharacterBase::AddCharacterAbilities() { // Grant abilities, but only on the server if (GetLocalRole() != ROLE_Authority || !IsValid(AbilitySystemComponent) || AbilitySystemComponent->bCharacterAbilitiesGiven) { return; } for (TSubclassOf& StartupAbility : CharacterAbilities) { AbilitySystemComponent->GiveAbility( FGameplayAbilitySpec(StartupAbility, GetAbilityLevel(StartupAbility.GetDefaultObject()->AbilityID), static_cast(StartupAbility.GetDefaultObject()->AbilityInputID), this)); } AbilitySystemComponent->bCharacterAbilitiesGiven = true; } ``` # SDHGame 李兄是在状态机每个节点的StateBegin()中调用CreateDynamicSkillInputActionMappingContext()进行动态绑定的。FSDHSkillInputActionBinding里包含FEnhancedActionKeyMapping相关数据。 ```c++ void USDHSMStateIns::OutputActionKeyMapping(TArray& OutBindings, const TArray& InputSkillBinding) { for (int32 i = 0; i < InputSkillBinding.Num(); i++) { FEnhancedActionKeyMapping NewMapping; NewMapping.Key = InputSkillBinding[i].Key; NewMapping.Action = InputSkillBinding[i].Action; OutBindings.Add(MoveTemp(NewMapping)); } } ```