본문 바로가기
Unreal 게임 개발/Unreal 강의 개인 정리

Attribute Set을 활용한 사망 처리 - GAS

by daisy0461 2025. 8. 25.
		...
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOutOfHealthDeleget);

UCLASS()
class ARENABATTLEGAS_API UABCharacterAttributeSet : public UAttributeSet
{
	...
	UPROPERTY()
	mutable FOutOfHealthDeleget OnOutOfHealth;
	...
	bool bOutOfHealth = false;
};

UABCharacterAttributeSet에 다음과 같이 Delegate를 선언하고 이미 한번 죽었는지 체크하는 bOutOfHealth를 추가한다.

여기서 mutable이 선언자가 있는데 mutable은 const 객체 안에서도 해당 변수는 수정이 가능하다는 의미이다.

 

이는 ASC->GetSet을 통해서 AttributeSet을 들고오면 const로 들고오게 된다.

이때 const로 되어있으면 Delegate 구독도 할 수 없기 때문에 mutable을 사용하여 구독(수정)이 가능하도록 한다.

 

void UABCharacterAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	//여기서 Data는 Effect로 인해서 변화된 데이터이다.
	Super::PostGameplayEffectExecute(Data);

	float MinimumHealth = 0.0f;
	//Health에 직접 접은은 불가능
	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		GAS_LOG(LogABGAS, Warning, TEXT("Direct Health Access : %f"), GetHealth());
		SetHealth(FMath::Clamp(GetHealth(), MinimumHealth, GetMaxHealth()));
	}
	//데미지를 통한 접근 가능.
	else if (Data.EvaluatedData.Attribute == GetDamageAttribute())
	{
		GAS_LOG(LogABGAS, Log, TEXT("Damage : %f"), GetDamage());
		SetHealth(FMath::Clamp(GetHealth()- GetDamage(), MinimumHealth, GetMaxHealth()));
		SetDamage(0.0f);
	}

	if ((GetHealth() <= 0.0f) && !bOutOfHealth)
	{
		//Character.State.IsDead라는 태그를 직접 부착하는 방식이다.
		Data.Target.AddLooseGameplayTag(ABTAG_CHARACTER_ISDEAD);
		OnOutOfHealth.Broadcast();
	}

	bOutOfHealth = (GetHealth() <= 0.0f);
}

그리고 Health를 처리하는 PostGameplayEffectExecute에서 사망했는지 확인하고
AddLooseGameplayTag를 통해 사망태그 (Character.State.IsDead)를 추가해준다.

그리고 Delegate를 Broadcast한다.

 

//NPC
AttributeSet->OnOutOfHealth.AddDynamic(this, &AABGASCharacterNonPlayer::OnOutOfHealth);
-----------------------------------------------------------
//Player
//PlayerState에서 ASC를 들고와서 PlayerState에 있는 ASC를 Player 캐릭터 ASC에 넣어준다.
ASC = GASPS->GetAbilitySystemComponent();
//위 단계에서 OwnerActor는 PlayerState로 AvatarActor는 Player 캐릭터로 정해졌다.
//이제 ASC 초기화를 해주면 된다.
//첫번째 인자는 OwnerActor, 두번째 인자는 AvatarActor를 넣어주면 된다.
ASC->InitAbilityActorInfo(GASPS, this);

const UABCharacterAttributeSet* CurrentAttributeSet = ASC->GetSet<UABCharacterAttributeSet>();
if (CurrentAttributeSet)
{
    CurrentAttributeSet->OnOutOfHealth.AddDynamic(this, &ThisClass::OnOutOfHealth);
}

NPC는 직접 AttributeSet을 들고 있기 때문에 GetSet을 할 필요 없이 직접 Bind하면 되고

Player는 PlayerState가 ASC를 가지고 있기 때문에 

PlayerState에서 ASC를 가져와 캐싱을 하고 해당 ASC에서 GetSet을 통해 AttributeSet을 가져온 후에

OnOutOfHealth와 바인딩하여 사망 처리를 한다.