1. 델리게이트 선언
(1) AuraAbilitySystemComponent에서 델리게이트 선언
커스텀 어빌리티 시스템 컴포넌트에서 어빌리티를 각 액터에게 부여하고 있다.
새로운 델리게이트를 사용하여 어빌리티가 부여되면 OverlayWidgetController에서 해당 정보를 위젯으로 전달하도록 한다.
DECLARE_MULTICAST_DELEGATE(FAbilitiesGiven);
public:
// 델리게이트 바인딩
void AbilityActorInfoSet();
FEffectAssetTags EffectAssetTags;
FAbilitiesGiven AbilitiesGivenDelegate;
void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
for (TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
{
// 게임플레이 어빌리티 스펙 생성
FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
if (const UAuraGameplayAbility* AuraAbility = Cast<UAuraGameplayAbility>(AbilitySpec.Ability))
{
AbilitySpec.DynamicAbilityTags.AddTag(AuraAbility->StartupInputTag);
GiveAbility(AbilitySpec);
}
}
AbilitiesGivenDelegate.Broadcast();
}
캐릭터들에게 어빌리티가 부여된 후에 AbilitiesGivenDelegate가 호출된다.
(2) OverlayWidgetController에서 콜백 함수 바인딩하기
오버레이 위젯 컨트롤러의 BindCallbacksToDependencies 함수에서 델리게이트와 함수를 바인딩한다.
void OnInitializeStartupAbilities();
void UOverlayWidgetController::BindCallbacksToDependencies()
{
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (auto* AuraASC = Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent))
{
// 어빌리티 부여 완료
AuraASC->AbilitiesGivenDelegate.AddUObject(this, &UOverlayWidgetController::OnInitializeStartupAbilities);
// 플로팅 메세지 생략
AuraASC->EffectAssetTags.AddLambda(
}
}
2. 두 가지 상황
서버에서 어빌리티를 부여하는 시점이 델리게이트가 콜백 함수에 바인드하기 이전 혹은 이후가 될 수 있다.
(델리게이트를 함수에 바인드 하기 전에 호출해버릴 수 있음)
따라서 불리언을 사용하여 두 가지 상황을 모두 처리한다.
(1) AuraAbilitySystemComponent에서 불리언 선언
public:
// 델리게이트 바인딩
void AbilityActorInfoSet();
FEffectAssetTags EffectAssetTags;
FAbilitiesGiven AbilitiesGivenDelegate;
void AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities);
bool bStartupAbilitiesGiven = false;
void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
for (TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
{
// 게임플레이 어빌리티 스펙 생성
FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
if (const UAuraGameplayAbility* AuraAbility = Cast<UAuraGameplayAbility>(AbilitySpec.Ability))
{
AbilitySpec.DynamicAbilityTags.AddTag(AuraAbility->StartupInputTag);
GiveAbility(AbilitySpec);
}
}
bStartupAbilitiesGiven = true;
AbilitiesGivenDelegate.Broadcast();
}
어빌리티가 먼저 부여되고 델리게이트 호출이 나중에 일어나는 상황에서는 콜백 함수를 바인딩하지 않고 즉시 호출한다.
if (auto* AuraASC = Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent))
{
if (AuraASC->bStartupAbilitiesGiven)
{
// 콜백 함수 바인드 필요 없이 바로 호출
UOverlayWidgetController::OnInitializeStartupAbilities();
}
else
{
// 어빌리티 부여 이전이면 델리게이트에 함수 바인딩
AuraASC->AbilitiesGivenDelegate.AddUObject(this, &UOverlayWidgetController::OnInitializeStartupAbilities);
}
(2) 델리게이트 수정
이제 FAbilitiesGiven 델리게이트를 수정하여 AuraAbilitySystemComponent를 매개변수로 전달하여 사용할 것이다.
(2-1) AuraAbilitySystemComponent
DECLARE_MULTICAST_DELEGATE_OneParam(FAbilitiesGiven, UAuraAbilitySystemComponent*);
void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bStartupAbilitiesGiven = true;
AbilitiesGivenDelegate.Broadcast(this);
}
(2-2) OverlayWidgetController
void OnInitializeStartupAbilities(UAuraAbilitySystemComponent* AuraAbilitySystemComponent);
(2-3) 어빌리티를 순회하는 델리게이트 생성
위젯 컨트롤러에서 AuraAbilitySystemComponent를 가져와 루프하는 것이 아니라
AuraAbilitySystemComponent에서 루프하기 위해 델리게이트를 생성한다.
DECLARE_DELEGATE_OneParam(FForEachAbility, const FGameplayAbilitySpec&)
void UAuraAbilitySystemComponent::ForEachAbility(const FForEachAbility& Delegate)
{
// 어빌리티가 차단되거나 변경되었을 수 있음, 어빌리티 잠금
FScopedAbilityListLock ActiveScopeLock(*this);
for (const FGameplayAbilitySpec& AbilitySpec : GetActivatableAbilities())
{
if (Delegate.ExecuteIfBound(AbilitySpec) == false)
{
UE_LOG(LogAura, Error, TEXT("Failed to execute delegate in %hs"), __FUNCTION__);
}
}
}
어빌리티가 중간에 태그에 의해 차단(Block)되거나 취소(Canceled)될 수 있으므로 ActiveScopeLock을 이용하여 어빌리티들을 잠근다.
(2-4) 입력 태그 가져오는 함수
FGameplayTag GetInputTagFromSpec(const FGameplayAbilitySpec& AbilitySpec);
FGameplayTag UAuraAbilitySystemComponent::GetInputTagFromSpec(const FGameplayAbilitySpec& AbilitySpec)
{
for (FGameplayTag Tag : AbilitySpec.DynamicAbilityTags)
{
if (Tag.MatchesTag(FGameplayTag::RequestGameplayTag(FName("InputTag"))))
{
return Tag;
}
}
return FGameplayTag();
}
(2-5) 어빌리티 정보 가져온 후 위젯 블루프린트로 정보 넘기기
void UOverlayWidgetController::OnInitializeStartupAbilities(UAuraAbilitySystemComponent* AuraAbilitySystemComponent)
{
// TODO : 주어진 어빌리티에 대한 모든 어빌리티 정보를 가져옴, 위젯으로 전달
// 어빌리티가 주어지지 않았다면 리턴
if (!AuraAbilitySystemComponent->bStartupAbilitiesGiven)
return;
// 어빌리티를 순회하지 않고 델리게이트를 사용
// 콜백 함수 바인딩
FForEachAbility BroadcastDelegate;
BroadcastDelegate.BindLambda([this, AuraAbilitySystemComponent](const FGameplayAbilitySpec& AbilitySpec)
{
FAuraAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AuraAbilitySystemComponent->GetAbilityTagFromSpec(AbilitySpec));
Info.InputTag = AuraAbilitySystemComponent->GetInputTagFromSpec(AbilitySpec);
// 블루프린트 델리게이트
AbilityInfoDelegate.Broadcast(Info);
});
// 델리게이트 실행
AuraAbilitySystemComponent->ForEachAbility(BroadcastDelegate);
}
3. 순서 정리
(1) FForEachAbility 델리게이트에 람다 함수 바인딩
(2) FForEachAbility 델리게이트 실행
- AuraASC 내의 ForEachAbility 함수 실행.
- 어빌리티 목록 잠금.
- AuraASC 내의 활성 가능한 모든 어빌리티(어빌리티 스펙)에 대해서 순회.
- 전달 받은 델리게이트에 해당 어빌리티 스펙이 바운드 되어 있으면 델리게이트 실행.
(3) 람다 함수 실행
- 람다 함수 내에서 델리게이트 실행 시 전달 받은 AbilitySpec을 사용하여 태그와 일치하는 어빌리티 정보를 가져온다.
- 람다 함수 내에서 AbilitySpec을 이용하여 입력 태그를 가져와 어빌리티 정보에 대입한다.
- 위젯 델리게이트로 어빌리티 정보를 넘긴다.
'UE 5 스터디 > Gameplay Ability System(GAS)' 카테고리의 다른 글
19-7. 게임플레이 어빌리티 코스트 & 쿨다운, 몽타주 디버그 (0) | 2025.01.14 |
---|---|
19-6. 오버레이 UI - (6) 위젯에 어빌리티 정보 표시하기, 스펠 키매핑 변경하기 (0) | 2025.01.14 |
19-4. 오버레이 UI - (4) 어빌리티 정보 데이터 에셋 (0) | 2025.01.13 |
19-3. 오버레이 UI - (3) 경험치 바 (0) | 2025.01.13 |
19-2. 오버레이 UI - (2) 스펠 글로브 수정 후 오버레이에 배치 (0) | 2025.01.13 |