[Community Gift] UE5 C++ Game Startup Loading Screen Plugin (Works in BP Only Projects)

:zap: :sparkling_heart: :zap: Rama’s C++ Game Startup Loading Screen Plugin :zap: :sparkling_heart: :zap:

:zap::zap::zap::zap: :zap::zap::zap::zap::zap::zap::zap::zap::zap:
:zap::zap::zap: Download Link: :zap: :zap: :zap:
:zap::zap::zap: :zap::zap::zap::zap::zap::zap::zap::zap::zap:

UE5.0 RamaCodeStartupLoadingScreen
~
UE5.1 RamaCodeStartupLoadingScreen

Supported Platforms: All

Precompiled Binaries: Windows
(This plugin will package fine along with other code for other platforms, but I am only providing precompiled binaries for Windows)


:sparkling_heart: What am I offering to you, oh Lovely Community in this plugin: :sparkling_heart:

  1. I am giving you a loading screen that will run ASAP when game is launched with editor closed (launched from commandline), standalone, or a packaged game. This is the UE5 version of the ShooterGame C++ Loading Screen module that needed some big changes to make it to UE5 land.

:unicorn: The Joy Of Customizeable Settings :star2:

  1. I am giving you lots of settings to play with to customize this C++ Loading Screen Module!
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
bool StartupLoadingScreenEnabled = true;

/** 
	This will make the Loading Screen work in a packaged build only, so you can run standalone / commandline editor builds without loading screen!
	This ONLY WILL WORK IF StartupLoadingScreenEnabled = true! 
*/
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
bool StartupLoadingScreenPackagedBuildsOnly = false;

/** Make sure to include this asset's folder in Additional Asset Folders to Cook if the asset is not being included in packaged game! <3 Rama */
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
FSoftObjectPath StartupLoadingImage;

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
FVector2D StartupLoadingScreenImageSize = FVector2D(1920,1080);

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
FLinearColor StartupLoadingScreenImageTint = FLinearColor::White;

//~~~ Progress Indicators ~~~

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
bool ProgressThrobberEnabled = true;

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
bool UseCircularProgressThrobber = true;

/** Default is Bottom Left */
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
bool ProgressThrobberPositionInBottomRight = false;

/** Padding relative to bottom left or right of screen */
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
float ProgressThrobberPadding = 15;

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
int32 ProgressThrobberPieceCount = 32;

UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
float ProgressThrobberCircularPieceRadius = 16;

/** Speed of rotation! ♥ Rama */
UPROPERTY(config, Category = "RamaCodeStartupLoadingScreenSettings", EditAnywhere, BlueprintReadWrite)
float ProgressThrobberCircularPiecePeriodSeconds = 1;
  1. The fastest way to test is to right click your uproject and select “Launch Game”, or run Standalone when editor is open.

  2. I preload the Loading Screen Texture during cooking to make sure the asset gets included for packaging!

  3. You can turn this plugin off any time, in settings, or have the loading screen only show up in packaged games, if you prefer!

  4. Known Issue: In Editor builds, the texture shows up as grey-checkerbox for a few moments during startup, this does NOT occur in packaged builds!

:rose: How It Works :rose:

  1. The Loading Screen image is stored as a FSoftObjPath, which is a string path ultimately, which means this can be saved as a config var.

  2. This soft path / string asset reference is then dynamically loaded before the rest of your game, so that a loading screen image can be put up on the screen!

  3. My class uses the fancy new UE PreLoadScreenManager to make this happen!

#include "PreLoadScreenBase.h"
#include "PreLoadScreenManager.h"

:zap::zap::zap: Progress Indicators? YES!!! :zap: :zap: :zap:

  1. I configured a pure C++ Slate widget with two different throbbers / progress bars that you can customize in the settings!

:heart: I Hope You Enjoy My Gift of Startup Loading Screens in UE5! :heart:

:heart:

Rama

PS:

The Code

All of the code is in one file mostly, if you wanted to see it!

//Copyright For EverNewJoy Eternity and Beyond, And With Love & Joy & Harmony to You! ♥ Rama ♥

#include "Modules/ModuleInterface.h"
#include "Misc/App.h"
#include "GenericPlatform/GenericApplication.h"
#include "GenericPlatform/GenericApplicationMessageHandler.h"
#include "SlateBasics.h"
#include "SlateExtras.h"
  
#include "Engine/Texture2D.h"
//~~~

//THE FUTURE!!! ♥ Rama
#include "PreLoadScreenBase.h"
#include "PreLoadScreenManager.h"

//~~~

#include "RamaCodeStartupLoadingScreenSettings.h"

//~~~

