Ue4C++编程------Loading界面与c++(四)

    我们知道,在基本所有的游戏中,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,用来显示当前处于什么状况下,如下图所示:

    Ue4C++编程------Loading界面与c++(四)_第1张图片

    我们将在加载界面,根据不同的关卡,使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来定制。   

    


    

    

    


    

你可能感兴趣的:(Ue4C++编程)