1. 보유한 어빌리티 순회하여 업그레이드 태그 전송

플레이어 캐릭터가 보유한(Activated) 어빌리티를 대상으로 순회를 하고, 랜덤한 어빌리티를 뽑아 해당 어빌리티의 랜덤 업그레이드 태그를 전송한다.

 

(1) AuraPlayerState -  델리게이트 선언

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnRandomUpgradeTagsGenerated, AAuraPlayerState*, AuraPlayerState, TArray<FGameplayTag>&, RandomUpgradeTags);
	// 랜덤 업그레이드 선택 델리게이트
	FOnRandomUpgradeTagsGenerated OnRandomUpgradeTagsGeneratedDelegate;

플레이어 스테이트에서 선택한 세 개의 업그레이드 태그를 게임 모드로 전달하는 델리게이트를 선언한다.

 

 

(2) 보유한 어빌리티 태그 가져오기

	// 활성화 모든 어빌리티의 태그를 반환
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GAS|Abilities")
	TArray<FGameplayTag> GetAllActiveAbilityTags() const;
TArray<FGameplayTag> AAuraPlayerState::GetAllActiveAbilityTags() const
{
    TArray<FGameplayTag> AllActiveTags;
    
    // 활성화된 어빌리티
    TArray<FGameplayAbilitySpec> ActiveSpecs = AbilitySystemComponent->GetActivatableAbilities();

    for (FGameplayAbilitySpec& Spec : ActiveSpecs)
    {
        FGameplayTagContainer AbilityTagContainer = Spec.Ability->AbilityTags;
        if (AbilityTagContainer.HasTag(FAuraGameplayTags::Get().Abilities_None))
            continue;

        for (auto Tag : AbilityTagContainer)
        {
            if (Tag.MatchesTag(FGameplayTag::RequestGameplayTag(TEXT("Abilities"))))
            {
                // 어빌리티 태그라면 추가
                AllActiveTags.Add(Tag);
            }
        }
    }
    
    return AllActiveTags;
}

ASC의 활성화 된 어빌리티를 가져온 이후, 부모 태그가 Abilities에 해당하는 모든 어빌리티 태그를 배열로 내보낸다.

 

 

(3) 세 개의 랜덤 태그를 뽑아 전달하는 함수

TArray<FGameplayTag> AAuraPlayerState::GetRandomUpgradeTagsForActivatedAbility_Three()
{
    const TArray<FGameplayTag> ActivatedAbilityTags = GetAllActiveAbilityTags();
    
    TArray<FGameplayTag> RandomUpgradeTags;
    RandomUpgradeTags.Empty();
    
    // 주어진 어빌리티 태그에 대해 랜덤한 업그레이드 태그 뽑기
    if (UAbilityUpgradeInfo* Info = UAuraAbilitySystemLibrary::GetAbilityUpgradeInfo(this))
    {
        int ActivatedAbilityTagsNum = ActivatedAbilityTags.Num();
        int RandValue0 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);
        int RandValue1 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);
        int RandValue2 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);

        // 랜덤으로 뽑은 어빌리티 태그는 중복 가능 -> 파이어볼트 업그레이드 2개 노출 가능
        const auto Tag0 = ActivatedAbilityTags[RandValue0];
        const auto Tag1 = ActivatedAbilityTags[RandValue1];
        const auto Tag2 = ActivatedAbilityTags[RandValue2];
        
        FGameplayTag UpgradeTag0;
        FGameplayTag UpgradeTag1;
        FGameplayTag UpgradeTag2;

        // 루프 함수 제한
        int CurrentAttempt = 0;
        
        // 동일한 태그가 없을 때까지 뽑기
        while (UpgradeTag0 == UpgradeTag1 || UpgradeTag1 == UpgradeTag2 || UpgradeTag0 == UpgradeTag2)
        {
            UpgradeTag0 = Info->GetRandomUpgradeTagForAbility(Tag0);
            UpgradeTag1 = Info->GetRandomUpgradeTagForAbility(Tag1);
            UpgradeTag2 = Info->GetRandomUpgradeTagForAbility(Tag2);

            CurrentAttempt++;

            if (CurrentAttempt > 10)
                break;
        }
        RandomUpgradeTags.Add(UpgradeTag0);
        RandomUpgradeTags.Add(UpgradeTag1);
        RandomUpgradeTags.Add(UpgradeTag2);
        
        // AuraGameModeBase에서 바인딩
        OnRandomUpgradeTagsGeneratedDelegate.Broadcast(this, RandomUpgradeTags);
    }
    return RandomUpgradeTags;
}

 

 

