0. 개요

이전 포스트에서 속성 값을 기반으로 어떤 속성을 변경하는 방법을 배웠다.

 

6-3. 게임플레이 이펙트 - 속성 기반 수정자(Attribute Based Modifier)

0. 개요속성을 효과적으로 변경할 수 있는 게임플레이 이펙트의 수정자 옵션 중 하나인 Attribute Based에 대해 알아본다.  1. 속성 기반 수정자(Attribute Based Modifier) (1) 기본 속성(Backing Attribute)- 캡

crat.tistory.com

이제 기본 속성(1차 속성, Primary Attributes)의 영향을 받는 2차 속성(보조 속성, Secondary Attributes)에 대해 배워본다.


- 파생된 속성(Derived Attributes)

다른 속성의 영향을 받는 속성을 말한다.

2차 속성은 모두 파생된 속성이다.


 

 

1. 2차 속성(Secondary Attributes)

(1) 정의

1차 속성의 영향을 받는 것은 물론, 다른 2차 속성의 영향을 받는 속성들도 파생된 속성(Derived Attributes)로 정의한다.

 

 

(2) 코드

AuraAttributeSet에 Secondary Attributes를 추가한다.

이제 MaxHealth와 MaxMana는 Primary Attributes가 아닌 Secondary Attributes 이다.

 

 

(2-1) 2차 속성 추가

	/*
	* Secondary 속성
	*/

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Secondary Attributes")
	FGameplayAttributeData MaxHealth;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxHealth);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxMana, Category = "Secondary Attributes")
	FGameplayAttributeData MaxMana;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxMana);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Armor, Category = "Secondary Attributes")
	FGameplayAttributeData Armor;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Armor);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArmorPenetration, Category = "Secondary Attributes")
	FGameplayAttributeData ArmorPenetration;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArmorPenetration);
	
	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_BlockChance, Category = "Secondary Attributes")
	FGameplayAttributeData BlockChance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, BlockChance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitChance, Category = "Secondary Attributes")
	FGameplayAttributeData CriticalHitChance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitChance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitDamage, Category = "Secondary Attributes")
	FGameplayAttributeData CriticalHitDamage;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitDamage);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitResistance, Category = "Secondary Attributes")
	FGameplayAttributeData CriticalHitResistance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitResistance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_HealthRegeneration, Category = "Secondary Attributes")
	FGameplayAttributeData HealthRegeneration;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, HealthRegeneration);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ManaRegeneration, Category = "Secondary Attributes")
	FGameplayAttributeData ManaRegeneration;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ManaRegeneration);

 

 

(2-2) OnReplication 노티파이 추가

	UFUNCTION()
	void OnRep_Strength(const FGameplayAttributeData& OldStrength) const;

	UFUNCTION()
	void OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const;

	UFUNCTION()
	void OnRep_Resilience(const FGameplayAttributeData& OldResilience) const;

	UFUNCTION()
	void OnRep_Vigor(const FGameplayAttributeData& OldVigor) const;

	UFUNCTION()
	void OnRep_Armor(const FGameplayAttributeData& OldArmor) const;

	UFUNCTION()
	void OnRep_ArmorPanetration(const FGameplayAttributeData& OldArmorPanetration) const;

	UFUNCTION()
	void OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const;

	UFUNCTION()
	void OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const;

	UFUNCTION()
	void OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const;

	UFUNCTION()
	void OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const;

	UFUNCTION()
	void OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const;

	UFUNCTION()
	void OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const;
void UAuraAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldArmor) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Armor, OldArmor);
}

void UAuraAttributeSet::OnRep_ArmorPanetration(const FGameplayAttributeData& OldArmorPenetration) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArmorPenetration, OldArmorPenetration);
}

void UAuraAttributeSet::OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, BlockChance, OldBlockChance);
}

void UAuraAttributeSet::OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitChance, OldCriticalHitChance);
}

void UAuraAttributeSet::OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitDamage, OldCriticalHitDamage);
}

void UAuraAttributeSet::OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitResistance, OldCriticalHitResistance);
}

void UAuraAttributeSet::OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, HealthRegeneration, OldHealthRegeneration);
}

