PART 2 - 강의 3/3

Meta Attributes

데미지 파이프라인과 임시 계산 값 관리

01

Meta Attribute란?

중간 계산용 임시 어트리뷰트

Meta Attributes는 UI에 노출되지 않고, 네트워크로 복제되지 않는 임시 어트리뷰트입니다. 복잡한 계산의 중간 값을 저장하고, 버프/디버프 적용 후 최종 값을 도출하는 데 사용됩니다.

Meta Attribute 특징
  • 복제 안 함 - 네트워크 대역폭 절약
  • UI 노출 안 함 - 내부 계산용
  • PostGameplayEffectExecute에서 처리 - 최종 변환
  • 처리 후 0으로 리셋 - 다음 사용 대비
02

데미지 파이프라인 구현

Damage -> Health 변환 흐름

데미지 Meta Attribute 정의 UCLASS() class UDamageAttributeSet : public UAttributeSet { GENERATED_BODY() public: // Meta Attributes - 복제되지 않음! // Replicated 지정자 없음 // 입력 데미지 (버프/디버프 적용 전) UPROPERTY(BlueprintReadOnly, Category = "Damage") FGameplayAttributeData IncomingDamage; ATTRIBUTE_ACCESSORS(UDamageAttributeSet, IncomingDamage) // 크리티컬 배율 UPROPERTY(BlueprintReadOnly, Category = "Damage") FGameplayAttributeData CriticalMultiplier; ATTRIBUTE_ACCESSORS(UDamageAttributeSet, CriticalMultiplier) // 최종 데미지 (계산 후) UPROPERTY(BlueprintReadOnly, Category = "Damage") FGameplayAttributeData FinalDamage; ATTRIBUTE_ACCESSORS(UDamageAttributeSet, FinalDamage) };
데미지 파이프라인 처리 void UDamageAttributeSet::PostGameplayEffectExecute( const FGameplayEffectModCallbackData& Data) { Super::PostGameplayEffectExecute(Data); if (Data.EvaluatedData.Attribute == GetIncomingDamageAttribute()) { float Damage = GetIncomingDamage(); // 1. 크리티컬 적용 if (GetCriticalMultiplier() > 1.0f) { Damage *= GetCriticalMultiplier(); } // 2. 방어력 감소 적용 float Armor = GetArmor(); float DamageReduction = Armor / (Armor + 100.f); Damage *= (1.f - DamageReduction); // 3. 최소 데미지 보장 Damage = FMath::Max(Damage, 1.f); // 4. FinalDamage에 저장 SetFinalDamage(Damage); // 5. Meta Attribute 리셋 SetIncomingDamage(0.f); SetCriticalMultiplier(1.0f); // 6. 실제 Health 감소 float NewHealth = GetHealth() - Damage; SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth())); } }
03

힐링 파이프라인

Healing -> Health 변환

힐링 처리 // Healing Meta Attribute UPROPERTY(BlueprintReadOnly, Category = "Healing") FGameplayAttributeData IncomingHealing; ATTRIBUTE_ACCESSORS(UMyAttributeSet, IncomingHealing) // PostGameplayEffectExecute에서 처리 if (Data.EvaluatedData.Attribute == GetIncomingHealingAttribute()) { const float LocalHealing = GetIncomingHealing(); SetIncomingHealing(0.f); // 리셋 if (LocalHealing > 0.f) { // 힐링 효율 버프 적용 (예: 1.2배) float HealingEfficiency = GetHealingEfficiency(); float ActualHealing = LocalHealing * HealingEfficiency; // Health 회복 const float NewHealth = GetHealth() + ActualHealing; SetHealth(FMath::Clamp(NewHealth, 0.0f, GetMaxHealth())); // 오버힐 처리 (선택적) float OverHeal = NewHealth - GetMaxHealth(); if (OverHeal > 0.f) { // 오버힐을 쉴드로 변환 등 } } }
04

Meta Attribute 사용 패턴

복잡한 계산을 단계별로 분리

어빌리티에서 Meta Attribute 설정 void UGA_MeleeAttack::OnHitTarget(AActor* Target) { // Damage Effect Spec 생성 FGameplayEffectSpecHandle DamageSpec = MakeOutgoingGameplayEffectSpec( DamageEffectClass, GetAbilityLevel()); // SetByCaller로 데미지 값 설정 DamageSpec.Data->SetSetByCallerMagnitude( FGameplayTag::RequestGameplayTag(FName("Data.Damage.Base")), CalculateBaseDamage()); // 크리티컬 확률 체크 if (FMath::FRand() < GetCriticalChance()) { DamageSpec.Data->SetSetByCallerMagnitude( FGameplayTag::RequestGameplayTag(FName("Data.Damage.CritMult")), 2.0f); // 크리티컬 배율 } // 타겟에 적용 ApplyGameplayEffectSpecToTarget(...); } // DamageEffect Blueprint에서: // Modifier: IncomingDamage = SetByCaller("Data.Damage.Base") // Modifier: CriticalMultiplier = SetByCaller("Data.Damage.CritMult")

장점 1: 모듈화

데미지 계산 로직을 AttributeSet에 집중시켜 유지보수 용이

장점 2: 버프 적용

Meta Attribute에 Duration GE로 배율 버프 가능

장점 3: 디버깅

각 단계별 값을 명확히 추적 가능

SUMMARY

핵심 요약

  • Meta Attribute: 복제되지 않는 임시 계산용 어트리뷰트
  • 데미지 파이프라인: IncomingDamage -> 버프/방어 적용 -> FinalDamage -> Health
  • PostGameplayEffectExecute에서 변환 로직 처리
  • 처리 후 반드시 0으로 리셋
  • SetByCaller로 어빌리티에서 값 전달
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: Meta Attribute 데미지 시스템

IncomingDamage Meta Attribute를 선언하고 PostGameplayEffectExecute에서 방어력 계산 후 최종 Health 감소를 적용하세요. IncomingDamage는 0으로 리셋하세요.

실습 2: IncomingHealing 구현

IncomingHealing Meta Attribute를 추가하고, 힐 증가/감소 버프 적용 후 최종 힐량을 Health에 적용하세요. MaxHealth 초과 방지 클램핑도 구현하세요.

심화 과제

undefined