로딩창을 구현해보도록 하겠습니다
원형 쓰로버로 로딩스피너를 사용
. . . 을 해당 위 아래로 가는 애니메이션을 만들어서 Dot1Animation ~ Dot3Animation까지 만들어주었습니다
또한 프로그래스바를 만들어주었습니다
해당 위젯은 코드와 바인드하여 작동하게 하였습니다
public:
UPROPERTY(meta = (BindWidget))
class UTextBlock* TextBlock_Dot1;
UPROPERTY(meta = (BindWidget))
class UTextBlock* TextBlock_Dot2;
UPROPERTY(meta = (BindWidget))
class UTextBlock* TextBlock_Dot3;
UPROPERTY(meta = (BindWidgetAnim), Transient)
class UWidgetAnimation* Dot1Animation;
UPROPERTY(meta = (BindWidgetAnim), Transient)
class UWidgetAnimation* Dot2Animation;
UPROPERTY(meta = (BindWidgetAnim), Transient)
class UWidgetAnimation* Dot3Animation;
UPROPERTY(meta = (BindWidget))
class UProgressBar* ProgressBar_Loading;
UFUNCTION()
void LoadingStart();
UFUNCTION()
void UpdateProgressBar();
FTimerHandle th_Progressbar;
float elapsedTime = 0.0f;
float totalTime = 1.0f;
UFUNCTION()
void StartDotAnim();
FTimerHandle th_DotAnimation;
로딩이 시작되면 프로그래스바를 타이머를 사용하여 0에서 1로 1에서 5초사이 랜덤시간값만큼
프로그래스바를 업데이트 시켜주며 StartDotAnim()함수는 스마트포인터를 사용하여
애니메이션을 1부터 3까지 작동시켜주는 함수입니다
스마트 포인터를 사용하여 댕글링포인트 문제를 사전에 방지하였습니다
프로그래스바값 alpha가 1에 도착하면
OpenLevel로 레벨을 변경합니다
void ULoadingWidget::LoadingStart()
{
ProgressBar_Loading->SetPercent(0.0f);
float duration = FMath::FRandRange(1.0f, 5.0f);
elapsedTime = 0.0f;
totalTime = duration;
GetWorld()->GetTimerManager().SetTimer(th_Progressbar, this, &ULoadingWidget::UpdateProgressBar, 0.01f, true);
}
void ULoadingWidget::UpdateProgressBar()
{
elapsedTime += 0.01f;
float alpha = elapsedTime / totalTime;
alpha = FMath::Clamp(alpha, 0.0f, 1.0f);
ProgressBar_Loading->SetPercent(alpha);
if (alpha >= 1.0f)
{
GetWorld()->GetTimerManager().ClearTimer(th_Progressbar);
UStatGameInstance* gameInstance = Cast<UStatGameInstance>(UGameplayStatics::GetGameInstance(this));
if (gameInstance)
{
UGameplayStatics::OpenLevel(this, gameInstance->targetLevelToLoad);
}
}
}
void ULoadingWidget::StartDotAnim()
{
if (!GetWorld()) return;
TWeakObjectPtr<ULoadingWidget> weakLoadingPointer(this);
int32 dotIndex = 0;
GetWorld()->GetTimerManager().SetTimer(th_DotAnimation, [weakLoadingPointer, dotIndex]() mutable
{
if (!weakLoadingPointer.IsValid() || !weakLoadingPointer->IsInViewport())
{
if (weakLoadingPointer.IsValid() && weakLoadingPointer->GetWorld())
weakLoadingPointer->GetWorld()->GetTimerManager().ClearTimer(weakLoadingPointer->th_DotAnimation);
return;
}
switch (dotIndex)
{
case 0:
if (weakLoadingPointer->Dot1Animation) weakLoadingPointer->PlayAnimation(weakLoadingPointer->Dot1Animation);
break;
case 1:
if (weakLoadingPointer->Dot2Animation) weakLoadingPointer->PlayAnimation(weakLoadingPointer->Dot2Animation);
break;
case 2:
if (weakLoadingPointer->Dot3Animation) weakLoadingPointer->PlayAnimation(weakLoadingPointer->Dot3Animation);
break;
}
dotIndex = (dotIndex + 1) % 3;
}, 0.1f, true);
}
또한 맵의 이름을 띄워주는 위젯도 생성하였습니다
Map Name UI입니다 게임모드에서 property값으로 가지고있는
FString mapName의 이름을 출력하게해보겠습니다
UI를 먼저만듭니다
mapNameWidget <맵 이름을 띄워주는 위젯>
loadingWidget < 로딩 위젯>
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
TSubclassOf<UUserWidget> loadingWidget;
ULoadingWidget* loadingWidgetInstance;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
TSubclassOf<UMapNameUI> mapNameWidget;
UMapNameUI* mapNampeWidgetInstance;
UFUNCTION()
void OnFadeInFinished();
UFUNCTION()
void RemoveMapNameWidget();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
FString UIMapName;
게임모드에서 페이드인과 로딩맵의 관련된 코드입니다
해당코드는 위젯을 만들고 델리게이트호출을 하여 다음 위젯을 호출시킵니다
//fade
if (pCon && bNeedFadeIn)
{
fadeWidgetInstance = CreateWidget<UFadeInOutWidget>(pCon, fadeWidget);
if (fadeWidgetInstance)
{
fadeWidgetInstance->AddToViewport();
if (fadeWidgetInstance->FadeIn)
{
FWidgetAnimationDynamicEvent endEvent;
endEvent.BindDynamic(this, &ASwordPlayerGameBase::RemoveFadeOutWidget);
fadeWidgetInstance->BindToAnimationFinished(fadeWidgetInstance->FadeIn, endEvent);
}
}
fadeWidgetInstance->PlayFadeIn();
}
//loding
if (bUseLoadingMap)
{
loadingWidgetInstance = CreateWidget<ULoadingWidget>(pCon, loadingWidget);
{
HideAllPlayerUI();
loadingWidgetInstance->AddToViewport();
loadingWidgetInstance->LoadingStart();
loadingWidgetInstance->StartDotAnim();
}
}
FWidgetAnimationDynamicEvent endEvent;
endEvent.BindDynamic(this, &ASwordPlayerGameBase::RemoveFadeOutWidget);
fadeWidgetInstance->BindToAnimationFinished(fadeWidgetInstance->FadeIn, endEvent);
이곳에서 호출되며 페이드 인 애니메이션이 끝난뒤 RemoveFadeOutWidget함수가
델리게이트로 애니메이션이 끝난뒤 자동 호출됩니다
해당함수는 델리게이트로 호출될 함수들입니다
페이드인 -> 델리게이트로 RemoveFadeOutWidget 함수호출 -> 함수가 끝나면 OnFadeInFinished 함수 호출
void ASwordPlayerGameBase::RemoveFadeOutWidget()
{
if (fadeWidgetInstance)
{
fadeWidgetInstance->RemoveFromParent();
fadeWidgetInstance = nullptr;
}
OnFadeInFinished();
}
void ASwordPlayerGameBase::HideAllPlayerUI()
{
if (pCon && bUnActivatePlayerWidget)
{
player->characterWidget->SetVisibility(ESlateVisibility::Collapsed);
}
}
void ASwordPlayerGameBase::OnLevelLoaded()
{
UStatGameInstance* gameInstance = Cast<UStatGameInstance>(UGameplayStatics::GetGameInstance(this));
if (gameInstance)
{
UGameplayStatics::OpenLevel(this, gameInstance->targetLevelToLoad);
}
}
void ASwordPlayerGameBase::OnFadeInFinished()
{
mapNampeWidgetInstance = CreateWidget<UMapNameUI>(pCon, mapNameWidget);
{
mapNampeWidgetInstance->mapName = UIMapName;
mapNampeWidgetInstance->AddToViewport();
mapNampeWidgetInstance->playMapNameWidget();
if (mapNampeWidgetInstance->MapNameAnim)
{
FWidgetAnimationDynamicEvent mapEndEvent;
mapEndEvent.BindDynamic(this, &ASwordPlayerGameBase::RemoveMapNameWidget);
mapNampeWidgetInstance->BindToAnimationFinished(mapNampeWidgetInstance->MapNameAnim, mapEndEvent);
}
}
}
void ASwordPlayerGameBase::RemoveMapNameWidget()
{
if (mapNampeWidgetInstance)
{
mapNampeWidgetInstance->RemoveFromParent();
mapNampeWidgetInstance = nullptr;
}
}
해당위치에서 UPROPERTY값으로 가지고있는 UIMapName값으로 레벨의 이름을 설정하며
위젯을 띄웁니다
mapNampeWidgetInstance->mapName = UIMapName;
mapNampeWidgetInstance->AddToViewport();
mapNampeWidgetInstance->playMapNameWidget();
마지막 도착지에서의 게임모드 설정입니다
페이드인이 필요하니 Need Fade In변수에 체크
또한 UIMapName도 설정해주겠습니다
(해당 변수들은 제가 만든 커스텀 변수들이며 원래 존재하지않습니다)
페이드인
로딩창
페이드아웃 , 맵이름 UI출력
전체 로직 짤입니다
(용량이 커서 화질이 꺠지는점 이해바랍니다)
'Unreal5 프로젝트 다이어리' 카테고리의 다른 글
Unreal - 몬스터 웨이브 만들기 (0) | 2025.05.17 |
---|---|
Unreal - 버튼 위젯 사용하기 (0) | 2025.05.16 |
Unreal - 페이드 인 / 아웃 (0) | 2025.05.15 |
Unreal - GameMode로 맵마다 설정을 변경하기 (0) | 2025.05.15 |
Unreal - 쿼터뷰 시점 벽에 붙었을떄 카메라의 이동 (0) | 2025.05.15 |