언리얼 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 옵션 비활성화)