(3-1) 활성화 된 어빌리티 중 랜덤으로 세 개의 어빌리티 추출

    const TArray<FGameplayTag> ActivatedAbilityTags = GetAllActiveAbilityTags();
    
    TArray<FGameplayTag> RandomUpgradeTags;
    RandomUpgradeTags.Empty();
    
    // 주어진 어빌리티 태그에 대해 랜덤한 업그레이드 태그 뽑기
    if (UAbilityUpgradeInfo* Info = UAuraAbilitySystemLibrary::GetAbilityUpgradeInfo(this))
    {
        int ActivatedAbilityTagsNum = ActivatedAbilityTags.Num();
        int RandValue0 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);
        int RandValue1 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);
        int RandValue2 = UKismetMathLibrary::RandomIntegerInRange(0, ActivatedAbilityTagsNum-1);

        // 랜덤으로 뽑은 어빌리티 태그는 중복 가능 -> 파이어볼트 업그레이드 2개 노출 가능
        const auto Tag0 = ActivatedAbilityTags[RandValue0];
        const auto Tag1 = ActivatedAbilityTags[RandValue1];
        const auto Tag2 = ActivatedAbilityTags[RandValue2];

랜덤한 인티저 세 개를 이용해 배열에 직접 접근하여 3개의 어빌리티 태그를 추출한다.

 

 

(3-2) 추출한 어빌리티 태그로부터 랜덤한 업그레이드 태그 추출

        FGameplayTag UpgradeTag0;
        FGameplayTag UpgradeTag1;
        FGameplayTag UpgradeTag2;

        // 루프 함수 제한
        int CurrentAttempt = 0;
        
        // 동일한 태그가 없을 때까지 뽑기
        while (UpgradeTag0 == UpgradeTag1 || UpgradeTag1 == UpgradeTag2 || UpgradeTag0 == UpgradeTag2)
        {
            UpgradeTag0 = Info->GetRandomUpgradeTagForAbility(Tag0);
            UpgradeTag1 = Info->GetRandomUpgradeTagForAbility(Tag1);
            UpgradeTag2 = Info->GetRandomUpgradeTagForAbility(Tag2);

            CurrentAttempt++;

            if (CurrentAttempt > 10)
                break;
        }
        RandomUpgradeTags.Add(UpgradeTag0);
        RandomUpgradeTags.Add(UpgradeTag1);
        RandomUpgradeTags.Add(UpgradeTag2);

Info는 업그레이드 정보를 저장하고 있다. 해당 클래스의 함수를 사용하여 주어진 어빌리티 태그에 해당하는 업그레이드를 랜덤하게 추출한다.

 

(3-2-1) AbilityUpgradeInfo 클래스의 GetRandomUpgradeTagForAbility 함수

FGameplayTag UAbilityUpgradeInfo::GetRandomUpgradeTagForAbility(const FGameplayTag& AbilityTag)
{
	auto AuraTags = FAuraGameplayTags::Get();
	
	FAuraAbilityUpgradeInfoArray UpgradeInfoArray = GetUpgradesForAbility(AbilityTag);
	if (UpgradeInfoArray.UpgradeInfos.IsEmpty())
		return AuraTags.Abilities_None;

	int32 ArrayNum = UpgradeInfoArray.UpgradeInfos.Num();
	int32 RandValue = UKismetMathLibrary::RandomIntegerInRange(0, ArrayNum - 1);

	return UpgradeInfoArray.UpgradeInfos[RandValue].UpgradeEffectTag;
}

업그레이드 정보 배열에서 어빌리티 태그를 이용해 사용 가능한 모든 업그레이드를 추출하여 랜덤한 태그를 내보내는 함수이다.

 

 

(3-3) 델리게이트 호출

        
        // AuraGameModeBase에서 바인딩
        OnRandomUpgradeTagsGeneratedDelegate.Broadcast(this, RandomUpgradeTags);
    }
    return RandomUpgradeTags;
}

AuraGameModeBase에서 바인딩하는 델리게이트를 호출하여 세 개의 태그를 전달한다.

 

 

(4) 델리게이트 바인딩

