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