0. 개요

이전 포스트에서 맵 컨테이너와 함수 포인터를 사용하여 속성 메뉴에 속성 초기 값을 표시하도록 설정했다.

이제 속성 값이 변화하면 변화된 값이 UI에 반영되도록 한다.

 

 

1. 속성 값 변화 델리게이트에 람다 함수 바인딩 - AttributeMenuWidgetController 클래스

어빌리티 시스템 컴포넌트에는 속성 값이 변화되면 호출되는 델리게이트인 GameplayAttributeValueChange 델리게이트가 있다.

해당 델리게이트에 속성을 인자로 넘겨 해당 속성의 값 변화를 가져올 수 있다.

 

(1) 코드

void UAttributeMenuWidgetController::BindCallbacksToDependencies()
{
	UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet);
	for (auto& Pair : AS->TagsToAttributes)
	{
		AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
			[this, Pair, AS](const FOnAttributeChangeData& Data)
			{
				// 키를 이용하여 캐릭터의 속성 정보를 꺼내기
				FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
				Info.AttributeValue = Pair.Value().GetNumericValue(AS);
				
				// 속성 정보 브로드캐스트
				AttributeInfoDelegate.Broadcast(Info);
			}
		);
	}
}

 

 

(2) 람다 문법

속성 값 변화 델리게이트에 람다 함수를 바인딩할 때의 람다 문법에 대해서 자세히 살펴본다.

 

- AttributeInfo는 속성 메뉴 위젯 컨트롤러의 멤버 변수이므로 this(속성 메뉴 위젯 컨트롤러 클래스)를 캡쳐한다.

- for 루프에서 Pair의 키-값의 유효성을 보장하기 위해 해당 값을 복사하여 사용해야 하므로 Pair를 캡쳐한다.

- AttributeInfo에 Pair의 값 자체를 가져오기 위해 AttributeSet를 인자로 넘겨야하므로 AS를 캡쳐한다.

(람다 함수 밖의 요소를 사용하기 위해서는 캡쳐가 필수)

 

 

2. 2차 속성 매핑

(1) 코드

UAuraAttributeSet::UAuraAttributeSet()
{
    const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();
    
    // 주 속성
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Resilience, GetResilienceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Vigor, GetVigorAttribute);

    // 2차 속성
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_Armor, GetArmorAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ArmorPanetration, GetArmorPenetrationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_BlockChance, GetBlockChanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitChance, GetCriticalHitChanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitDamage, GetCriticalHitDamageAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitResistance, GetCriticalHitResistanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_HealthRegeneration, GetHealthRegenerationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ManaRegeneration, GetManaRegenerationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxHealth, GetMaxHealthAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxMana, GetMaxManaAttribute);
}

 

 

3. 리팩토링(Refactorying) - 함수 추출(Function Extraction)

함수 추출은 리팩토링의 한 단계로써 반복, 재사용되는 코드를 함수로 추출하여 코드의 가독성을 높이는 과정이다.

 

(1) 속성 정보 브로드캐스트 함수 - BroadCastAttributeInfo 함수

void UAttributeMenuWidgetController::BroadCastAttributeInfo(const FGameplayTag& GameplayTag, const FGameplayAttribute& Attribute)
{
	// 키를 이용하여 캐릭터의 속성 정보를 꺼내기
	FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(GameplayTag);
	Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);

	// 속성 정보 브로드캐스트
	AttributeInfoDelegate.Broadcast(Info);
}

 

 

(2) 기존 함수 코드 수정

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
	UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet);
	check(AttributeInfo);

	for (auto& Pair : AS->TagsToAttributes)
	{
		BroadCastAttributeInfo(Pair.Key, Pair.Value());
	}
}

void UAttributeMenuWidgetController::BindCallbacksToDependencies()
{
	// 속성 세트 가져오기
	UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet);
	check(AttributeInfo);

	for (auto& Pair : AS->TagsToAttributes)
	{
		AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
			[this, Pair](const FOnAttributeChangeData& Data)
			{
				BroadCastAttributeInfo(Pair.Key, Pair.Value());
			}
		);
	}
}