struct FRamaCodeStartupLoadingScreenBrush : public FSlateDynamicImageBrush, public FGCObject
{
	//GCObject allows for tracking this even if not  UPROPERTY()
	UTexture2D* TextureObj = nullptr;
	
	FRamaCodeStartupLoadingScreenBrush( UTexture2D* T2D, const FVector2D& InImageSize, const FName& TexName, const FLinearColor& InTint )
		: FSlateDynamicImageBrush( T2D, InImageSize, TexName, InTint )
	{
		TextureObj = T2D;
	}

	virtual void AddReferencedObjects(FReferenceCollector& Collector) override
	{
		if( TextureObj )
		{
			Collector.AddReferencedObject(TextureObj);
		}
	}
};



class SRamaCodeStartupLoadingScreenImage : public SCompoundWidget
{
public:
	SLATE_BEGIN_ARGS(SRamaCodeStartupLoadingScreenImage) {}
	SLATE_END_ARGS()

	//~~~
	
	void Construct(const FArguments& InArgs)
	{
		URamaCodeStartupLoadingScreenSettings* Settings = URamaCodeStartupLoadingScreenSettings::Get();
		if(!Settings)
		{
			UE_LOG(LogTemp, Error, TEXT("URamaCodeStartupLoadingScreenSettings:: Settings not valid!"));
			return;
		}

		if(!Settings->StartupLoadingImage.IsValid())
		{
			UE_LOG(LogTemp, Error, TEXT("URamaCodeStartupLoadingScreenSettings:: StartupLoadingImage was not set yet!"));
			return;
		}
		
		const FString LoadingScreenName(Settings->StartupLoadingImage.ToString());
 
		//This may show up as greybox for a few moments in Editor builds, works great in packaged games!
		UTexture2D* TextureObj = LoadObject<UTexture2D>( NULL, *LoadingScreenName);
		if(!TextureObj)
		{
			UE_LOG(LogTemp, Error, TEXT("URamaCodeStartupLoadingScreenSettings:: StartupLoadingImage Texture2D was not valid! <3 Rama"));
			return;
		}
		
		
		//since we are not using game styles here, just load one image
		LoadingScreenBrush = MakeShareable( new FRamaCodeStartupLoadingScreenBrush( TextureObj, Settings->StartupLoadingScreenImageSize, *LoadingScreenName, Settings->StartupLoadingScreenImageTint) );
 
		ChildSlot
		[
			
			SNew(SOverlay)
			+SOverlay::Slot()
			.HAlign(HAlign_Fill)
			.VAlign(VAlign_Fill)
			[
				SNew(SImage)
				.Image(LoadingScreenBrush.Get())
			]
			
			
			/*
			SNew(SBorder)
			.HAlign(HAlign_Fill)
			.VAlign(VAlign_Fill)
			.BorderImage(FCoreStyle::Get().GetBrush("WhiteBrush"))
			.BorderBackgroundColor(FLinearColor::Yellow)
			.Padding(0)
			*/
			
			/*
			SNew(SOverlay)
			*/
			+SOverlay::Slot()
			.HAlign(HAlign_Fill)
			.VAlign(VAlign_Fill)
			[
				SNew(SSafeZone)
				.VAlign(VAlign_Bottom)
				.HAlign( (Settings->ProgressThrobberPositionInBottomRight) ? HAlign_Right : HAlign_Left)
				.Padding(15.0f)
				.IsTitleSafe(true)
				[ 
					SNew(SCircularThrobber)
					.NumPieces(Settings->ProgressThrobberPieceCount)
					
					//SThrobber
					//.Animate(SThrobber::EAnimation::All)
					//.Animate(SThrobber::EAnimation::Vertical)
					
					//SCircular
					.Radius(Settings->ProgressThrobberCircularPieceRadius)
					.Period(Settings->ProgressThrobberCircularPiecePeriodSeconds)
					.Visibility( (Settings->UseCircularProgressThrobber) ? EVisibility::Visible : EVisibility::Collapsed)
				] 
			]
			
			+SOverlay::Slot()
			.HAlign(HAlign_Fill)
			.VAlign(VAlign_Fill)
			[
				SNew(SSafeZone)
				.VAlign(VAlign_Bottom)
				.HAlign( (Settings->ProgressThrobberPositionInBottomRight) ? HAlign_Right : HAlign_Left)
				.Padding(Settings->ProgressThrobberPadding)
				.IsTitleSafe(true)
				[ 
					SNew(SThrobber)
					.NumPieces(Settings->ProgressThrobberPieceCount)
					
					//SThrobber
					.Animate(SThrobber::EAnimation::All)
					//.Animate(SThrobber::EAnimation::Vertical)
					.Visibility( (Settings->UseCircularProgressThrobber) ? EVisibility::Collapsed : EVisibility::Visible )
				] 
			]
		];
	}

private:

