[UE5] 데미지 타입별 플레이어 피격 구현

연하·2024년 8월 21일
0

Trapper

목록 보기
30/32
post-thumbnail

오늘은 데미지의 종류에 따라 캐릭터가 다르게 반응하도록 구현하려고 한다. 기획서에 명시되어 있는 데미지의 종류는 다운, 넉백, 스턴, 슬로우, 약공격, 강공격이 있다.

데미지 타입 클래스 만들기

데미지 타입의 클래스를 이용해 구분하므로, DamageType을 상속받은 클래스를 먼저 만들어주었다. '클래스'만 필요하기 때문에, 코드의 선언부와 구현부는 모두 비워놓았다.

약공격과 강공격은 데미지의 세기에 따라 후순위로 분류되므로, 일반 데미지타입이 들어왔을 때 적용하도록 하고 특수한 데미지 타입만 만들어주었다.

TakeDamage() 함수에 데미지 타입 판별 코드 구현

기존에 데미지를 처리하는 멀티캐스트 RPC 함수가 데미지 이벤트를 받도록 수정해주고, 타입을 판별해 로그를 출력하도록 만들었다.

// 데미지 타입별 처리
const UDamageType* DamageType = DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>();

if (DamageType->IsA<UDamageTypeDown>())
{
	UE_LOG(LogTemp, Warning, TEXT("Damage Type : Down"));
}
else if (DamageType->IsA<UDamageTypeStun>())
{
	UE_LOG(LogTemp, Warning, TEXT("Damage Type : Stun"));
}
else if (DamageType->IsA<UDamageTypeKnockBack>())
{
	UE_LOG(LogTemp, Warning, TEXT("Damage Type : Knock Back"));
}
else if (DamageType->IsA<UDamageTypeSlow>())
{
	UE_LOG(LogTemp, Warning, TEXT("Damage Type : Slow"));
}
else
{
	// 우선 수치는 하드코딩 -> 추후 데이터 테이블로 뺄 것
	if (Damage < 70)
	{
		UE_LOG(LogTemp, Warning, TEXT("Damage Type : Light Attack"));
	}
	else
	{			
    	UE_LOG(LogTemp, Warning, TEXT("Damage Type : Heavy Attack"));
	}
}

테스트 환경 만들기

콜리전 박스를 가지고 있는 액터를 하나 만들어주고, 투명한 머테리얼을 가진 메시와 텍스트 렌더러를 달아준 뒤, 데미지 타입을 스트링으로 받도록 변수를 하나 만들어주었다.

게임이 시작되면 텍스트 렌더러에 입력한 스트링으로 바꿔주는 코드를 넣고,

받은 스트링에 따라 데미지를 주도록 노드를 구성했다. 다소 복잡하지만... 각기 다른 클래스를 넣어주어야 해서 어쩔수 없었다...ㅎㅎ

테스트 레벨에 배치해주고 실행하면,

이렇게 설정해준 클래스 타입별로 로그가 잘 찍히는 것을 볼 수 있다.

Slow 데미지 타입이 빠지게 되어 Slow 관련 클래스와 테스트 액터를 삭제해주었다.

몽타주 수정

기획서에 명시되어 있는 애니메이션 에셋을 리타게팅 해준 후, 기존 TakeDamage 몽타주에 섹션을 나누어 넣어주었다.

몽타주 재생

void ATrapperPlayer::MulticastRPCCharacterAlive_Implementation(float Damage, FDamageEvent const& DamageEvent, AActor* DamageCauser)
{
	IsDamaged = true;

	if (IsValid(DamageCauser) && DamageCauser->ActorHasTag("NoCharacterHitAnimationTrap"))
	{
		return;
	}

	GetCharacterMovement()->SetMovementMode(MOVE_None);

	UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
	if (!IsValid(AnimInstance) && !IsValid(DamagedAnimationMontage))
	{
		return;
	}

	// 몽타주 재생
	AnimInstance->Montage_Play(DamagedAnimationMontage, 1.0);

	// 데미지 타입별 애니메이션 섹션 이동
	const UDamageType* DamageType = DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>();

	if (DamageType->IsA<UDamageTypeDown>())
	{
		AnimInstance->Montage_JumpToSection(FName("Down"), DamagedAnimationMontage);
	}
	else if (DamageType->IsA<UDamageTypeStun>())
	{
		AnimInstance->Montage_JumpToSection(FName("StunStart"), DamagedAnimationMontage);
	}
	else if (DamageType->IsA<UDamageTypeKnockBack>())
	{
		AnimInstance->Montage_JumpToSection(FName("KnockBack"), DamagedAnimationMontage);
	}
	else
	{
		if (Damage < 70)
		{
			AnimInstance->Montage_JumpToSection(FName("Light"), DamagedAnimationMontage);
		}
		else
		{
			AnimInstance->Montage_JumpToSection(FName("Heavy"), DamagedAnimationMontage);
		}
	}

	// 몽타주 끝났을 때 델리게이트 바인딩
	FOnMontageEnded EndDelegate;
	EndDelegate.BindUObject(this, &ATrapperPlayer::DamagedEnd);
	AnimInstance->Montage_SetEndDelegate(EndDelegate, DamagedAnimationMontage);
}

몽타주를 재생한 뒤, 데미지 타입별로 애니메이션 섹션을 바꿔주는 식으로 코드를 구현하였다.

이제 데미지 타입별로 몽타주가 재생되는 것을 볼 수 있다 :)

0개의 댓글