언리얼 C++ 게임 개발의 정석/8. 충돌 설정과 대미지 전달

8.2 디버그 드로잉 및 대미지 프레임 워크

ftftgop3 2024. 4. 8. 20:42

디버그 드로잉

공격 범위를 시각적으로 표현 해 드버그에 효과적인 기능 

 

ABCharacter.h

어택 거리 및 범위 변수 추가

UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
	GENERATED_BODY()
    private:
	UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
		float AttackRange; //거리

	UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
		float AttackRadius;//범위
}

ABCharacter.cpp

DrawDebugHelpers.h 헤더 추가

#include "DrawDebugHelpers.h"

AABCharacter::AABCharacter()
{
	AttackRange = 200.0f;
	AttackRadius = 50.0f;
}


void AABCharacter::AttackCheck()
{
	FHitResult HitResult;
	//자기 자신은 감지 되면 안되니 this로 무시 설정
	FCollisionQueryParams Params(NAME_None, false, this);

	bool bResult = GetWorld()->SweepSingleByChannel(
		HitResult, //결과 구조체
		GetActorLocation(), //시작 위치
		GetActorLocation() + GetActorForwardVector() * 200.0f, //끝 위치
		FQuat::Identity, //회전 값
		ECollisionChannel::ECC_GameTraceChannel2, // Attack 채널 값
		FCollisionShape::MakeSphere(50.0f), //캡슐 크기 50 생성 
		Params);

	#if ENABLE_DRAW_DEBUG
	FVector TraceVec = GetActorForwardVector() * AttackRange;//끝 지점 벡터
	FVector Center = GetActorLocation() + TraceVec * 0.5f;//중간 점
	float HalfHeight = AttackRange * 0.5f + AttackRadius;//캡슐의 높이
	FQuat CapsuleRot = FRotationMatrix::MakeFromZ(TraceVec).ToQuat();//캐릭터가 바라보는 방향으로 Z 값 회전
	FColor DrawColor = bResult ? FColor::Green : FColor::Red;
	float DebugLifeTime = 5.0f;

	DrawDebugCapsule(GetWorld(),
		Center,
		HalfHeight,
		AttackRadius,
		CapsuleRot,
		DrawColor,
		false,
		DebugLifeTime);

#endif
	if (bResult)
	{
		//가비지 컬렉션 때문에 참조 문제가 생길 수 있어서 약 포인트 지정, 
		//Isvalid 로 액터 유효 확인
		if (HitResult.Actor.IsValid())
		{
			ABLOG(Warning, TEXT("Hit Actor Name: %s"), *HitResult.Actor->GetName());
		}
	}
	
}

 

대미지 프레임 워크

언리얼 에진에서 제공하는 대미지 프레임 워크 사용

AActer 의 TakeDamage 라는 함수 사용

 

네개의 인자 사용

DamageAmount: 대미지 의 세기

DamageEvent : 대미지 종류

EventInstigator : 공격 명령의 가해자

DamageCauser : 대미지 전달의 위한 사용자 도구

 

가해자를 폰이 아닌 플레이어 컨트롤러로 설정,  플레이어가 컨트롤 해서 대미지 가함

Acter can be Damaged 속성을 false 변경 시 모든 대미지 값은 0으로 고정 ( 무적 상태)

 

TakeDamage() Override 후 재정의

{
    public:
    virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent,
		class AController* EventInstigator, AActor* DamageCauser) override;
}
    
float AABCharacter::TakeDamage(float DamageAmount, FDamageEvent const & DamageEvent,
AController * EventInstigator, AActor * DamageCauser)
{
	float FinalDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator,
    DamageCauser);
	ABLOG(Warning, TEXT("Actor : %s took Damage : %f"), *GetName(), FinalDamage);
	return FinalDamage;
}

 

죽는 애니메이션 추가 

ABAnimInstance 에 IsDead 변수 추가

각 애니메이션 실행 함수에서 IsDead 값을 체크해 동작 막기

class ARENABATTLE_API UABAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
    public:
    void SetDeadAnim() { IsDead = true; }
    
    private:
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Pawn, Meta = (AllowPrivateAccess = true))
		bool IsDead;
 }
 
 UABAnimInstance::UABAnimInstance()
 {
 		IsDead = false;
 }
 //애닝 인스턴스에서 상속 받은 NativeUpdateAnimation 사용, Tick 보다 뒤에 실행
void UABAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);
	//현재 Pawn에 접근, 컨트롤러가 조종하는 Pawn 리턴
	auto Pawn = TryGetPawnOwner();
	if (!::IsValid(Pawn))
		return;

	
	if (!IsDead)
	{
		//속도 값을 가지고 온다
		CurrentPawnSpeed = Pawn->GetVelocity().Size();
		auto Character = Cast<ACharacter>(Pawn);
		if (Character)
		{
			//character의 movementcomponent 의 Isfalling() 호출
			IsInAir = Character->GetMovementComponent()->IsFalling();
		}
	}
}

void UABAnimInstance::PlayAttackMontage()
{
	ABCHECK(!IsDead);
	Montage_Play(AttackMontage, 1.0f);
}

void UABAnimInstance::JumpToAttackMontageSection(int32 NewSection)
{
	//현재 몽타주 실행 중 인지 체크
	//ABCHECK(Montage_IsPlaying(AttackMontage));
	ABCHECK(!IsDead);
	if (Montage_IsPlaying(AttackMontage))
		//해당 몽타주의 NewSection 섹션으로 실행
		Montage_JumpToSection(GetAttackMontageSectionName(NewSection), AttackMontage);
	else
		ABLOG(Warning, TEXT("AttackMontage"));
}

 

블루 프린트에 죽는 애니메이션 추가

bool 블린더 노드 추가

Isdead 변수를 이용해 true 일 때 죽는 애니메이션 실행 (Loop 옵션 비활성화)