├── .gitattributes ├── .gitignore ├── Config └── FilterPlugin.ini ├── Docs └── screenshot.png ├── LICENSE ├── LoadingScreen.uplugin ├── README.md ├── Resources └── Icon128.png └── Source └── LoadingScreen ├── LoadingScreen.Build.cs ├── Private ├── LoadingScreenFunctionLibrary.cpp ├── LoadingScreenModule.cpp ├── LoadingScreenSettings.cpp ├── LoadingScreenSettings.h ├── SSimpleLoadingScreen.cpp └── SSimpleLoadingScreen.h └── Public ├── ILoadingScreenModule.h └── LoadingScreenFunctionLibrary.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | Intermediate/ -------------------------------------------------------------------------------- /Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /Docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinbad/LoadingScreen/3a376c53cbf03fa66ee271abdd6cd8f917b19f2b/Docs/screenshot.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Epic Games Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LoadingScreen.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | 4 | "Version": 1, 5 | "VersionName": "5.0", 6 | "FriendlyName": "Loading Screen", 7 | "Description": "A simple loading screen plug-in.", 8 | "Category": "Loading", 9 | "CreatedBy": "Epic Games, Inc.", 10 | "CreatedByURL": "https://www.epicgames.com", 11 | "DocsURL": "https://github.com/ue4plugins/LoadingScreen", 12 | "SupportURL": "https://github.com/ue4plugins/LoadingScreen/issues", 13 | "EngineVersion": "ANY_VERSION", 14 | "EnabledByDefault": true, 15 | "CanContainContent": false, 16 | 17 | "Modules": [ 18 | { 19 | "Name": "LoadingScreen", 20 | "Type": "Runtime", 21 | "LoadingPhase": "PreLoadingScreen" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LoadingScreen 2 | 3 | Unreal Engine 4 plug-in that adds a simplified layer on top of the loading screen system 4 | to make it easier to add a loading screen. 5 | 6 | ![Screenshot](Docs/screenshot.png) 7 | 8 | 9 | ## About 10 | 11 | The LoadingScreen plug-in implements a module that allows you to configure a simple 12 | Loading Screen system in the engine. To goal is to make it more customizable over 13 | time to avoid needing to write a new loading screen manually. 14 | 15 | 16 | ## Supported Platforms 17 | 18 | This plug-in was last built against **Unreal Engine 4.22**. It works on all platforms (probably). 19 | 20 | 21 | ## Dependencies 22 | 23 | This plug-in requires Visual Studio and either a C++ code project or a the full 24 | Unreal Engine 4 source code from GitHub. If you are new to programming in UE4, 25 | please see the official [Programming Guide](https://docs.unrealengine.com/latest/INT/Programming/index.html)! 26 | 27 | 28 | ## Usage 29 | 30 | You can use this plug-in as a project plug-in, or an Engine plug-in. 31 | 32 | If you use it as a project plug-in, clone this repository into your project's 33 | */Plugins* directory and compile your game in Visual Studio. A C++ code project 34 | is required for this to work. 35 | 36 | The plug-in configured to be enabled by default once it's in your game's plug-in directory. 37 | 38 | ## Support 39 | 40 | **Note: This plugin is not supported by Epic Games.** 41 | 42 | Please [file an issue](https://github.com/nickdarnell/LoadingScreen/issues), 43 | submit a [pull request](https://github.com/nickdarnell/LoadingScreen/pulls?q=is%3Aopen+is%3Apr) 44 | or hit me up on twitter [@NickDarnell](https://twitter.com/NickDarnell) 45 | 46 | 47 | ## References 48 | 49 | * [Introduction to UE4 Plugins](https://wiki.unrealengine.com/An_Introduction_to_UE4_Plugins) 50 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinbad/LoadingScreen/3a376c53cbf03fa66ee271abdd6cd8f917b19f2b/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/LoadingScreen/LoadingScreen.Build.cs: -------------------------------------------------------------------------------- 1 | using UnrealBuildTool; 2 | using System.IO; 3 | 4 | public class LoadingScreen : ModuleRules 5 | { 6 | public LoadingScreen(ReadOnlyTargetRules Target) 7 | : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public")); 12 | PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private")); 13 | 14 | PublicDependencyModuleNames.AddRange(new string[] { 15 | "Core" 16 | }); 17 | 18 | PrivateDependencyModuleNames.AddRange(new string[] { 19 | "CoreUObject", 20 | "MoviePlayer", 21 | "Slate", 22 | "SlateCore", 23 | "InputCore", 24 | "Engine", 25 | "DeveloperSettings" 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/LoadingScreenFunctionLibrary.cpp: -------------------------------------------------------------------------------- 1 | #include "LoadingScreenFunctionLibrary.h" 2 | 3 | 4 | FLoadingScreenDescription ULoadingScreenFunctionLibrary::GetStartupLoadingScreen() 5 | { 6 | return GetDefault()->StartupScreen; 7 | } 8 | 9 | FLoadingScreenDescription ULoadingScreenFunctionLibrary::GetDefaultLoadingScreen() 10 | { 11 | return GetDefault()->DefaultScreen; 12 | } 13 | 14 | void ULoadingScreenFunctionLibrary::SetLoadingScreen(FLoadingScreenDescription InDescription) 15 | { 16 | GetMutableDefault()->DefaultScreen = InDescription; 17 | } 18 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/LoadingScreenModule.cpp: -------------------------------------------------------------------------------- 1 | #include "ILoadingScreenModule.h" 2 | #include "LoadingScreenSettings.h" 3 | #include "SSimpleLoadingScreen.h" 4 | #include "Framework/Application/SlateApplication.h" 5 | 6 | #define LOCTEXT_NAMESPACE "LoadingScreen" 7 | 8 | class FLoadingScreenModule : public ILoadingScreenModule 9 | { 10 | public: 11 | FLoadingScreenModule(); 12 | 13 | /** IModuleInterface implementation */ 14 | virtual void StartupModule() override; 15 | virtual void ShutdownModule() override; 16 | virtual bool IsGameModule() const override 17 | { 18 | return true; 19 | } 20 | 21 | private: 22 | void HandlePrepareLoadingScreen(); 23 | 24 | void HandleMovieClipFinished(const FString& FinishedClip); 25 | 26 | void BeginLoadingScreen(const FLoadingScreenDescription& ScreenDescription); 27 | 28 | TSharedPtr WidgetLoadingScreen; 29 | }; 30 | 31 | IMPLEMENT_MODULE(FLoadingScreenModule, LoadingScreen) 32 | 33 | FLoadingScreenModule::FLoadingScreenModule() 34 | { 35 | 36 | } 37 | 38 | void FLoadingScreenModule::StartupModule() 39 | { 40 | if ( !IsRunningDedicatedServer() && FSlateApplication::IsInitialized() ) 41 | { 42 | // Load for cooker reference 43 | const ULoadingScreenSettings* Settings = GetDefault(); 44 | for ( const FSoftObjectPath& Ref : Settings->StartupScreen.Images ) 45 | { 46 | Ref.TryLoad(); 47 | } 48 | for ( const FSoftObjectPath& Ref : Settings->DefaultScreen.Images ) 49 | { 50 | Ref.TryLoad(); 51 | } 52 | 53 | if ( IsMoviePlayerEnabled() ) 54 | { 55 | // Binds the delegate to auto fire the loading screen code when a level changes and when a movie finishes 56 | GetMoviePlayer()->OnPrepareLoadingScreen().AddRaw(this, &FLoadingScreenModule::HandlePrepareLoadingScreen); 57 | } 58 | 59 | // Prepare the startup screen, the PrepareLoadingScreen callback won't be called 60 | // if we've already explictly setup the loading screen. 61 | BeginLoadingScreen(Settings->StartupScreen); 62 | } 63 | } 64 | 65 | void FLoadingScreenModule::ShutdownModule() 66 | { 67 | if ( !IsRunningDedicatedServer() ) 68 | { 69 | if (WidgetLoadingScreen) 70 | { 71 | WidgetLoadingScreen.Reset(); 72 | } 73 | GetMoviePlayer()->OnPrepareLoadingScreen().RemoveAll(this); 74 | } 75 | } 76 | 77 | void FLoadingScreenModule::HandlePrepareLoadingScreen() 78 | { 79 | const ULoadingScreenSettings* Settings = GetDefault(); 80 | BeginLoadingScreen(Settings->DefaultScreen); 81 | } 82 | 83 | void FLoadingScreenModule::HandleMovieClipFinished(const FString & FinishedClip) 84 | { 85 | // If its not the last movie then try keep waiting 86 | if (!GetMoviePlayer()->IsLastMovieInPlaylist()) 87 | { 88 | return; 89 | } 90 | 91 | // Unbind the delegate so we're not firing this multiple times 92 | GetMoviePlayer()->OnMovieClipFinished().RemoveAll(this); 93 | 94 | // Show the loading screen widget 95 | if (WidgetLoadingScreen) 96 | { 97 | WidgetLoadingScreen->HandleMoviesFinishedPlaying(); 98 | } 99 | } 100 | 101 | void FLoadingScreenModule::BeginLoadingScreen(const FLoadingScreenDescription& ScreenDescription) 102 | { 103 | if (WidgetLoadingScreen) 104 | { 105 | WidgetLoadingScreen.Reset(); 106 | } 107 | 108 | FLoadingScreenAttributes LoadingScreen; 109 | LoadingScreen.MinimumLoadingScreenDisplayTime = ScreenDescription.MinimumLoadingScreenDisplayTime; 110 | LoadingScreen.bAutoCompleteWhenLoadingCompletes = ScreenDescription.bAutoCompleteWhenLoadingCompletes; 111 | LoadingScreen.bMoviesAreSkippable = ScreenDescription.bMoviesAreSkippable; 112 | LoadingScreen.bWaitForManualStop = ScreenDescription.bWaitForManualStop; 113 | LoadingScreen.MoviePaths = ScreenDescription.MoviePaths; 114 | LoadingScreen.PlaybackType = ScreenDescription.PlaybackType; 115 | 116 | 117 | if (ScreenDescription.bShowWidget) 118 | { 119 | // Create and store widget 120 | WidgetLoadingScreen = SNew(SSimpleLoadingScreen, ScreenDescription) 121 | .bShowThrobber(ScreenDescription.Throbber.bShowThrobber) 122 | .ThrobberType(ScreenDescription.Throbber.ThrobberType) 123 | ; 124 | LoadingScreen.WidgetLoadingScreen = WidgetLoadingScreen; 125 | } 126 | 127 | const bool IsPlayingValidMovies = LoadingScreen.MoviePaths.Num() != 0; 128 | // Incase we have no movie paths, this will force it to show the loading screen anyway 129 | if (!IsPlayingValidMovies) 130 | { 131 | // Forces the movie player to create a movie streamer to actually show the widget and such 132 | LoadingScreen.MoviePaths.Add(""); 133 | } 134 | // If we have movies to show, then setup what happens if we're supposed to show ui otherwise skip this 135 | else 136 | { 137 | // Edgecase 138 | GetMoviePlayer()->OnMovieClipFinished().RemoveAll(this); 139 | 140 | GetMoviePlayer()->OnMovieClipFinished().AddRaw(this, &FLoadingScreenModule::HandleMovieClipFinished); 141 | } 142 | 143 | // This happens last after everything has been prepared ahead of time 144 | GetMoviePlayer()->SetupLoadingScreen(LoadingScreen); 145 | 146 | if (!IsPlayingValidMovies) 147 | { 148 | if (WidgetLoadingScreen) 149 | { 150 | WidgetLoadingScreen->HandleMoviesFinishedPlaying(); 151 | } 152 | } 153 | } 154 | 155 | 156 | #undef LOCTEXT_NAMESPACE 157 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/LoadingScreenSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "LoadingScreenSettings.h" 2 | #include "Styling/CoreStyle.h" 3 | #include "Engine/Font.h" 4 | #include "UObject/ConstructorHelpers.h" 5 | 6 | #define LOCTEXT_NAMESPACE "LoadingScreen" 7 | 8 | FLoadingScreenSlotPosition::FLoadingScreenSlotPosition() 9 | : Anchors(0.5f) 10 | , Offset(FVector::ZeroVector) 11 | , Alignment(FVector::ZeroVector) 12 | { } 13 | 14 | FLoadingScreenSlotText::FLoadingScreenSlotText() 15 | : bShouldShowText(true) 16 | , TextJustification(ETextJustify::Center) 17 | , WrapAt(1000.0f) 18 | , TextColor(FSlateColor(FLinearColor::White)) 19 | { 20 | if (!IsRunningDedicatedServer()) 21 | { 22 | // TODO (break Hot-reload) 23 | //static ConstructorHelpers::FObjectFinder RobotoFontObj(TEXT("/Engine/EngineFonts/Roboto")); 24 | //Font = FSlateFontInfo(RobotoFontObj.Object, 20, FName("Normal")); 25 | } 26 | } 27 | 28 | FLoadingScreenText::FLoadingScreenText() 29 | : SlotText(FLoadingScreenSlotText()) 30 | , SlotPosition(FLoadingScreenSlotPosition()) 31 | { } 32 | 33 | FLoadingScreenThrobber::FLoadingScreenThrobber() 34 | : bShowThrobber(true) 35 | , ThrobberType(EThrobberLoadingType::TLT_Regular) 36 | , bFlipThrobberAnimation(false) 37 | , NumPiecesThrobber(6) 38 | , ThrobberImage(*FCoreStyle::Get().GetBrush("Throbber.Chunk")) 39 | , ThrobberSlotPosition(FLoadingScreenSlotPosition()) 40 | , AnimateHorizontally(true) 41 | , AnimateVertically(true) 42 | , AnimateOpacity(true) 43 | , ThrobberPeriod(0.75f) 44 | , ThrobberRadius(16.0f) 45 | , ImageBrush(*FCoreStyle::Get().GetDefaultBrush()) 46 | , ImageColorAndOpacity(FLinearColor::White) 47 | { } 48 | 49 | FLoadingScreenTips::FLoadingScreenTips() 50 | : SlotText(FLoadingScreenSlotText()) 51 | , SlotPosition(FLoadingScreenSlotPosition()) 52 | , TimeBetweenTips(0) 53 | { } 54 | 55 | FLoadingScreenDescription::FLoadingScreenDescription() 56 | : bShowWidget(true) 57 | , MinimumLoadingScreenDisplayTime(-1.0f) 58 | , bAutoCompleteWhenLoadingCompletes(true) 59 | , bMoviesAreSkippable(true) 60 | , bWaitForManualStop(false) 61 | , PlaybackType(EMoviePlaybackType::MT_Looped) 62 | , bShowUiOverlay(true) 63 | , bShowUiAfterMovies(true) 64 | , Throbber(FLoadingScreenThrobber()) 65 | , LoadingScreenText(FLoadingScreenText()) 66 | , LoadingScreenDescription(FLoadingScreenText()) 67 | , LoadingScreenTips(FLoadingScreenTips()) 68 | , bShowImagesAfterMovies(true) 69 | , ImageStretch(EStretch::ScaleToFit) 70 | { 71 | LoadingScreenText.Text = LOCTEXT("Loading", "LOADING"); 72 | } 73 | 74 | ULoadingScreenSettings::ULoadingScreenSettings(const FObjectInitializer& Initializer) 75 | : Super(Initializer) 76 | { 77 | 78 | } 79 | 80 | #undef LOCTEXT_NAMESPACE 81 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/LoadingScreenSettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Widgets/Layout/Anchors.h" 5 | #include "Fonts/SlateFontInfo.h" 6 | #include "MoviePlayer.h" 7 | #include "Widgets/Layout/SScaleBox.h" 8 | #include "Framework/Text/TextLayout.h" 9 | #include "Engine/DeveloperSettings.h" 10 | 11 | #include "LoadingScreenSettings.generated.h" 12 | 13 | UENUM(BlueprintType) 14 | enum class EThrobberLoadingType : uint8 15 | { 16 | /** Uses a regular throbber to indicate loading */ 17 | TLT_Regular UMETA(DisplayName = "Regular"), 18 | /** Uses a circular throbber to indicate loading */ 19 | TLT_Circular UMETA(DisplayName = "Circular"), 20 | /** Uses an image instead of a throbber type incase you want to use an image with a material or something to indicate loading */ 21 | TLT_Image UMETA(DisplayName = "Image") 22 | }; 23 | 24 | USTRUCT(BlueprintType) 25 | struct LOADINGSCREEN_API FLoadingScreenSlotPosition 26 | { 27 | GENERATED_BODY() 28 | 29 | public: 30 | 31 | FLoadingScreenSlotPosition(); 32 | 33 | /** The anchor for the Widget 34 | * 0-X = Left Side 35 | * 1-X = Right Side 36 | * 0-Y = Top Side 37 | * 1-Y = Bottom Side 38 | */ 39 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Slot Position") 40 | FAnchors Anchors; 41 | 42 | /** The offset for the Widget 43 | * -X = Left 44 | * +X = Right 45 | * -Y = Up 46 | * +Y = Down 47 | */ 48 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Slot Position") 49 | FVector2D Offset; 50 | 51 | /** Alignment pivot point of the Widget with 0.5 being center of either axis 52 | * 0-X = Left Side 53 | * 1-X = Right Side 54 | * 0-Y = Top Side 55 | * 1-Y = Bottom Side 56 | */ 57 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Slot Position") 58 | FVector2D Alignment; 59 | 60 | }; 61 | 62 | USTRUCT(BlueprintType) 63 | struct LOADINGSCREEN_API FLoadingScreenSlotText 64 | { 65 | GENERATED_BODY() 66 | 67 | public: 68 | 69 | FLoadingScreenSlotText(); 70 | 71 | /** Flag for showing the widget. */ 72 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 73 | bool bShouldShowText; 74 | 75 | /** The justification of the text. */ 76 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 77 | TEnumAsByte TextJustification; 78 | 79 | /** The size of the text before it's wrapped to the next line. */ 80 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 81 | float WrapAt; 82 | 83 | /** The color to use for the text */ 84 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading Screen Text") 85 | FSlateColor TextColor; 86 | 87 | /** The font to display for text. */ 88 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 89 | FSlateFontInfo Font; 90 | }; 91 | 92 | USTRUCT(BlueprintType) 93 | struct LOADINGSCREEN_API FLoadingScreenText 94 | { 95 | GENERATED_BODY() 96 | 97 | public: 98 | 99 | FLoadingScreenText(); 100 | 101 | /** Text Information related to the text */ 102 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading Screen Text") 103 | FLoadingScreenSlotText SlotText; 104 | 105 | /** The slot position of the text */ 106 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading Screen Text") 107 | FLoadingScreenSlotPosition SlotPosition; 108 | 109 | /** The text to display on the loading screen. */ 110 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Loading Screen Text", meta = (MultiLine = "true")) 111 | FText Text; 112 | 113 | }; 114 | 115 | USTRUCT(BlueprintType) 116 | struct LOADINGSCREEN_API FLoadingScreenThrobber 117 | { 118 | GENERATED_BODY() 119 | 120 | public: 121 | 122 | FLoadingScreenThrobber(); 123 | 124 | /** Flag for showing the loading throbber if true, false will not show any throbber. */ 125 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber") 126 | bool bShowThrobber; 127 | 128 | /** Decides which throbber type to show if true, false will not show any throbber. */ 129 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber", meta = (EditCondition = "bShowThrobber")) 130 | EThrobberLoadingType ThrobberType; 131 | 132 | /** Should throbber animate in opposite direction? Works for both regular and circular throbber */ 133 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber", meta = (EditCondition = "bShowThrobber")) 134 | bool bFlipThrobberAnimation; 135 | 136 | /** The numbers of pieces in the throbber when it is shown */ 137 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber", meta = (ClampMin = "1", ClampMax = "25", EditCondition = "bShowThrobber")) 138 | int NumPiecesThrobber; 139 | 140 | /** The image for each throbber piece */ 141 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber", meta = (EditCondition = "bShowThrobber")) 142 | FSlateBrush ThrobberImage; 143 | 144 | /** The slot position of the throbber */ 145 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Throbber", meta = (EditCondition = "bShowThrobber")) 146 | FLoadingScreenSlotPosition ThrobberSlotPosition; 147 | 148 | /** Should the pieces animate horizontally? */ 149 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Regular", meta = (EditCondition = "bShowThrobber")) 150 | bool AnimateHorizontally; 151 | 152 | /** Should the pieces animate vertically? */ 153 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Regular", meta = (EditCondition = "bShowThrobber")) 154 | bool AnimateVertically; 155 | 156 | /** Should the pieces animate their opacity? */ 157 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Regular", meta = (EditCondition = "bShowThrobber")) 158 | bool AnimateOpacity; 159 | 160 | /** The amount of time for a full circle(in seconds) */ 161 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Circular", meta = (EditCondition = "bShowThrobber")) 162 | float ThrobberPeriod; 163 | 164 | /** The radius of the circle */ 165 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Circular", meta = (EditCondition = "bShowThrobber")) 166 | float ThrobberRadius; 167 | 168 | /** Image to draw (adjust image size here to adjust the size in X and Y) */ 169 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Image", meta = (EditCondition = "bShowThrobber")) 170 | FSlateBrush ImageBrush; 171 | 172 | /** Color and opacity */ 173 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Image", meta = (EditCondition = "bShowThrobber", sRGB = "true")) 174 | FLinearColor ImageColorAndOpacity; 175 | 176 | }; 177 | 178 | USTRUCT(BlueprintType) 179 | struct LOADINGSCREEN_API FLoadingScreenTips 180 | { 181 | GENERATED_BODY() 182 | 183 | public: 184 | 185 | FLoadingScreenTips(); 186 | 187 | /** Text Information related to the tips text */ 188 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 189 | FLoadingScreenSlotText SlotText; 190 | 191 | /** The slot position of the tips */ 192 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips") 193 | FLoadingScreenSlotPosition SlotPosition; 194 | 195 | /** The intended time between tips before it automatically switches to a new tip, anything below zero will cause the tips to not change. */ 196 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips", meta = (ClampMin = "0")) 197 | int TimeBetweenTips; // Using an integer because letting people be able to get it really low might be bad... 198 | 199 | /** The tips to display on the load screen */ 200 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tips", meta =(MultiLine = "true")) 201 | TArray Tips; 202 | 203 | }; 204 | 205 | USTRUCT(BlueprintType) 206 | struct LOADINGSCREEN_API FLoadingScreenDescription 207 | { 208 | GENERATED_BODY() 209 | 210 | public: 211 | 212 | FLoadingScreenDescription(); 213 | 214 | /** Flag for showing any ui elements and images if true(incase you only want to show movies and thats it then set this to false) */ 215 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Loading") 216 | bool bShowWidget; 217 | 218 | /** The minimum time that a loading screen should be opened for, -1 if there is no minimum time. */ 219 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Loading") 220 | float MinimumLoadingScreenDisplayTime; 221 | 222 | /** If true, the loading screen will disappear as soon as loading is done. */ 223 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Loading") 224 | bool bAutoCompleteWhenLoadingCompletes; 225 | 226 | /** If true, movies can be skipped by clicking the loading screen as long as loading is done. */ 227 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Loading") 228 | bool bMoviesAreSkippable; 229 | 230 | /** If true, movie playback continues until Stop is called. */ 231 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Loading") 232 | bool bWaitForManualStop; 233 | 234 | /** Should we just play back, loop, etc. NOTE: if playback type is MT_LoadingLoop, then MoviePlayer will auto complete when in the last movie and load finishes regardless of bAutoCompleteWhenLoadingCompletes */ 235 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Movies") 236 | TEnumAsByte PlaybackType; 237 | 238 | /** The movie paths local to the game's Content/Movies/ directory without extension. */ 239 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|Movies") 240 | TArray MoviePaths; 241 | 242 | /** Should we show the throbber/loading text etc? Generally you'll want to set this to false if you just want to show a movie. This will render over any movie/background image. */ 243 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI") 244 | bool bShowUiOverlay; 245 | 246 | /** Flag for showing UI after all movies have been played successfully if true. False will show during movies. */ 247 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI", meta = (EditCondition = "bShowUIOverlay")) 248 | bool bShowUiAfterMovies; 249 | 250 | /** Throbber to display when loading, can show circular and regular throbber types */ 251 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Throbber", meta = (EditCondition = "bShowUIOverlay")) 252 | FLoadingScreenThrobber Throbber; 253 | 254 | /** Text to display to indicate that the game is loading */ 255 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Loading Text", meta = (EditCondition = "bShowUIOverlay")) 256 | FLoadingScreenText LoadingScreenText; 257 | 258 | /** Optional text to display as a description. */ 259 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Description", meta = (EditCondition = "bShowUIOverlay")) 260 | FLoadingScreenText LoadingScreenDescription; 261 | 262 | /** Optional text to display that will randomly swap out with other tips if applicable */ 263 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Tips", meta = (EditCondition = "bShowUIOverlay")) 264 | FLoadingScreenTips LoadingScreenTips; 265 | 266 | /** Flag for showing images after all movies have been played successfully if true. False will show during movies. */ 267 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Images") 268 | bool bShowImagesAfterMovies; 269 | 270 | /** The texture display while in the loading screen on top of the movie. Will render after and over any movies. */ 271 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Images", meta = (AllowedClasses = "/Script/Engine.Texture2D")) 272 | TArray Images; 273 | 274 | /** The scaling type to apply to images. */ 275 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screens|UI|Images") 276 | TEnumAsByte ImageStretch; 277 | }; 278 | 279 | /** 280 | * Settings for the simple loading screen plugin. 281 | */ 282 | UCLASS(config=Game, defaultconfig, meta=(DisplayName="Loading Screen")) 283 | class LOADINGSCREEN_API ULoadingScreenSettings : public UDeveloperSettings 284 | { 285 | GENERATED_BODY() 286 | 287 | public: 288 | 289 | ULoadingScreenSettings(const FObjectInitializer& Initializer); 290 | 291 | /** The startup screen for the project. */ 292 | UPROPERTY(config, EditAnywhere, Category = "Screens") 293 | FLoadingScreenDescription StartupScreen; 294 | 295 | /** The default load screen between maps. */ 296 | UPROPERTY(config, EditAnywhere, Category = "Screens") 297 | FLoadingScreenDescription DefaultScreen; 298 | }; 299 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp: -------------------------------------------------------------------------------- 1 | #include "SSimpleLoadingScreen.h" 2 | 3 | #include "Slate/DeferredCleanupSlateBrush.h" 4 | #include "Widgets/Layout/SScaleBox.h" 5 | #include "Widgets/Images/SImage.h" 6 | #include "Widgets/Layout/SSpacer.h" 7 | #include "Widgets/SOverlay.h" 8 | #include "Widgets/SBoxPanel.h" 9 | #include "Widgets/Layout/SDPIScaler.h" 10 | #include "Widgets/Text/STextBlock.h" 11 | #include "Widgets/Layout/SBorder.h" 12 | #include "Widgets/Layout/SConstraintCanvas.h" 13 | #include "Widgets/Layout/SSafeZone.h" 14 | #include "Widgets/Images/SThrobber.h" 15 | #include "Widgets/Layout/SDPIScaler.h" 16 | #include "Framework/Application/SlateApplication.h" 17 | #include "Engine/Texture2D.h" 18 | #include "Engine/Engine.h" 19 | #include "Engine/UserInterfaceSettings.h" 20 | 21 | #define LOCTEXT_NAMESPACE "LoadingScreen" 22 | 23 | ///////////////////////////////////////////////////// 24 | // SSimpleLoadingScreen 25 | 26 | static float PointSizeToSlateUnits(float PointSize) 27 | { 28 | const float SlateFreeTypeHorizontalResolutionDPI = 96.0f; 29 | const float FreeTypeNativeDPI = 72.0f; 30 | const float PixelSize = PointSize * (SlateFreeTypeHorizontalResolutionDPI / FreeTypeNativeDPI); 31 | 32 | return PixelSize; 33 | } 34 | 35 | void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScreenDescription& InScreenDescription) 36 | { 37 | LastToolTipUpdate = -1.0f; 38 | 39 | ScreenDescriptionInfo = InScreenDescription; 40 | 41 | // Only show on construct if UI is true and we're not showing it after movies 42 | const bool bShowUiOnConstruct = (ScreenDescriptionInfo.bShowUiOverlay && !ScreenDescriptionInfo.bShowUiAfterMovies); 43 | bShowThrobber = InArgs._bShowThrobber; 44 | ThrobberType = InArgs._ThrobberType; 45 | 46 | // Construct the root of this widget 47 | TSharedRef Root = SNew(SOverlay); 48 | 49 | // If there's an image defined 50 | if (ScreenDescriptionInfo.Images.Num() > 0) 51 | { 52 | // Construct a random image to use for the loading screen 53 | const int32 ImageIndex = FMath::RandRange(0, ScreenDescriptionInfo.Images.Num() - 1); 54 | const FSoftObjectPath& ImageAsset = ScreenDescriptionInfo.Images[ImageIndex]; 55 | UObject* ImageObject = ImageAsset.TryLoad(); 56 | if ( UTexture2D* LoadingImage = Cast(ImageObject) ) 57 | { 58 | FVector2D Size = FVector2D(LoadingImage->GetSizeX(), LoadingImage->GetSizeY()); 59 | LoadingScreenBrush = FDeferredCleanupSlateBrush::CreateBrush(LoadingImage, Size); 60 | //LoadingImage, Size, FName(*ImageAsset.ToString())) 61 | // Adds a slot to the root then add that image to the widget, renders over the movie if supposed to 62 | BackgroundImageWidget = SNew(SImage) 63 | .Visibility(ScreenDescriptionInfo.bShowImagesAfterMovies ? EVisibility::Hidden : EVisibility::SelfHitTestInvisible) 64 | .Image(LoadingScreenBrush->GetSlateBrush()); 65 | 66 | Root->AddSlot(0) 67 | .HAlign(HAlign_Fill) 68 | .VAlign(VAlign_Fill) 69 | [ 70 | SNew(SScaleBox) 71 | .Stretch(ScreenDescriptionInfo.ImageStretch) 72 | [ 73 | BackgroundImageWidget.ToSharedRef() 74 | ] 75 | ]; 76 | } 77 | } 78 | 79 | // Handles creating the throbber widget 80 | { 81 | // Decides which throbber type to show 82 | switch (ThrobberType) 83 | { 84 | case EThrobberLoadingType::TLT_Circular: 85 | { 86 | // Construct circular throbber 87 | TSharedPtr ConstructedThrobber = SNew(SCircularThrobber) 88 | .Radius(ScreenDescriptionInfo.Throbber.ThrobberRadius) 89 | .Period(ScreenDescriptionInfo.Throbber.ThrobberPeriod) 90 | .NumPieces(ScreenDescriptionInfo.Throbber.NumPiecesThrobber) 91 | .PieceImage(&ScreenDescriptionInfo.Throbber.ThrobberImage); 92 | 93 | ThrobberWidget = ConstructedThrobber; 94 | break; 95 | } 96 | case EThrobberLoadingType::TLT_Regular: 97 | { 98 | // Decide which animation to play for regular throbber 99 | const int32 AnimationParams = (ScreenDescriptionInfo.Throbber.AnimateVertically ? SThrobber::Vertical : 0) | 100 | (ScreenDescriptionInfo.Throbber.AnimateHorizontally ? SThrobber::Horizontal : 0) | 101 | (ScreenDescriptionInfo.Throbber.AnimateOpacity ? SThrobber::Opacity : 0); 102 | const SThrobber::EAnimation Animation = static_cast(AnimationParams); 103 | 104 | // Construct regular throbber 105 | TSharedPtr ConstructedThrobber = SNew(SThrobber) 106 | .Animate(Animation) 107 | .NumPieces(ScreenDescriptionInfo.Throbber.NumPiecesThrobber) 108 | .PieceImage(&ScreenDescriptionInfo.Throbber.ThrobberImage); 109 | 110 | ThrobberWidget = ConstructedThrobber; 111 | break; 112 | } 113 | case EThrobberLoadingType::TLT_Image: 114 | default: 115 | { 116 | // Setup image to show 117 | const FSlateBrush* ImageBrush = &ScreenDescriptionInfo.Throbber.ImageBrush; 118 | 119 | // Construct an image in place of throbber 120 | TSharedPtr ConstructedImage = SNew(SImage) 121 | .Image(ImageBrush) 122 | .ColorAndOpacity(ScreenDescriptionInfo.Throbber.ImageColorAndOpacity); 123 | 124 | ThrobberWidget = ConstructedImage; 125 | break; 126 | } 127 | } 128 | 129 | // Only adjust the the scaling if we're not using an image 130 | if (ThrobberType != EThrobberLoadingType::TLT_Image) 131 | { 132 | // Handles flipping the throbber if needed 133 | ThrobberWidget->SetRenderTransformPivot(FVector2D(0.5f, 0.5f)); 134 | const float ThrobberScale = (float)((ScreenDescriptionInfo.Throbber.bFlipThrobberAnimation) ? -1 : 1); 135 | ThrobberWidget->SetRenderTransform(FSlateRenderTransform(FScale2D(ThrobberScale, 1.0f))); 136 | } 137 | // Show throbber if allowed 138 | ThrobberWidget->SetVisibility((bShowThrobber && bShowUiOnConstruct) ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 139 | } 140 | 141 | // Construct tooltip widget 142 | CurrentToolTipWidget = SNew(STextBlock) 143 | .Visibility(EVisibility::Hidden) // Default to hidden just incase 144 | .WrapTextAt(ScreenDescriptionInfo.LoadingScreenTips.SlotText.WrapAt) 145 | .Font(ScreenDescriptionInfo.LoadingScreenTips.SlotText.Font) 146 | .ColorAndOpacity(ScreenDescriptionInfo.LoadingScreenTips.SlotText.TextColor) 147 | .Justification(ScreenDescriptionInfo.LoadingScreenTips.SlotText.TextJustification); 148 | 149 | // Handles creating the tip text widget 150 | if (ScreenDescriptionInfo.LoadingScreenTips.Tips.Num() > 0) 151 | { 152 | // Decide tool tip to show 153 | CurrentToolTipIndex = FMath::RandRange(0, ScreenDescriptionInfo.LoadingScreenTips.Tips.Num() - 1); 154 | 155 | // Update the text 156 | CurrentToolTipWidget->SetText(ScreenDescriptionInfo.LoadingScreenTips.Tips[CurrentToolTipIndex]); 157 | // Show tooltip widget if allowed 158 | CurrentToolTipWidget->SetVisibility((ScreenDescriptionInfo.LoadingScreenTips.SlotText.bShouldShowText && bShowUiOnConstruct) 159 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 160 | 161 | // For deciding the time between tooltips 162 | LastToolTipUpdate = FPlatformTime::Seconds(); 163 | } 164 | 165 | // Construct Description Text 166 | DescriptionTextWidget = SNew(STextBlock) 167 | .Text(ScreenDescriptionInfo.LoadingScreenDescription.Text) 168 | .Font(ScreenDescriptionInfo.LoadingScreenDescription.SlotText.Font) 169 | .ColorAndOpacity(ScreenDescriptionInfo.LoadingScreenDescription.SlotText.TextColor) 170 | .Justification(ScreenDescriptionInfo.LoadingScreenDescription.SlotText.TextJustification) 171 | .WrapTextAt(ScreenDescriptionInfo.LoadingScreenDescription.SlotText.WrapAt) 172 | .Visibility((ScreenDescriptionInfo.LoadingScreenDescription.SlotText.bShouldShowText && bShowUiOnConstruct) 173 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 174 | 175 | // Construct Loading text 176 | LoadingTextWidget = SNew(STextBlock) 177 | .Text(ScreenDescriptionInfo.LoadingScreenText.Text) 178 | .Font(ScreenDescriptionInfo.LoadingScreenText.SlotText.Font) 179 | .ColorAndOpacity(ScreenDescriptionInfo.LoadingScreenText.SlotText.TextColor) 180 | .Justification(ScreenDescriptionInfo.LoadingScreenText.SlotText.TextJustification) 181 | .Visibility((ScreenDescriptionInfo.LoadingScreenText.SlotText.bShouldShowText && bShowUiOnConstruct) 182 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 183 | 184 | // Adds a slot to the root of this widget to allow for other widgets to be added to it, renders over image/movie 185 | Root->AddSlot() 186 | .HAlign(HAlign_Fill) 187 | .VAlign(VAlign_Fill) 188 | [ 189 | SNew(SSafeZone) 190 | [ 191 | SNew(SConstraintCanvas) 192 | 193 | // Adds the circular throbber to the canvas 194 | + SConstraintCanvas::Slot() 195 | .Anchors(ScreenDescriptionInfo.Throbber.ThrobberSlotPosition.Anchors) 196 | .Offset(FMargin(ScreenDescriptionInfo.Throbber.ThrobberSlotPosition.Offset)) 197 | .Alignment(ScreenDescriptionInfo.Throbber.ThrobberSlotPosition.Alignment) 198 | .AutoSize(true) 199 | .ZOrder(1) 200 | [ 201 | ThrobberWidget.ToSharedRef() 202 | ] 203 | 204 | // Adds the tip text to the canvas 205 | + SConstraintCanvas::Slot() 206 | .Anchors(ScreenDescriptionInfo.LoadingScreenTips.SlotPosition.Anchors) 207 | .Offset(FMargin(ScreenDescriptionInfo.LoadingScreenTips.SlotPosition.Offset)) 208 | .Alignment(ScreenDescriptionInfo.LoadingScreenTips.SlotPosition.Alignment) 209 | .AutoSize(true) 210 | .ZOrder(1) 211 | [ 212 | CurrentToolTipWidget.ToSharedRef() 213 | ] 214 | 215 | // Adds the description text to the canvas 216 | + SConstraintCanvas::Slot() 217 | .Anchors(ScreenDescriptionInfo.LoadingScreenDescription.SlotPosition.Anchors) 218 | .Offset(FMargin(ScreenDescriptionInfo.LoadingScreenDescription.SlotPosition.Offset)) 219 | .Alignment(ScreenDescriptionInfo.LoadingScreenDescription.SlotPosition.Alignment) 220 | .AutoSize(true) 221 | .ZOrder(2) 222 | [ 223 | DescriptionTextWidget.ToSharedRef() 224 | ] 225 | 226 | // Adds the loading text to the canvas 227 | + SConstraintCanvas::Slot() 228 | .Anchors(ScreenDescriptionInfo.LoadingScreenText.SlotPosition.Anchors) 229 | .Offset(FMargin(ScreenDescriptionInfo.LoadingScreenText.SlotPosition.Offset)) 230 | .Alignment(ScreenDescriptionInfo.LoadingScreenText.SlotPosition.Alignment) 231 | .AutoSize(true) 232 | .ZOrder(3) 233 | [ 234 | LoadingTextWidget.ToSharedRef() 235 | ] 236 | ] 237 | ]; 238 | 239 | ChildSlot 240 | [ 241 | Root 242 | ]; 243 | } 244 | 245 | void SSimpleLoadingScreen::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) 246 | { 247 | // Dont continue if we only have 1 tip to show 248 | if (ScreenDescriptionInfo.LoadingScreenTips.Tips.Num() == 1) 249 | { 250 | return; 251 | } 252 | 253 | const int TipDelay = ScreenDescriptionInfo.LoadingScreenTips.TimeBetweenTips; 254 | 255 | // Dont continue if the delay time is at zero 256 | if (TipDelay == 0) 257 | { 258 | return; 259 | } 260 | // If the time between now and last tooltip update is longer than the intended delay 261 | else if ((InCurrentTime - LastToolTipUpdate) > TipDelay) 262 | { 263 | // Record the time 264 | LastToolTipUpdate = InCurrentTime; 265 | 266 | // Valid check 267 | if (CurrentToolTipWidget) 268 | { 269 | // Update the text to a new random tool tip 270 | CurrentToolTipWidget->SetText(GetRandomToolTip()); 271 | } 272 | } 273 | } 274 | 275 | void SSimpleLoadingScreen::HandleMoviesFinishedPlaying() 276 | { 277 | // Show the background if we're allowed to 278 | if (ScreenDescriptionInfo.bShowImagesAfterMovies) 279 | { 280 | if (BackgroundImageWidget) 281 | { 282 | BackgroundImageWidget->SetVisibility(EVisibility::SelfHitTestInvisible); 283 | } 284 | } 285 | 286 | // Show ui elements if we're showing ui and we can show it after movies 287 | if (ScreenDescriptionInfo.bShowUiAfterMovies && ScreenDescriptionInfo.bShowUiOverlay) 288 | { 289 | if (ThrobberWidget) 290 | { 291 | ThrobberWidget->SetVisibility(ScreenDescriptionInfo.Throbber.bShowThrobber 292 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 293 | } 294 | 295 | if (LoadingTextWidget) 296 | { 297 | LoadingTextWidget->SetVisibility(ScreenDescriptionInfo.LoadingScreenText.SlotText.bShouldShowText 298 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 299 | } 300 | 301 | if (DescriptionTextWidget) 302 | { 303 | DescriptionTextWidget->SetVisibility(ScreenDescriptionInfo.LoadingScreenDescription.SlotText.bShouldShowText 304 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 305 | } 306 | 307 | // Only show tooltip widget if we have any tips to show 308 | if (CurrentToolTipWidget && ScreenDescriptionInfo.LoadingScreenTips.Tips.Num() != 0) 309 | { 310 | // Reset the time so incase if when we're visible its not shorter than its supposed to be 311 | LastToolTipUpdate = FPlatformTime::Seconds(); 312 | 313 | 314 | CurrentToolTipWidget->SetVisibility(ScreenDescriptionInfo.LoadingScreenTips.SlotText.bShouldShowText 315 | ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden); 316 | } 317 | } 318 | } 319 | 320 | float SSimpleLoadingScreen::GetDPIScale() const 321 | { 322 | const FVector2D& DrawSize = GetCachedGeometry().ToPaintGeometry().GetLocalSize(); 323 | const FIntPoint Size((int32)DrawSize.X, (int32)DrawSize.Y); 324 | return GetDefault()->GetDPIScaleBasedOnSize(Size); 325 | } 326 | 327 | FText SSimpleLoadingScreen::GetRandomToolTip() 328 | { 329 | // Decides a random tip to show thats not the current tooltip 330 | { 331 | const int32 Total = ScreenDescriptionInfo.LoadingScreenTips.Tips.Num(); 332 | int32 RandomTip = FMath::RandRange(0, Total - 1); 333 | // If there's only one then do nothing 334 | if (Total == 1) 335 | { 336 | RandomTip = 0; 337 | } 338 | else 339 | { 340 | // Find a random index that is not currently used 341 | while (RandomTip == CurrentToolTipIndex) 342 | { 343 | // Randomize the index 344 | RandomTip = FMath::RandRange(0, Total - 1); 345 | } 346 | } 347 | 348 | // Update current index to be this randomized one 349 | CurrentToolTipIndex = RandomTip; 350 | } 351 | 352 | return ScreenDescriptionInfo.LoadingScreenTips.Tips[CurrentToolTipIndex]; 353 | } 354 | 355 | bool SSimpleLoadingScreen::CanShowToolTip() const 356 | { 357 | return (ScreenDescriptionInfo.LoadingScreenTips.Tips.Num() > 0); 358 | } 359 | 360 | #undef LOCTEXT_NAMESPACE 361 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Private/SSimpleLoadingScreen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Widgets/SCompoundWidget.h" 4 | #include "Styling/CoreStyle.h" 5 | #include "LoadingScreenSettings.h" 6 | 7 | class FDeferredCleanupSlateBrush; 8 | class STextBlock; 9 | class SImage; 10 | 11 | class SSimpleLoadingScreen : public SCompoundWidget 12 | { 13 | public: 14 | 15 | SLATE_BEGIN_ARGS(SSimpleLoadingScreen) : 16 | _bShowThrobber(false), 17 | _ThrobberType(EThrobberLoadingType::TLT_Regular) 18 | {} 19 | SLATE_ARGUMENT(bool, bShowThrobber); 20 | SLATE_ARGUMENT(EThrobberLoadingType, ThrobberType); 21 | SLATE_END_ARGS() 22 | 23 | void Construct(const FArguments& InArgs, const FLoadingScreenDescription& ScreenDescription); 24 | 25 | virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; 26 | 27 | /** Handles setting visibility on objects that should be showing after all loading movies finished showing */ 28 | void HandleMoviesFinishedPlaying(); 29 | 30 | private: 31 | float GetDPIScale() const; 32 | 33 | /** Returns a random tool tip that is not currently used and sets the current index to that new one */ 34 | FText GetRandomToolTip(); 35 | 36 | /** Checks if we're able to show any tool tips */ 37 | bool CanShowToolTip() const; 38 | 39 | TSharedPtr LoadingScreenBrush; 40 | 41 | bool bShowThrobber; 42 | EThrobberLoadingType ThrobberType; 43 | 44 | double LastToolTipUpdate; 45 | int CurrentToolTipIndex; 46 | TSharedPtr CurrentToolTipWidget; 47 | TSharedPtr LoadingTextWidget; 48 | TSharedPtr DescriptionTextWidget; 49 | TSharedPtr ThrobberWidget = SNullWidget::NullWidget; 50 | TSharedPtr BackgroundImageWidget; 51 | 52 | FLoadingScreenDescription ScreenDescriptionInfo; 53 | }; 54 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Public/ILoadingScreenModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Modules/ModuleManager.h" 4 | 5 | /** 6 | * The public interface to this module 7 | */ 8 | class ILoadingScreenModule : public IModuleInterface 9 | { 10 | 11 | public: 12 | 13 | /** 14 | * Singleton-like access to this module's interface. This is just for convenience! 15 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 16 | * 17 | * @return Returns singleton instance, loading the module on demand if needed 18 | */ 19 | static inline ILoadingScreenModule& Get() 20 | { 21 | return FModuleManager::LoadModuleChecked< ILoadingScreenModule >("LoadingScreen"); 22 | } 23 | 24 | /** 25 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 26 | * 27 | * @return True if the module is loaded and ready to use 28 | */ 29 | static inline bool IsAvailable() 30 | { 31 | return FModuleManager::Get().IsModuleLoaded( "LoadingScreen" ); 32 | } 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /Source/LoadingScreen/Public/LoadingScreenFunctionLibrary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Kismet/BlueprintFunctionLibrary.h" 5 | #include "LoadingScreenSettings.h" 6 | #include "LoadingScreenFunctionLibrary.generated.h" 7 | 8 | /** 9 | * 10 | */ 11 | UCLASS() 12 | class LOADINGSCREEN_API ULoadingScreenFunctionLibrary : public UBlueprintFunctionLibrary 13 | { 14 | GENERATED_BODY() 15 | 16 | public: 17 | 18 | /** Returns the startup loading screen settings */ 19 | UFUNCTION(BlueprintPure, Category = "Loading Screen") 20 | static FLoadingScreenDescription GetStartupLoadingScreen(); 21 | 22 | /** Returns the current default loading screen settings. */ 23 | UFUNCTION(BlueprintPure, Category = "Loading Screen") 24 | static FLoadingScreenDescription GetDefaultLoadingScreen(); 25 | 26 | /** 27 | * Sets the current default loading screen settings to InDescription. 28 | * NOTE: This by default does not save those changes so when the application closes, it will reset those settings. 29 | */ 30 | UFUNCTION(BlueprintCallable, Category = "Loading Screen") 31 | static void SetLoadingScreen(FLoadingScreenDescription InDescription); 32 | 33 | }; 34 | --------------------------------------------------------------------------------