	/** loading screen image brush */
	TSharedPtr<FSlateDynamicImageBrush> LoadingScreenBrush;
};


//~~~



//See PreLoadScreenBase.h
class FJoyPreLoadScreen : public FPreLoadScreenBase
{
public:
	
    /*** IPreLoadScreen Implementation ***/
	virtual void Init() override
	{
		if (!GIsEditor && FApp::CanEverRender())
		{
			EngineLoadingWidget = SNew(SRamaCodeStartupLoadingScreenImage);
		}
	}
	
    virtual EPreLoadScreenTypes GetPreLoadScreenType() const override { return EPreLoadScreenTypes::EngineLoadingScreen; }
    virtual TSharedPtr<SWidget> GetWidget() override { return EngineLoadingWidget; }
private:

    TSharedPtr<SWidget> EngineLoadingWidget;
};

class FRamaCodeStartupLoadingScreenModule : public IModuleInterface
{
public:
	
	//Delegate
	void OnPreLoadScreenManagerCleanUp()
	{
		//Once the PreLoadScreenManager is cleaning up, we can get rid of all our resources too
		PreLoadingScreen.Reset();
		
		//SHUTDOWN HERE
		ShutdownModule();
	}

	TSharedPtr<FPreLoadScreenBase> PreLoadingScreen;
	
	//~~~
	
	//Startup
	virtual void StartupModule() override
	{		
		UE_LOG(LogTemp, Warning, TEXT("RamaCodeStartupLoadingScreen: Started! "));
		
		URamaCodeStartupLoadingScreenSettings* Settings = URamaCodeStartupLoadingScreenSettings::Get();
		if(!Settings)
		{
			UE_LOG(LogTemp, Error, TEXT("URamaCodeStartupLoadingScreenSettings:: Settings not valid!"));
			return;
		}
		
		if(!Settings->StartupLoadingScreenEnabled)
		{
			UE_LOG(LogTemp, Warning, TEXT("URamaCodeStartupLoadingScreenSettings:: Exiting because not enabled in ProjectSettings! <3 Rama"));
			return;
		}
		
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if(GIsEditor)
		{
			TestLoadingForObjectCooker();
			return;
		}
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		
		//Packaged Builds Only?
		if(Settings->StartupLoadingScreenPackagedBuildsOnly && WITH_EDITOR)
		{
			return;
		}
		
		//~~~
		 
		if (!IsRunningDedicatedServer())
		{
			if (!GIsEditor && FApp::CanEverRender() && FPreLoadScreenManager::Get())
			{
				PreLoadingScreen = MakeShared<FJoyPreLoadScreen>();
				PreLoadingScreen->Init();
			
				FPreLoadScreenManager::Get()->RegisterPreLoadScreen(PreLoadingScreen);
				
				//PreloadScreenManager tells this module when to shutdown
				FPreLoadScreenManager::Get()->OnPreLoadScreenManagerCleanUp.AddRaw(this, &FRamaCodeStartupLoadingScreenModule::OnPreLoadScreenManagerCleanUp);
			}
		}
		
		//END OF STARTUP
	}
	
	void TestLoadingForObjectCooker()
	{
		//So user doesn't have to remember to manually add the asset in asset folders to package
		// ♥ Rama
	
		URamaCodeStartupLoadingScreenSettings* Settings = URamaCodeStartupLoadingScreenSettings::Get();
		if(!Settings)
		{
			return;
		}

		if(!Settings->StartupLoadingImage.IsValid())
		{
			return;
		}
		
		//This will run during packaging and cause cooker to include the object because LoadObject was used.
		UTexture2D* TextureObj = LoadObject<UTexture2D>( NULL, *Settings->StartupLoadingImage.ToString());
	}
	
	virtual bool IsGameModule() const override
	{
		return true;
	}
};

IMPLEMENT_GAME_MODULE(FRamaCodeStartupLoadingScreenModule, RamaCodeStartupLoadingScreen);
3 Likes

This is a fantastic gift, thank you so much Rama!

3 Likes

:heart: You’re welcome! :heart:

:heart:

Rama

1 Like

This is an actual C++ launched Game Startup Loading Screen that comes up within seconds!

(no matter how long the actual game loading process takes!)

:heart:

Rama

1 Like

:clap:That’s great!!!

1 Like

but in android,it will crash.

Hey!

So I’m looking for something like this - a simple, startup-onlu loading screen. But:

  • I don’t know Cpp
  • my project is Cpp, and this here says it will work in PB only…
  • I’m using UE5.2

will I be able to use it?