This tutorial will explain how to use GT to create a loading screen. The tutorial describes the workings of the LoadingScreen_Map level in the sample CoUIGTTestFPS game. The LoadingScreen_Map is almost a duplicate of the ComplexMenu_Map but the loading screen is separated into a separate HTML file and run as part of UE4's loading screen.
Currently, the loading screen feature works only when GT is in asynchronous mode. To change the synchronicity mode, go to the GT plugin's settings (Coherent GT -> Options -> Run Asynchronous) Changes to the synchronicity require an engine restart.
Additionally, due to a limitation of UE4 (for which we've contacted Epic) GT cannot run as a loading screen before the first level. That is, you can use GT as a loading screen in between levels, but not before your first level has loaded.
The loading screen can be configured with the following options, all found in FCoherentUIGTLoadingScreenSettings
:
Note: Not all options can be used simulteniously - Wait for manual stop flag and Minimum loading screen display time are conflicting.
For UE4 versions post 4.11, the setup of the loading screen can be at any time before the level change, e.g. it can be in the BeginPlay's method of the Game's GameMode. For 4.10 and 4.11 you must make sure that the engine doesn't change resolution in the time between the loading screen is setup and the level is actually changed.
SetupLoadingScreen
Blueprint function.FCoherentUIGTLoadingScreenSettings LoadingScreenSettings; LoadingScreenSettings.URL = "coui://UIResources/loading_screen_sample/loading_screen.html"; TSharedPtr<SCoherentUIGTLoadingScreenWidget> LoadingScreen = ICoherentUIGTPlugin::Get().SetupLoadingScreen(LoadingScreenSettings);
ICoherentUIGTPlugin::SetupLoadingScreen
will return nullptr
.Since the engine's main loop is blocked while the level is loaded, your code needs to have another way to send continious updates to the UI. For this, you can use the SCoherentUIGTLoadingScreenWidget::RegisterLoadingScreenTimer
method which let you hook up a callback to be called every now and then. For example, as seen in the sample code for CoUIGTTestFPSLoadingScreenGameMode.cpp:
FWidgetActiveTimerDelegate
can be easily created via a lambda function, e.g:
// A function to update the progress in the UI using dummy values FWidgetActiveTimerDelegate ProgressBarDelegate = FWidgetActiveTimerDelegate::CreateLambda([this](double /*InCurrentTime*/, float /*InDeltaTime*/) { static float LoadingProgress = 0.f; LoadingScreen->GetView()->TriggerEvent("LoadingScreenProgress", LoadingProgress += 0.01f); return EActiveTimerReturnType::Continue; }); // Hook up both functions to timers. The timers will be cleared automatically when the loading screen is finished. LoadingScreen->RegisterLoadingScreenTimer(0.1f, ProgressBarDelegate);
Since it's invalid to use TriggerEvent before the the GT is ready to transfer data between C++ and JS, you'll find that that example code wait for GT to become ready before starting the timers:
void ACoUIGTTestFPSLoadingScreenGameMode::PrepareLoadingScreen() { ... auto LoadingScreen = ICoherentUIGTPlugin::Get().SetupLoadingScreen(LoadingScreenSettings); auto Helper = new FLoadingScreenHelper(LoadingScreen); // Will self-delete when the loading screen is done // Wait for GT to be ready for C++ <-> JS communication before doing anything LoadingScreen->ViewListenerOwner.ReadyForBindings.AddRaw(Helper, &FLoadingScreenHelper::OnLoadingScreenReadyForBindings); }
As mentioned, the LoadingScreen_Map closely resembles the ComplexMenu_Map. The HTML pages are almost identical except for some small difference which this paragraph will cover: