阿赵UE引擎C++编程学习笔记——场景加载和切换_ue addstreaminglevel-CSDN博客
【UE】大世界子关卡StreamingLevel加载流程源码浅析-虚幻4_ue4 streaminglevel-CSDN博客
基础知识
关卡可分为两类:持久关卡(PersistentLevel),子关卡或者流关卡(StreamingLevel)
持久关卡(PersistentLevel):默认加载进内存,它将会一直加载,无法卸载
子关卡或者流关卡(StreamingLevel):动态加载到内存(根据玩家位置和关卡距离,在运行时进行动态加载。)
1.直接切换
所谓切换关卡,就是从当前关卡进入到一个新的关卡, 旧关卡的数据将会被放弃。进入新的关卡后,将会执行新关卡的关卡蓝图和GameMode的生命周期。但是需要注意GameInstance里的数据并不会清除,因此此时需要注意GameInstance的数据是否会影响。
如:
- 在GameInstance里定义了变量 A = 10, GameMode A = 10, 同时改变变量 A = 20,重新切换关卡后GameInstance A = 20, GameMode A = 10。切换关卡可以重置大部分数据,但是需要注意无法重置的数据。
- 一个关卡对应一个GameMode,切换关卡后,需要重新给GameMode赋值,这也是外什么GameMode的数据会重置
个人理解
- 当当前关卡不会在用时,如游戏中的地图切换,这样可以减小开销,减小不必要的性能消耗
- 某些时候的垃圾回收,当场景中Actor需要更新时,发生卡顿,又不知原因时使用(不是很建议,因为涉及数据的重新赋值,且Actor过多时会发生卡顿)
蓝图中节点
2. 加载实例
加载关卡和切换关卡不一样的地方是,原有的关卡并不会被卸载,而是把新的关卡直接加入到旧的关卡当中。然后生命周期还是走的原有关卡,新关卡只是用于加载资源。
个人理解
类型更新,在原有的基础上添加新东西
蓝图
这个方法会返回是否加载成功,还有会返回加载后的Level对象,可以用于后续的控制:
3. 通过流读取关卡
区别于上面第2种方法,通过StreamLevel来加载场景,必须先把场景设置到Level里面。这是因为,一个主关卡可以添加很多个子关卡,这些子关卡可以设置成并不是一开始就加载,而是有需要的时候才加载显示。而很多个子关卡组成一个大关卡,就能实现超大型地图场景了。
个人理解
一个大关卡由多个小关卡构成,且每个小关卡有自己的数据与生命周期,如关卡蓝图
接下来看看怎样添加子场景。比如我要把Level2场景作为Level1场景的子场景,那么我们应该打开Level1场景,然后再去窗口——>关卡,打开关卡面板:
然后把Level2拖动到关卡面板
然后把Level2的修改流送方法改成蓝图:
蓝图:需要时加载
固定加载:默认就加载
设置好了之后,通过Load Stream Level节点,就可以加载子场景了。可以通过引用或者场景名称来加载。如果没有上面的设置,加载的时候会报错说找不到该名字的流场景。
这里有个设置叫做Make Visible After Load,意思是在场景加载完的时候,是否需要显示出来,如果勾上,那么加载完成后,就自动显示了。
如果想后面再显示场景的显示,可以这样:
- 通过GetStreamingLevel节点,可以找到刚才加载的StreamLevel
- 通过Set Should Be Visible节点,可以设置Level是否显示
- 如果想知道某个Level当前是否显示,可以用is Level Visible节点来查看
C++实现
1、 切换关卡
和蓝图的OpenLevel节点相同,都是加载新场景放弃就场景,调用如下:
UGameplayStatics::OpenLevel(GetWorld(), “Level2”);
2、 通过StreamLevel加载
这个和蓝图的Load Stream Level节点功能基本一致,也是需要先去关卡面板把子场景添加好,才能正常加载:
加载
FString fileName = TEXT("Level2");
FLatentActionInfo info;
UGameplayStatics::LoadStreamLevel(GetWorld(), *fileName, true,false,info);
卸载
FLatentActionInfo info;
FString fileName = TEXT("Level2");
UGameplayStatics::UnloadStreamLevel(GetWorld(), *fileName, info, false);
控制
FString fileName = TEXT("Level2");
ULevelStreaming* curLevel = UGameplayStatics::GetStreamingLevel(GetWorld(), *fileName);
if (curLevel == nullptr)
{
return;
}
bool isVisible = curLevel->IsLevelVisible();
curLevel->SetShouldBeVisible(not isVisible);
3、 按路径加载Level
如果不想先设置子Level,而直接按照路径加载某个场景资源,可以这样:
加载
ULevelStreamingDynamic* StreamingLevel;
FString path = TEXT("/Game/Level/Level3");
FLatentActionInfo info;
StreamingLevel = NewObject<ULevelStreamingDynamic>(GWorld, ULevelStreamingDynamic::StaticClass(), NAME_None, RF_Public, NULL);
StreamingLevel->SetWorldAssetByPackageName(*path);
GetWorld()->AddStreamingLevel(StreamingLevel);
StreamingLevel->SetShouldBeLoaded(true);
StreamingLevel->SetShouldBeVisible(true);
控制和移除
需要自己保存之前加载的StreamingLevel,接下来可以控制该Level的显示隐藏或者卸载移除都可以
if (StreamingLevel != nullptr)
{
StreamingLevel->SetIsRequestingUnloadAndRemoval(true);
}