我们知道,在基本所有的游戏中,Loading界面是必不可少的,该界面是在关卡间过度的时候显示的,用于告知玩家,正在加载资源,Loading界面有几种方法,其中一种是Level Streaming,还有可以参考ue4给我们提供的项目,里面也有关于loading界面的介绍,不过是单一的添加个新模块,而我要介绍的是另一种方法。
首先在我们的gameinstance中,添加两个新的成员函数,如下所示:
private:
UFUNCTION()
void BeginLoadingScreen(const FString& MapName);
UFUNCTION()
void EndLoadingScreen(UWorld* InLoadedWorld);
然后在我们的Init函数中,将这两个函数注册,如下所示:
FCoreUObjectDelegates::PreLoadMap.AddUObject(this, &UBlogGameInstance::BeginLoadingScreen);
FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &UBlogGameInstance::EndLoadingScreen);
我们创建一个枚举来表示当前我们处于哪个关卡中,因为我们希望当我们进入不同的关卡时,我们的加载界面能有不同,如下所示:
UENUM()
namespace NowLevel
{
enum type
{
INITIAL, // 初始化界面
LEVELONE, // 第一个关卡
};
}
然后在gameinstance中创建一个成员变量,来表示当前所处的关卡,初始化为INITIAL,如下所示:
NowLevel::type CurrentLevel;
接着我们创建一个蓝图控件,该控件就是用来显示加载界面的,控件很简单,就一个背景图片,及两个TEXT,用来显示当前处于什么状况下,如下图所示:
我们将在加载界面,根据不同的关卡,使TEXT Block显示不同的文字,绑定那些就不用说了吧。这个前面都有。
实现我们前面定义的loading函数,如下:
void UBlogGameInstance::BeginLoadingScreen(const FString& MapName)
{
if (LoadingWidget != nullptr)
{
ULoadingUserWidget* NewWidget = CreateWidget(this, LoadingWidget);
if (NewWidget != nullptr)
{
switch (CurrentLevel)
{
case NowLevel::INITIAL:
NewWidget->SetLevel(0);
break;
case NowLevel::LEVELONE:
NewWidget->SetLevel(1);
break;
default:
break;
}
// 创建加载界面参数
if (!IsRunningDedicatedServer())
{
FLoadingScreenAttributes attr;
attr.bAutoCompleteWhenLoadingCompletes = true;
attr.WidgetLoadingScreen = NewWidget->TakeWidget();
}
}
}
}
不要忘记在我们的配置文件中,加上movie模块,如下:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "MoviePlayer" });
接下来就编译我们的代码吧。需要说明的是,这个loading界面在编辑器中,是无法显示的,所以要在工程的右键,选择lanuchgame来运行我们的游戏,观察效果如何。发现在createwidget的时候,生成的widget为空指针。。google后发现,原来要创建原生的swiget,首先添加slate模块:
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
然后添加如下代码:
// 加载地图中间显示
struct FHotBattleLoadingScreenBrush : public FSlateDynamicImageBrush, public FGCObject
{
FHotBattleLoadingScreenBrush(const FName TextureName, const FVector2D& ImageSize)
: FSlateDynamicImageBrush(TextureName, ImageSize)
{
ResourceObject = LoadObject(NULL, *TextureName.ToString());
}
virtual void AddReferencedObjects(FReferenceCollector& Collector)
{
if (ResourceObject)
{
Collector.AddReferencedObject(ResourceObject);
}
}
};
class SHotBattleLoadingScreen : public SCompoundWidget // GetMoviePlayer必须使用swidget
{
public:
SLATE_BEGIN_ARGS(SHotBattleLoadingScreen) : _NowLevel() {}
SLATE_ARGUMENT(NowLevel::type, NowLevel) // 使用这个宏后就有了_NowLevel变量
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
NowLevelIn = InArgs._NowLevel; // 获取当前处于哪个关卡,加载相应的背景图在这使用_NowLevel变量
FString text;
FName LoadingScreenName;
switch (NowLevelIn)
{
case NowLevel::INITIAL:
LoadingScreenName = TEXT("/Game/ThirdPersonCPP/UI/Res/Initialize");
text = FString(TEXT("Initialize"));
break;
case NowLevel::LEVELONE:
LoadingScreenName = TEXT("/Game/ThirdPersonCPP/UI/Res/Ice");
text = FString(TEXT("LevelOne"));
break;
}
LoadingScreenBrush = MakeShareable(new FHotBattleLoadingScreenBrush(LoadingScreenName, FVector2D(1920, 1080)));
ChildSlot
[
SNew(SOverlay)
+ SOverlay::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SImage)
.Image(LoadingScreenBrush.Get())
]
+ SOverlay::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(text))
]
];
}
private:
TSharedPtr LoadingScreenBrush;
NowLevel::type NowLevelIn;
};
void UBlogGameInstance::BeginLoadingScreen(const FString& MapName)
{
//if (LoadingWidget != nullptr)
//{
// APlayerController* AC = GetWorld()->GetFirstPlayerController();
// UE_LOG(LogTemp, Warning, TEXT("NewWidget: %s"), *(AC->GetName()));
// ULoadingUserWidget* NewWidget = CreateWidget(AC, LoadingWidget);
// //UE_LOG(LogTemp, Warning, TEXT("NewWidget: %s"), *(NewWidget->GetName()));
// if (NewWidget != nullptr)
// {
// switch (CurrentLevel)
// {
// case NowLevel::INITIAL:
// NewWidget->SetLevel(0);
// break;
// case NowLevel::LEVELONE:
// NewWidget->SetLevel(1);
// break;
// default:
// break;
// }
// // 创建加载界面参数
// if (!IsRunningDedicatedServer())
// {
// FLoadingScreenAttributes attr;
// attr.bAutoCompleteWhenLoadingCompletes = true;
// attr.WidgetLoadingScreen = NewWidget->TakeWidget();
// }
// }
//}
if (!IsRunningDedicatedServer())
{
FLoadingScreenAttributes LoadingScreen;
LoadingScreen.bAutoCompleteWhenLoadingCompletes = true;
//LoadingScreen.WidgetLoadingScreen = FLoadingScreenAttributes::NewTestLoadingScreenWidget(); // 使用自定义的loadscreen的话必须是slate
LoadingScreen.WidgetLoadingScreen = SNew(SHotBattleLoadingScreen).NowLevel(CurrentLevel); // 加载地图时使用该背景
GetMoviePlayer()->SetupLoadingScreen(LoadingScreen);
}
}
测试如下。可以看到中间有Initialize的字,至于怎么调整字体大小,颜色这些,就自行研究吧,需要使用TextBlockStyle来定制。