void AAuraGameModeBase::PostLogin(APlayerController* NewPlayer)
{
	Super::PostLogin(NewPlayer);

	if (NewPlayer)
	{
		if (AAuraHUD* AuraHUD = Cast<AAuraHUD>(NewPlayer->GetHUD()))
		{
			// 어빌리티 업그레이드 카드 세팅
			AuraHUD->OnInitializeGameModeDelegate.Broadcast();
			if (AAuraPlayerState* AuraPS = NewPlayer->GetPlayerState<AAuraPlayerState>())
			{
				AuraPS->OnRandomUpgradeTagsGeneratedDelegate.AddDynamic(this, &AAuraGameModeBase::HandleRandomUpgradeTagsGenerated);
				AuraPS->OnPlayerStateInitialized.AddDynamic(this, &AAuraGameModeBase::HandlePlayerStateInitialized);
			}
		}
	}
}

 

 

(4-1) 콜백 함수

void AAuraGameModeBase::HandleRandomUpgradeTagsGenerated(AAuraPlayerState* AuraPS,
	TArray<FGameplayTag>& RandomUpgradeTags)
{
	if (!HasAuthority())
		return;

	if (RandomUpgradeTags.IsEmpty() || RandomUpgradeTags.Num() < 3)
		return;
	
	if (AAuraHUD* AuraHUD = Cast<AAuraHUD>(AuraPS->GetPlayerController()->GetHUD()))
	{
		auto Tag0 = RandomUpgradeTags[0];
		auto Tag1 = RandomUpgradeTags[1];
		auto Tag2 = RandomUpgradeTags[2];
		AuraHUD->ReceivedCardsDelegate.Broadcast(Tag0, Tag1, Tag2);
	}
}

전달 받은 태그를 AuraHUD로 전달하여 카드에 반영한다.

 

AuraHUD에서는 아래 콜백 함수가 호출된다.

void AAuraHUD::HandleRandomAbilityUpgrade(FGameplayTag UpgradeTag0, FGameplayTag UpgradeTag1,
    FGameplayTag UpgradeTag2)
{
    auto* Info = UAuraAbilitySystemLibrary::GetAbilityUpgradeInfo(this);
    if (Info == nullptr)
        return;
    
    auto* CardViewModel_0 = CardSelectionViewModel->GetCardViewModelByIndex(0);
    if (CardViewModel_0)
    {
        auto Upgrade = Info->GetUpgradeInfoForUpgradeTag(UpgradeTag0);
        
        CardViewModel_0->SetUpgradeTag(Upgrade.UpgradeEffectTag);
        CardViewModel_0->SetUpgradeDescription(Upgrade.UpgradeDescription);
        CardViewModel_0->SetUpgradeName(Upgrade.UpgradeName);
        CardViewModel_0->SetUpgradeMaxLevel(Upgrade.UpgradeMaxLevel);

        CardViewModel_0->OnUpgradeTagAssignedDelegate.Broadcast(UpgradeTag0);
    }

    auto* CardViewModel_1 = CardSelectionViewModel->GetCardViewModelByIndex(1);
    if (CardViewModel_1)
    {
        auto Upgrade = Info->GetUpgradeInfoForUpgradeTag(UpgradeTag1);
        
        CardViewModel_1->SetUpgradeTag(Upgrade.UpgradeEffectTag);
        CardViewModel_1->SetUpgradeDescription(Upgrade.UpgradeDescription);
        CardViewModel_1->SetUpgradeName(Upgrade.UpgradeName);
        CardViewModel_1->SetUpgradeMaxLevel(Upgrade.UpgradeMaxLevel);
        
        CardViewModel_1->OnUpgradeTagAssignedDelegate.Broadcast(UpgradeTag1);
    }

    auto* CardViewModel_2 = CardSelectionViewModel->GetCardViewModelByIndex(2);
    if (CardViewModel_2)
    {
        auto Upgrade = Info->GetUpgradeInfoForUpgradeTag(UpgradeTag2);
        
        CardViewModel_2->SetUpgradeTag(Upgrade.UpgradeEffectTag);
        CardViewModel_2->SetUpgradeDescription(Upgrade.UpgradeDescription);
        CardViewModel_2->SetUpgradeName(Upgrade.UpgradeName);
        CardViewModel_2->SetUpgradeMaxLevel(Upgrade.UpgradeMaxLevel);
        
        CardViewModel_2->OnUpgradeTagAssignedDelegate.Broadcast(UpgradeTag2);
    }
}

각 카드의 뷰 모델의 필드 노티파이를 변경하고 태그 할당 완료 델리게이트를 호출한다.

각 카드의 뷰 모델에 태그 할당이 완료되면 배경 색을 바꾸는 함수를 호출한다.

 

 

2. 어빌리티 종류에 따른 카드 배경 색 변화시키기

전달받은 태그를 Matches Tag 함수로 분별하여 배경 색의 틴트를 변경한다.