即使开放世界已然成为现今游戏趋势,切换关卡过程中的读条仍是很难避免的,譬如进入房屋、传送到其他世界等等。

于是就引入了loadingscreen这一需求。

loadingscreen顾名思义就是加载过程中通过其他线程显示的画面,可以是真读条(显示当前进度),也可以仅仅转着圈,循环播放某段视频。

我们首先需要新建c++类MyGameInstance继承自GameInstance,并在项目设置中将其设为当前使用的

这里我先创建了一个继承自MyGameInstance的蓝图,叫bp_MyGameInstance。

开始写代码之前,还有这些准备工作:

1.在projectname.build.cs文件中增加"MoviePlayer","UMG", "Slate", "SlateCore"几项

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject",
            "Engine", "InputCore", "HeadMountedDisplay",
            "MoviePlayer",
            "UMG", "Slate", "SlateCore"});

 

2.在projectname.h中包含一些头文件

#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/UMGStyle.h"
#include "Runtime/UMG/Public/Slate/SObjectWidget.h"
#include "Runtime/UMG/Public/IUMGModule.h"
#include "Runtime/UMG/Public/Blueprint/UserWidget.h"

#include "Runtime/MoviePlayer/Public/MoviePlayer.h"
#include "Runtime/SlateCore/Public/Widgets/SWidget.h"

 

然后重写gameinstance中的这个函数

virtual void Init() override;
void UMyGameInstance::Init()
{
    UGameInstance::Init();

    FCoreUObjectDelegates::PreLoadMap.AddUObject(this,     &UMyGameInstance::BeginLoadingScreen);
    FCoreUObjectDelegates::PostLoadMap.AddUObject(this, &UMyGameInstance::EndLoadingScreen);
}

 

接下来这两个函数

UFUNCTION()
    virtual void BeginLoadingScreen(const FString& MapName);
UFUNCTION()
    virtual void EndLoadingScreen();
void UMyGameInstance::BeginLoadingScreen(const FString& MapName)
{
    
    loadlevel_count++;
    if (!IsRunningDedicatedServer())
    {

        FLoadingScreenAttributes LoadingScreen;
        LoadingScreen.bAutoCompleteWhenLoadingCompletes = false;
        LoadingScreen.bMoviesAreSkippable = true;//任意键打断如果加载完成
        LoadingScreen.bWaitForManualStop = true;//
        LoadingScreen.PlaybackType = EMoviePlaybackType::MT_Looped;

        
        //不知道怎么destroy..
        inWidget = CreateWidget<UUserWidget>(this, WidgetTemplate);//应该有垃圾回收
        
        TSharedPtr<SWidget> WidgetPtr = inWidget->TakeWidget();
        LoadingScreen.WidgetLoadingScreen = WidgetPtr;
        
        LoadingScreen.MoviePaths.Add("squad_intro_movie");
        GetMoviePlayer()->SetupLoadingScreen(LoadingScreen);
        
    }
}

void UMyGameInstance::EndLoadingScreen()
{
    
    if (!IsRunningDedicatedServer())
    {

    }
}

 

上文中的squad_intro_movie其实是Content\Movies目录下的squad_intro_movie.mp4文件,不需要后缀名,要注意不是将其拖到编辑器中,而是把mp4文件复制到实际工程文件目录里。

而WidgetTemplate则是mygameinstance暴露到蓝图的用于Loadingscreen的控件类,

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = UI)
        TSubclassOf<UUserWidget> WidgetTemplate;
UUserWidget* inWidget = NULL;

inWidget才是真正被create出来的控件对象,虽然每次loading都新create了一次,但是ue4对控件应该有自己的垃圾回收机制。

至于控件蓝图,需要从mygameinstance中获取当前loading是否完成

UFUNCTION(BlueprintPure, Category = MyGameInstance)
        bool myisloadingfinished();
bool UMyGameInstance::myisloadingfinished()
{
    
    return GetMoviePlayer()->IsLoadingFinished();
}

我的loadingscreen控件蓝图目前只包含三样东西:

加载过程中throbber(就是那个点点点)显示,而“请按任意键继续”的文本隐藏;

加载完成时反之。

textblock的visibility函数:

点点点的visibility函数:

 

 要注意的是点击视口中运行并不能看到效果,需要选择独立窗口运行。

然后就大功告成啦!!!这里借用了一下squad的小视频