ASC学习笔记0008:用于注册能力按键输入的回调
中文注释:UrealEngine-5.2.1源码-AbilitySystemComponent.h
学习内容:
/** 用于注册能力按键输入的回调 */DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityAbilityKey, /*UGameplayAbility*, Ability, */int32, InputID);
一. 这是一个 Unreal Engine 中的宏定义,用于声明一个动态多播委托。让我为您详细解释这个声明:
语法分析
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityAbilityKey, // 委托类型名称/*UGameplayAbility*, Ability, */ // 被注释掉的参数int32, InputID // 实际的参数类型和名称
);
实际效果
这个宏会生成一个名为 FAbilityAbilityKey 的动态多播委托,其签名相当于:
// 生成的委托签名(概念上)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityAbilityKey, int32, InputID);// 对应的函数签名
void Broadcast(int32 InputID);
在 Gameplay Ability System 中的用途
这个委托通常用于处理能力系统的输入绑定:
// 在 Ability System Component 中
UPROPERTY(BlueprintAssignable, Category = "Abilities")
FAbilityAbilityKey AbilityKeyPressed;// 绑定回调
AbilitySystemComponent->AbilityKeyPressed.AddDynamic(this, &AMyCharacter::OnAbilityKeyPressed);// 回调函数实现
UFUNCTION()
void OnAbilityKeyPressed(int32 InputID) {// 处理对应 InputID 的能力激活UE_LOG(LogTemp, Warning, TEXT("Ability key pressed: %d"), InputID);
}
注意事项
-
注释掉的参数:原本可能设计为传递
UGameplayAbility*和能力,但最终只保留了InputID -
命名重复:委托名称
FAbilityAbilityKey中的 "Ability" 重复了,可能是笔误 -
建议的改进命名:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAbilityInput, int32, InputID);
这个委托让您可以在蓝图中或 C++ 中绑定回调,当玩家按下绑定的能力按键时触发相应的游戏能力。
二. 在真实的游戏项目中,这种能力按键委托在能力系统中有着广泛而核心的应用。以下是一些具体的实际应用场景:
1. 玩家输入与能力绑定
输入组件中的绑定
// 在玩家控制器或角色中
void AMyPlayerController::SetupInputComponent()
{Super::SetupInputComponent();InputComponent->BindAction("Ability1", IE_Pressed, this, &AMyPlayerController::OnAbility1Pressed);InputComponent->BindAction("Ability2", IE_Pressed, this, &AMyPlayerController::OnAbility2Pressed);
}void AMyPlayerController::OnAbility1Pressed()
{// 触发能力按键委托,InputID 对应能力槽位AbilitySystemComponent->OnAbilityKeyPressed.Broadcast(1);
}void AMyPlayerController::OnAbility2Pressed()
{AbilitySystemComponent->OnAbilityKeyPressed.Broadcast(2);
}
2. 能力系统组件中的处理
// 在自定义 AbilitySystemComponent 中
UMyAbilitySystemComponent::UMyAbilitySystemComponent()
{// 绑定委托OnAbilityKeyPressed.AddDynamic(this, &UMyAbilitySystemComponent::HandleAbilityInput);
}void UMyAbilitySystemComponent::HandleAbilityInput(int32 InputID)
{if (!OwnerActor || OwnerActor->IsPendingKill())return;// 查找对应输入ID的能力FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromInputID(InputID);if (AbilitySpec && AbilitySpec->Ability){// 尝试激活能力TryActivateAbility(AbilitySpec->Handle);}
}
3. UI 技能栏集成
技能栏按钮点击
// 技能栏UI组件
void USkillBarWidget::OnSkillButtonClicked(int32 SlotIndex)
{if (APlayerController* PC = GetOwningPlayer()){if (UMyAbilitySystemComponent* ASC = GetAbilitySystemComponent()){// 通过委托通知能力系统ASC->OnAbilityKeyPressed.Broadcast(SlotIndex);}}
}
4. 复杂的输入上下文系统
// 支持不同上下文下的输入重映射
void UInputContextManager::HandleGlobalAbilityInput(int32 InputID)
{// 根据当前上下文获取映射后的能力IDint32 MappedAbilityID = GetMappedAbilityID(CurrentContext, InputID);// 广播映射后的IDAbilitySystem->OnAbilityKeyPressed.Broadcast(MappedAbilityID);
}
5. 连招系统集成
// 连招管理器
UComboManager::UComboManager()
{// 监听能力按键OnAbilityKeyPressed.AddDynamic(this, &UComboManager::OnAbilityInputReceived);
}void UComboManager::OnAbilityInputReceived(int32 InputID)
{// 记录输入时间戳FInputRecord NewRecord;NewRecord.InputID = InputID;NewRecord.Timestamp = GetWorld()->GetTimeSeconds();InputHistory.Add(NewRecord);// 检测连招CheckForCombo();
}
6. 平台特定适配
// 处理不同平台的输入差异
void UCrossPlatformInputHandler::HandleTouchInput(int32 TouchIndex, FVector2D Location)
{// 将触摸位置转换为能力IDint32 AbilityID = ConvertTouchToAbilityID(Location);if (AbilityID != INDEX_NONE){OnAbilityKeyPressed.Broadcast(AbilityID);}
}void UCrossPlatformInputHandler::HandleControllerInput(FKey Key)
{// 手柄按键映射到能力IDint32 AbilityID = ControllerMapping.FindRef(Key);if (AbilityID != INDEX_NONE){OnAbilityKeyPressed.Broadcast(AbilityID);}
}
7. AI 指令系统
// AI控制器下达能力使用指令
void AAIAbilityController::IssueAbilityCommand(int32 AbilityID, AActor* Target)
{// AI也可以通过相同的接口触发能力if (UAbilitySystemComponent* ASC = Pawn->FindComponentByClass<UAbilitySystemComponent>()){ASC->OnAbilityKeyPressed.Broadcast(AbilityID);// 记录AI决策LogAIAbilityUsage(AbilityID, Target);}
}
8. 回放和调试系统
// 能力输入记录和回放
void UAbilityReplaySystem::RecordAbilityInput(int32 InputID)
{FReplayFrame Frame;Frame.InputID = InputID;Frame.Timestamp = GetWorld()->GetTimeSeconds();ReplayData.Add(Frame);// 同时广播给实时系统OnAbilityKeyPressed.Broadcast(InputID);
}void UAbilityReplaySystem::ReplayInputs()
{for (const FReplayFrame& Frame : ReplayData){// 在回放时模拟输入GetWorld()->GetTimerManager().SetTimerForNextTick([this, Frame]() {OnAbilityKeyPressed.Broadcast(Frame.InputID);});}
}
实际项目中的优势
-
解耦设计 - 输入系统不需要了解具体能力实现
-
统一接口 - 键盘、鼠标、手柄、触摸屏都使用相同的委托
-
扩展性 - 轻松添加新的输入源或能力类型
-
调试友好 - 可以集中监控所有能力输入事件
-
网络同步 - 在多人游戏中容易同步输入事件
这种模式在《堡垒之夜》、《英雄联盟》等大型游戏中得到了广泛应用,是构建复杂能力系统的核心架构之一。
