캐릭터의 무기 오버랩 이벤트를 구현했으니 어제에 이어 캐릭터를 공격해 데미지를 입혀 사망에 이르는 과정을 처리해보겠다
먼저 플레이어 캐릭터를 만들었던것처럼 적 캐릭터를 만들어보자
LKCharacterBase를 상속받은 LKEnemyCharacter를 만들어 모든 적을 이 클래스로 만들것임
// LKEnemyCharacter.h
UCLASS()
class LOSTKINGDOM_API ALKEnemyCharacter : public ALKCharacterBase
{
GENERATED_BODY()
public:
ALKEnemyCharacter();
protected:
virtual void AttackStart() override;
};
// LKEnemyCharacter.cpp
ALKEnemyCharacter::ALKEnemyCharacter()
{
GetCapsuleComponent()->SetCollisionProfileName(TEXT("LKEnemy"));
}
void ALKEnemyCharacter::AttackStart()
{
Super::AttackStart();
WeaponComponent->SetCollisionProfileName(TEXT("LKEnemyAttack"));
}
플레이어 캐릭터와 비슷하게 생성자에서 캡슐 컴포넌트 콜리전을 적 프로필 LKEnemy로 바꿔주고 공격을 시작할 때 무기 컴포넌트 콜리전을 적 공격 프로필로 바꿔주는 기본적인 구현을 했다
그리고 빌드 후 블루프린트 클래스를 만들어주고 이제 적 캐릭터의 메시, 애니메이션을 만들어줘야 한다
에픽스토어 런처에서 마켓플레이스로 가서 플레이어 캐릭터와 비슷한 Paragon 시리즈 중 처음 적은 인간형으로 만들고 싶어

위의 캐릭터를 애셋으로 받아 프로젝트에 추가했다(용량 너무 커)
블루프린트 클래스로 만든 적으로 가서 메시를 지정해준 후

기존에 플레이어 캐릭터에 쓰던 애니메이션은 스켈레톤이 다르기 때문에 새로 만들어줘야 한다(저번 개발일지 참고)
그렇게 새로 만들어주고(플레이어 애니메이션 블루프린트와 비슷하게 만들면 된다. 나같은 경우 복제해서 애니메이션 클립들만 다 바꿔줌)
그리고 맵에 배치해보자

로그까지 잘 뜨는걸 확인할 수 있다
이제 캐릭터가 데미지를 받아 HP가 0으로 내려가면 죽는 처리를 해보자
근데 아직 캐릭터 스탯을 구현 못했으니 그냥 공격 받으면 죽는 걸로 대체
모든 캐릭터의 부모 클래스인 LKCharacterBase에서 사망 처리를 하자
// LKCharacterBase.h
// Dead Section
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation")
TObjectPtr<UAnimMontage> DeadMontage;
virtual float TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
virtual void SetDead();
void PlayDeadAnimation();
// LKCharacterBase.cpp
void ALKCharacterBase::SetDead()
{
GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);
PlayDeadAnimation();
SetActorEnableCollision(false);
}
void ALKCharacterBase::PlayDeadAnimation()
{
AnimInstance->StopAllMontages(0.0f);
AnimInstance->Montage_Play(DeadMontage);
}
캐릭터의 HP가 0이하로 내려가면 SetDead 함수가 호출되면서 캐릭터의 움직임을 막고 사망 애니메이션을 재생시킨다. 사망 애니메이션이 재생되면 이전에 재생되던 모든 몽타주의 재생을 멈추고 사망 몽타주 재생. 그리고 더 이상 죽은 캐릭터에 콜리전을 활성화하는건 성능에 안좋으니 꺼주자
이제 사망 애니메이션 몽타주를 만들자
다른 몽타주처럼 애니메이션 몽타주를 만들어서 사망 애니메이션 애셋을 재생시킨다음 사망 애니메이션은 블렌드처리 필요없이 바로 재생되면 되니까 다음의 옵션을 꺼준다

그리고 몽타주 슬롯을 하나 만들어 Dead Slot이라고 만든 후 이 몽타주가 Dead Slot으로 설정되게 만든다

애니메이션 블루프린트로 가서 Dead Slot 몽타주 재생 노드를 추가한다. 이러면 사망 몽타주가 모든 애니메이션을 덮는다

적도 똑같이 만들어주면 된다
이제 코드에서 적을 공격해서 데미지를 주는 로직을 작성해보자
// LKCharacterBase.cpp
#include "Engine/DamageEvents.h"
...
void ALKCharacterBase::OnAttack(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Warning, TEXT("OtherActor : %s %d"), *OtherActor->GetName(), CurrentCombo);
if (OtherActor)
{
ALKCharacterBase* Enemy = Cast<ALKCharacterBase>(OtherActor);
if (Enemy)
{
FDamageEvent DamageEvent;
Enemy->TakeDamage(10.0f, DamageEvent, GetController(), this);
}
}
}
...
float ALKCharacterBase::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
SetDead();
return DamageAmount;
}
언리얼에는 유니티와 달리 따로 데미지 프레임워크를 제공하고 있어서 문서들을 잘 찾아보고 사용할 수 있다.
그래서 TakeDamage 함수를 AActor에서 제공하고 있고 이를 오버라이드해서 캐릭터가 데미지를 받을 때 사용할 수 있다
TakeDamage를 작성할때 FDamageEvent 구조체가 있는데 헤더파일을 작성해주지 않으면 선언할 수 없으므로 헤더 파일 꼭 참고
그래서 무기 콜리전에 캐릭터 콜리전이 반응하면 캐릭터 액터의 SetDead 함수를 호출해서 적을 죽여버린다. 이제 컴파일해서 실행해보자

이제 캐릭터 위 체력바같은 HUD를 띄워야하는데 Widget 부분 양이 길어질 것 같아서 여기서 마무리하고 다음 포스트를 쓰겠다