Unreal - 로딩 창

2025. 5. 16. 04:54·Unreal5 프로젝트 다이어리

로딩창을 구현해보도록 하겠습니다

원형 쓰로버로 로딩스피너를 사용

. . . 을 해당 위 아래로 가는 애니메이션을 만들어서 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
'Unreal5 프로젝트 다이어리' 카테고리의 다른 글
  • Unreal - 몬스터 웨이브 만들기
  • Unreal - 버튼 위젯 사용하기
  • Unreal - 페이드 인 / 아웃
  • Unreal - GameMode로 맵마다 설정을 변경하기
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (119) N
      • Unreal5 프로젝트 다이어리 (73)
      • Unreal5 프로젝트 다이어리2 (2)
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 다이어리 (21) N
        • Stack (3)
        • Hash (4)
        • Heap (2)
        • Sort (1) N
      • 코드 개인보관함 (7)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼 시퀀스
    언리얼 페이드 인
    언리얼 spawn
    언리얼 비헤이비어트리
    unreal look at
    언리얼 behavior tree
    언리얼 behaviortree
    언리얼 foot step
    언리얼 스폰
    unreal loading
    unreal 컷씬
    언리얼 look at
    unreal 시퀀스
    언리얼 로딩창
    unreal sequence
    언리얼
    언리얼 로딩
    언리얼 컷씬
    언리얼 페이드 아웃
    unreal 로딩
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 로딩 창
상단으로

티스토리툴바