void UAuraAttributeSet::OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const
{
    // Notify 매크로
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ManaRegeneration, OldManaRegeneration);
}

 

 

(2-3) 노티파이 컨디션 추가

void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const 
{
    // 복제할 때 반드시 오버라이드하여 사용해야 함
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // 조건 노티파이 - 복제된 속성에 사용, 조건 없음, 항상 복제(REPNOTIFY_OnChanged : 변화할 때만 복제)
    // Primary 속성
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Strength, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Resilience, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Vigor, COND_None, REPNOTIFY_Always);

    // Vital 속성
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Health, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Mana, COND_None, REPNOTIFY_Always);

    // Secondary 속성
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Armor, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, BlockChance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitChance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitDamage, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, HealthRegeneration, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ManaRegeneration, COND_None, REPNOTIFY_Always);
}

 

 

2. 2차 속성 초기화

(1) 게임플레이 이펙트로 2차 속성 초기화하기 - AuraCharacterBase

 

6-2. 게임플레이 이펙트로 속성 값 초기화

0. 개요이전 포스트에서 데이터 테이블로 속성 값을 초기화 하는 방법을 사용했다.그러나 이 것은 아직 미완성인 방법이고 덜 대중적인 방법이다.따라서 더 대중적인 방법으로, 게임플레이가 시

crat.tistory.com

이전 포스트에서 게임플레이 이펙트를 이용하여 1차 속성 값을 초기화 했던 것과 같이 2차 속성도 초기화 할 것이다.


- 주의사항

2차 속성은 1차 속성의 영향을 받기 때문에 반드시 1차 속성이 초기화 된 후에 초기화되어야 한다.


 

(2) 기존 속성 초기화 함수 리펙토링

기존에 Primary Attributes를 초기화하던 로직을 그대로 Secondary Attributes에 적용함은 물론, 추후에 추가될 수 있는 다른 속성들을 위해 기존 함수를 범용성 있는 함수로 리펙토링한다.

	void ApplyEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level) const;
	void InitializeDefaultAttributes() const;

 

void AAuraCharacterBase::ApplyEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level) const
{
	check(IsValid(GetAbilitySystemComponent()));
	check(GameplayEffectClass);

	// 컨텍스트 핸들
	FGameplayEffectContextHandle ContextHandle = GetAbilitySystemComponent()->MakeEffectContext();

	// 스펙 핸들
	FGameplayEffectSpecHandle SpecHandle = GetAbilitySystemComponent()->MakeOutgoingSpec(GameplayEffectClass, Level, ContextHandle);

	// 게임플레이 이펙트를 타겟에게 적용함
	GetAbilitySystemComponent()->ApplyGameplayEffectSpecToTarget(*SpecHandle.Data.Get(), GetAbilitySystemComponent());
}

void AAuraCharacterBase::InitializeDefaultAttributes() const
{
	ApplyEffectToSelf(DefaultPrimaryAttributes, 1.f);
	ApplyEffectToSelf(DefaultSecondaryAttributes, 1.f);
}

 

이후 AuraCharacter에서 호출한 함수를 변경한다.

void AAuraCharacter::InitAbilityActorInfo()
{
   //~~~~~~~~~~~
    InitializeDefaultAttributes();
}

 

 

3. 게임플레이 이펙트 생성하기

(1) BP_AuraCharacter에 기본 2차 속성 클래스를 지정하기

 

 

(2) 게임플레이 이펙트 생성하기

이제 초기값으로 초기화하기 위한 게임플레이 이펙트를 생성한다.

2차 속성은 항상 적용되는 효과이므로 지속 정책(Duration Policy)을 Infinite로 지정한다.

아래 포스트를 참고하여 계산식을 적용한다.

 

6-3. 게임플레이 이펙트 - 속성 기반 수정자(Attribute Based Modifier)

0. 개요속성을 효과적으로 변경할 수 있는 게임플레이 이펙트의 수정자 옵션 중 하나인 Attribute Based에 대해 알아본다.  1. 속성 기반 수정자(Attribute Based Modifier) (1) 기본 속성(Backing Attribute)- 캡

crat.tistory.com