스테미나 시스템
HP와 동일하게 델리게이트로 UI와 연동하고 스테미나가 0이 되면 추후 처리를 위해 제작해보자.
스테미나가 0이되면 즉사할 수 있게끔 해보자.
스텟 컴포넌트에 추가해준다.
float URASStatComponent::ApplyStaminaDamage(float InStaminaDamageAmount)
{
const float PrevStamina = GetStamina();
const float ActualStaminaDamage = FMath::Clamp<float>(InStaminaDamageAmount, 0, InStaminaDamageAmount);
if (ActualStaminaDamage > 0)
RecoveryDelayRemaining = RecoveryDelayDuration;
SetStamina(PrevStamina - ActualStaminaDamage);
return ActualStaminaDamage;
}
HP를 연동한 부분에 스테미나도 연결해준다.
void ARASCommonMonster::PostInitializeComponents()
{
Super::PostInitializeComponents();
Stat->BaseStats = URASGameSingleton::Get().GetStatForName(CreatureName);
CreatureDamageInfo = URASGameSingleton::Get().GetDamageInfoForName(CreatureName);
StatusBarWidgetComponent->InitWidget();
auto Widget = Cast<URASStatusBarWidget>(StatusBarWidgetComponent->GetUserWidgetObject());
if (Widget == nullptr) return;
Widget->BindHP(Stat);
Widget->BindStamina(Stat);
Stat->SetHp(100000);
Stat->SetStamina(100000);
Stat->OnHpZero.AddUObject(this, &ARASCommonMonster::Death);
}
void URASStatusBarWidget::BindStamina(class URASStatComponent* InStatComponent)
{
StatComponent = InStatComponent;
if (InStatComponent != nullptr)
{
InStatComponent->OnStaminaChanged.AddUObject(this, &URASStatusBarWidget::UpdateStamina);
}
}
void URASStatusBarWidget::UpdateStamina(float InStamina)
{
if (StatComponent,IsValidLowLevel() && Stamina_Bar)
{
TargetStaminaPercent = InStamina / StatComponent->GetMaxStamina();
if (FMath::IsNearlyZero(CurrentStaminaPercent))
{
CurrentStaminaPercent = TargetStaminaPercent;
Stamina_Bar->SetPercent(CurrentStaminaPercent);
}
}
}
이렇게 해서 스테미나도 UI에 연결할 수 있다.
물론 이렇게 똑같이 플레이어의 HUD도 연결해주면 된다.
패링 성공시 화면 블러
패링에 성공하면 화면을 블러처리 함과 동시에 슬로우를 걸어 연출에 극적인 느낌을 추가해보자.
화면을 블러처리하는 방법에는 여러가지가 있을 수 있지만,
블러를 담당하는 머티리얼을 만들고 이를 VFX로 재생해서 스케일이 1초동안 점점 커지며 어느 한 지점을 기점으로 주변으로 확장되는 블러를 제작해보자.
머티리얼은 Blend Mode는 additive이고 Shading Model은 Unlit으로 설정한다.
이는 머티리얼의 Normal에 연결할 노드이다.
중심을 기준으로 방사형 노멀 변위를 만들고 Dynamic Parameter로 세기를 조절한뒤 DeriveNormalZ로 최종 법선을 생성한다. 이는 굴절 효과에서 픽셀단 굴절 방향을 만들어주는 핵심이다.

이는 머티리얼의 Opcaity에 연결할 노드이다.
텍스처 좌표를 활용해서 그라디언트를 만든 뒤, 여러 과정을 통해 알파를 계산한다.
DitherTemporalAA로 에일리어싱을 줄이고 Depth Fade로 지면이나 다른 오브젝트에 닿는 부위에서 부드럽게 사라지게 만든다.

이는 Refraction에 연결될 노드이고
DynamicParameter와 DepthFade의 결과를 토대로 굴절값을 조절한다.
Depth Fade를 Opacity와 Refraction에 동시에 걸어, 경계부분에서 자연스럽게 페이드 되돌록 구성한다.

