前言

在使用虚幻引擎设计产品中会经常使用切换地图,你是否也遇到启动软件会黑屏半天,或是切换地图黑屏一下?客户总是说体验不好!是否有办法解决呢?

首先需要了解为什么会黑屏一下,其实非常简单!因为计算机在启动软件后需要加载磁盘资产,加载过程是需要时间消耗的,但是有时候需要加载的资产又多,然后磁盘读取效率又低,所以导致等待时间过长。在加载的时候,软件窗口是空闲的,但是又没有其他渲染任务,所以就黑屏了。

所以大多数软件会设计Loading页面。Loading页面其实就是先加载小资产(数量少,速度快),然后让窗体渲染等待页面,对于使用者来说能看到软件反馈体验就会好很多。像一般软件启动显示Logo,广告,切换地图显示提示信息。

在虚幻引擎中实现加载页面大致有两种

  • 纯粹的等待页面,例如绝地求生,添加等待图标,一直转圈等待
  • 加载进度条等待页面,有进度条可以直观看到加载进度情况 两者区别是,第一种不知道要等待多久,因为并不知道执行后台任务的进度。第二种可以知道执行后台的任务进度,进度完成则加载完成。

第一种我们可以在社区的wiki找到实施方案(需要通过c++来实现)传送门

本篇我们主要讲解第二种实施方案。

说明

第一二种方案其实都是一样的,都是需要借助后台加载资产,而不阻碍前台的逻辑执行,只是第二种多了加载进度的信息

整个过程我们需要借助两个函数(全局函数)

  • LoadPackageAsync:完成后台的异步加载
  • GetAsyncLoadPercentage:获取加载过程中的完成进度(值0-100) 在源码中有清晰的注释,说明函数的设计意图

建议

一般如果需要做过地图进度条,建议先将当前的关卡释放掉,以防内存占用过大被系统杀掉。所以更常规的做法一般是先切换到一个小关卡(openlevel即可),官方在实施无缝切换时也是使用此方案。

你可以先创建一个小关卡,在小关卡中启用异步后台加载,加载完成后再openlevel目标关卡(由于关卡资源已经加载过了,所以打开地图就无需等待)

实施

1、启动异步加载地图(放执行一次逻辑,不要多次执行),参照如下:

c++
1
2
3
4
5
6
7
8
//MapPath是地图包名称,第二个参数为设定匿名函数,用来获取加载结果,你也可以自行设计绑定回调函数
LoadPackageAsync(MapPath.GetLongPackageName(), FLoadPackageAsyncDelegate::CreateLambda([this]( const FName& /*PackageName*/, UPackage* /*LoadedPackage*/, EAsyncLoadingResult::Type Result/*Result*/)
{
    if (Result == EAsyncLoadingResult::Succeeded)
    {
        //可执行通知进行地图切换,即openlevel
    }
}));

此代码段,可以编写在启动切换地图的执行逻辑中,执行一次即可。

地图包路径: 右键地图资产,复制引用,将获取到引用路径,去掉额外信息参照如下:

复制结果:World’/Game/Environment_Set/Maps/Environment_Set_Map.Environment_Set_Map’

包名称:/Game/Environment_Set/Maps/Environment_Set_Map

通知代理: 通知代理可以设置匿名函数,也可以绑定到成员函数,具体可以参照虚幻单播设计。主要是通知加载结果。

匿名函数中注意参数捕获传入捕获方式。否则无法完成外部通知。

2、获取资产加载进度。

c++
1
2
3
4
5
6
//参考代码,注意返回值范围0-100,-1代表未发现加载包
float ALoadActor::GetLoadPercent()
{
    //参数传入加载地图的包名称,注意参数类型是FName
    return GetAsyncLoadPercentage(FName(MapPath.GetLongPackageName()));
}

注意,获取进度应该是需要轮询的,否则获取一次是无法知道过程的,毕竟加载是个时间流失过程。

最后

整个过程其实还是需要设计一下才可以,上面给到的是核心函数。

为了方便大家理解,我写了个插件,你可以插件工程来修改你的项目。

使用过程中需要调用插件中的子系统API完成地图切换,切换时,需要提供切换过度地图与进度UI,具体参照工程案例。

测试打包可以使用,测试平台Windows x64

其他版本引擎可以尝试直接升级使用。

Github:工程地址

虚幻引擎:4.27.2