1. 속성 저항 태그 생성 및 데미지 계산식 수정

(1) AuraGameplayTags - Native 게임플레이 태그 생성

속성 저항을 도입하기 위해 새로운 태그를 생성한다.

새로운 속성 타입을 생성한다.

	FGameplayTag Attributes_Resistance_Fire;
	FGameplayTag Attributes_Resistance_Arcane;
	FGameplayTag Attributes_Resistance_Lightning;
	FGameplayTag Attributes_Resistance_Physical;

	// 데미지
	FGameplayTag Damage;
	FGameplayTag Damage_Fire;
	FGameplayTag Damage_Lightning;
	FGameplayTag Damage_Arcane;
	FGameplayTag Damage_Physical;

	TMap<FGameplayTag, FGameplayTag> DamageTypesToResistances;
	// 데미지 타입
	GameplayTags.Damage_Fire = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Damage.Fire"),
		FString("Fire Damage Type")
	);

	GameplayTags.Damage_Lightning = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Damage.Lightning"),
		FString("Lightning Damage Type")
	);

	GameplayTags.Damage_Arcane = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Damage.Arcane"),
		FString("Arcane Damage Type")
	);

	GameplayTags.Damage_Physical = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Damage.Physical"),
		FString("Physical Damage Type")
	);

	// 저항
	GameplayTags.Attributes_Resistance_Fire = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Attributes.Resistance.Fire"),
		FString("Fire Resistance")
	);

	GameplayTags.Attributes_Resistance_Lightning = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Attributes.Resistance.Lightning"),
		FString("Lightning Resistance")
	);

	GameplayTags.Attributes_Resistance_Arcane = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Attributes.Resistance.Arcane"),
		FString("Arcane Resistance")
	);

	GameplayTags.Attributes_Resistance_Physical = UGameplayTagsManager::Get().AddNativeGameplayTag(
		FName("Attributes.Resistance.Physical"),
		FString("Physical Resistance")
	);

	// 데미지 타입과 저항 연결
	GameplayTags.DamageTypesToResistances.Add(GameplayTags.Damage_Fire, GameplayTags.Attributes_Resistance_Fire);
	GameplayTags.DamageTypesToResistances.Add(GameplayTags.Damage_Lightning, GameplayTags.Attributes_Resistance_Lightning);
	GameplayTags.DamageTypesToResistances.Add(GameplayTags.Damage_Arcane, GameplayTags.Attributes_Resistance_Arcane);
	GameplayTags.DamageTypesToResistances.Add(GameplayTags.Damage_Physical, GameplayTags.Attributes_Resistance_Physical);

기존의 Array를 대체하여 각 속성 타입에 대해 속성 저항을 값으로 갖는 TMap을 갖게 될것이다.

 

 

(2) ExecCalc_Damage - 데미지 계산식 수정

	// Set by Caller Magnitude 가져오기
	float Damage = 0.f;
	for (auto& Pair : FAuraGameplayTags::Get().DamageTypesToResistances)
	{
		const float DamageTypeValue = Spec.GetSetByCallerMagnitude(Pair.Key);
		Damage += DamageTypeValue;
	}

 

 

2. AuraAttributeSet 속성 세트에 속성으로 추가하기

이전까지의 작업은 속성 저항에 대한 데미지 계산과 Native 게임플레이 태그 생성이다.

이제 속성으로 추가한다.

 

(1) 헤더 파일

/*
* Secondary 속성 - 속성 저항
*/
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_FireResistance, Category = "Resistances Attributes")
FGameplayAttributeData FireResistance;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet, FireResistance);

UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_LightningResistance, Category = "Resistances Attributes")
FGameplayAttributeData LightningResistance;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet, LightningResistance);

UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArcaneResistance, Category = "Resistances Attributes")
FGameplayAttributeData ArcaneResistance;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArcaneResistance);

UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_PhysicalResistance, Category = "Resistances Attributes")
FGameplayAttributeData PhysicalResistance;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet, PhysicalResistance);

각 저항에 대한 Getter, Setter를 선언하는 매크로를 추가하고 블루프린트에서 불러들일 수 있도록 속성 데이터를 생성한다.

그리고 ReplicatedUsing 인수를 사용하여 복제가 발생하면 해당 함수를 호출하도록 지정한다.

	UFUNCTION()
	void OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const;
	
	UFUNCTION()
	void OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const;
	
	UFUNCTION()
	void OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const;
	
	UFUNCTION()
	void OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const;

 

 

(2) 생성자

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);

    // 속성 저항
    TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Fire, GetFireResistanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Lightning, GetLightningResistanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Arcane, GetArcaneResistanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Physical, GetPhysicalResistanceAttribute);
}

생성했던 Native 태그를 속성으로 추가할 것이다.

TMap<FGameplayTag, TStaticFuncPtr<FGameplayAttribute()>> TagsToAttributes;

위의 맵에 키-값 쌍이 태그-함수 포인터 쌍으로 되도록 지정한다.

 

 

(3) GetLifeTimeReplicatedProps 함수

    // 속성 저항
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, FireResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, LightningResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ArcaneResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, PhysicalResistance, COND_None, REPNOTIFY_Always);
}

새롭게 생성한 저항 속성들에 대해 복제가 항상 일어나도록 지정한다.

 

 

(4) 복제 발생 시 작동하는 콜백 함수

void UAuraAttributeSet::OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, FireResistance, OldFireResistance);
}

void UAuraAttributeSet::OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, LightningResistance, OldLightningResistance);
}

void UAuraAttributeSet::OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArcaneResistance, OldArcaneResistance);
}

void UAuraAttributeSet::OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, PhysicalResistance, OldPhysicalResistance);
}

복제가 발생하여 각 속성 값이 변경되면 위의 함수가 발동되며, 속성 세트에 대해 값이 변경된다.

 

 

3. 속성 메뉴 위젯에 속성 저항 값 추가하기

(1) BP_AttributeMenuWidgetController - 속성 메뉴 위젯 컨트롤러

이 위젯 컨트롤러는 DA_AttributeInfo 데이터 에셋을 가지고 속성 값을 위젯으로 전송하고 있다.

 

(1-2) DA_AttributeInfo 데이터 에셋

이전에 추가한 속성 저항 Attributes에 대하여 값을 추가한다.

 

 

(2) WBP_AttributeMenu

속성 값을 가져와 표기할 줄을 추가한다.

해당 Row에 대해 변수로 사용을 체크한다.

Set Attribute Tags 함수에 대해서 각 행에 태그를 가져와 값을 설정하는 노드를 연결한다.

올바르게 연결되었다면 위처럼 나타날 것이다.

 

 

(3) GE_SecondaryAttributes 에 수정자 추가

이제 캐릭터에 속성 저항을 부여하기 위해 게임플레이 이펙트를 수정한다.

모든 속성 저항은 Resilience를 따라 설정되도록 한다.