한 개의 파티클이 1초간 스케일업 되면서 주변을 Additive Glow + 굴절(Blur)로 보이게 만들 수 있다. 파티클 생성 후 1초간 커지면서, 중심 부분은 굴절과 빛 번짐이 강하게 보이고, 경계는 Depth Fade/DitherTemporalAA로 부드럽게 사라지는 형태가 된다

여기서 Scale Sprite Size를 1초동안 2배로 늘리면 된다.
오브젝트 사망처리
HP가 0이 되었을 때 Death 하도록 만들자.
void ARASCharacterBase::Death()
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance == nullptr) return;
AnimInstance->StopAllMontages(0.1f);
AnimInstance->OnMontageEnded.RemoveAll(this);
AnimInstance->SetRootMotionMode(ERootMotionMode::RootMotionFromMontagesOnly);
int DeathType = FMath::RandRange(0, 1);
if (DeathMontage == nullptr) return;
AnimInstance->StopSlotAnimation(0.1f, TEXT("DefaultSlot"));
float PlayResult = AnimInstance->Montage_Play(DeathMontage);
UE_LOG(LogTemp, Log, TEXT("DeathMontage PlayResult: %f"), PlayResult);
if (DeathType == 0)
{
AnimInstance->Montage_JumpToSection(TEXT("FrontDeath"));
}
else
{
AnimInstance->Montage_JumpToSection(TEXT("BackDeath"));
}
}
void ARASPlayer::Death()
{
CombatState = EPlayerCombatState::Deathing;
Super::Death();
FTimerHandle DeathHandle;
GetWorld()->GetTimerManager().SetTimer(DeathHandle, [this]()
{
// 플레이어 사망 UI 띄움, UI에서 다시하기 버튼 클릭시 게임모드에서 플레이어를 저장된 위치로 리스폰
},
4.f, false);
}
void ARASCommonMonster::Death()
{
ARASAICommonController* MyController = Cast<ARASAICommonController>(GetController());
MyController->StopAI();
IndicatorWideget->SetVisibility(false);
auto Widget = Cast<URASStatusBarWidget>(StatusBarWidgetComponent->GetUserWidgetObject());
if (Widget == nullptr) return;
Widget->SetVisibilityBar(false);
bIsDeath = true;
Super::Death();
GetCapsuleComponent()->SetCollisionProfileName(TEXT("DeathCollision"));
ARASPlayer* Player = Cast<ARASPlayer>(Target);
if (Player != nullptr)
Player->PressTab();
FTimerHandle DeathHandle;
GetWorld()->GetTimerManager().SetTimer(DeathHandle, [this]()
{
Destroy();
},
5.f, false);
}
이 함수를 HP가 0이 되는순가 브로드캐스트 해주자.
float URASStatComponent::ApplyDamage(float InDamageAmount)
{
const float PrevHp = GetHp();
const float ActualDamage = FMath::Clamp<float>(InDamageAmount, 0, InDamageAmount);
SetHp(PrevHp - ActualDamage);
if (GetHp() <= KINDA_SMALL_NUMBER)
{
OnHpZero.Broadcast();
}
return ActualDamage;
}
Stat->OnHpZero.AddUObject(this, &ARASPlayer::Death);

이렇게 해서 죽은 뒤 5초뒤에 사라지게 할 수 있다.
'Unreal Engine 5 > ProjectRAS' 카테고리의 다른 글
| [UE5] ProjectRAS - Map Generator (0) | 2025.04.23 |
|---|---|
| [UE5] ProjectRAS - 맵 디자인 및 블프화 (0) | 2025.04.16 |
| [UE5] ProjectRAS - 패링으로 적 밀격 하기, UI 만들기 (0) | 2025.03.20 |
| [UE5] ProjectRAS - 전투 공격 판정 과 패링, 적 타겟팅 시스템(락온) (0) | 2025.03.12 |
| [UE5] ProjectRAS - 시점 고정과 일반 몬스터 (0) | 2025.03.06 |