Unreal C++ - 데미지 출력
카테고리: Unreal
Unreal C++ - 데미지 출력
언리얼에서 피격 부분에 데미지를 출력하는 방법을 기록한 포스트입니다.
데미지를 출력하기 위한 UCUserWidget_Damage 클래스를 생성하고 이를 상속받는 Widget Blueprint를 생성합니다.
//CUserWidget_Damage.h 파일
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CUserWidget_Damage.generated.h"
UCLASS()
class CPP_PORTFOLIO_API UCUserWidget_Damage : public UUserWidget
{
GENERATED_BODY()
public:
FORCEINLINE void SetDamage(int InDamage) { Damage = InDamage; }
UFUNCTION(BlueprintCallable)
int GetDamage();
private:
int Damage = 0;
};
//CUserWidget_Damage.cpp 파일
#include "Widgets/CUserWidget_Damage.h"
int UCUserWidget_Damage::GetDamage()
{
return Damage;
}
텍스트의 값을 GetDamage로 가져온 Damage값과 Bind하여 출력 시 밑에서 입력한 데미지로 출력하도록 설정합니다.
이 후 기존 코드의 데미지를 입는 부분에 데미지를 출력하는 함수를 추가합니다.
//몬스터에게 피해를 적용하는 메서드
void UCHitComponent_Monster::Hit(ACharacter* InAttacker, const FHitData& InHitData, EPhysicalSurface InBodyPart, FHitResult SweepResult)
{
UCMonsterStateComponent* state = Cast<UCMonsterStateComponent>(OwnerCharacter->GetComponentByClass(UCMonsterStateComponent::StaticClass()));
UCMonsterBehaviorComponent* behavior = Cast<UCMonsterBehaviorComponent>(OwnerCharacter->GetComponentByClass(UCMonsterBehaviorComponent::StaticClass()));
HP = FMath::Clamp<float>(HP - InHitData.Damage, 0, MaxHP);
//데미지 출력 추가 부분
{
APlayerController* controller = Cast<APlayerController>(InAttacker->GetController());
FVector screenPosition;
controller->ProjectWorldLocationToScreenWithDistance(OwnerCharacter->GetActorLocation(), screenPosition, true);
PrintDamage(InAttacker, InHitData.Damage, screenPosition.X, screenPosition.Y, screenPosition.Z);
}
if (FMath::IsNearlyZero(HP))
{
Dead();
return;
}
//TODO: sound and effects
if (BodyPartHP.Contains(TEnumAsByte<EPhysicalSurface>(InBodyPart)))
{
BodyPartHP[InBodyPart].DamageTaken += InHitData.Damage;
if (BodyPartHP[InBodyPart].DamageTaken >= BodyPartHP[InBodyPart].BreakDamage)
{
BodyPartHP[InBodyPart].DamageTaken -= BodyPartHP[InBodyPart].BreakDamage;
if (Montages[InBodyPart] != nullptr && BodyPartHP[InBodyPart].BreakCount > 0)
{
BodyPartHP[InBodyPart].BreakCount--;
if (!!state)
{
state->SetHitState();
}
if(!!behavior)
{
behavior->SetHitMode();
}
OwnerCharacter->PlayAnimMontage(Montages[InBodyPart]);
}
}
}
}
// 몬스터 피격을 관리하는 컴포넌트의 데미지 출력 메서드
void UCHitComponent_Monster::PrintDamage(ACharacter* InAttacker, int InDamage, int x, int y, int distance)
{
APlayerController* controller = Cast<APlayerController>(InAttacker->GetController());
if (controller == nullptr)
return;
UCUserWidget_Damage* widget = Cast<UCUserWidget_Damage>(CreateWidget(controller, DamageWidget));
distance = FMath::Clamp(distance, 0, 1000);
float scale = 0.8f + (0.6 * (1 - float(distance) / 1000));
widget->SetDamage(InDamage);
widget->SetRenderTranslation(FVector2D(x, y));
widget->SetRenderScale(FVector2D(scale, scale));
widget->AddToViewport();
}
공격자(Player)의 controller를 가져와 controller의 ProjectWorldLocationToScreenWithDistance함수를 사용하여 WVP연산을 통해 나타낸 몬스터의 위치를 역연산합니다.
역연산을 통해 나온 몬스터의 위치의 Screen에서의 좌표와 controller와 떨어져 있는 거리를 통해 출력될 데미지 Widget의 크기를 결정한다.