UE4 World, Level, LevelStreaming从入门到深入
前言
在《塞尔达传说:旷野之息》中,玩家攀上初始高塔的瞬间,目光所及的山川湖泊皆可抵达;在《艾尔登法环》中,黄金树的辉光始终悬于地平线之上,指引玩家穿越无缝衔接的史诗战场。这些现代游戏杰作背后的核心挑战之一,是如何将庞大的虚拟世界“装入”有限的内存与算力中,同时保持玩家沉浸感不被加载黑屏或性能卡顿打破。
虚幻引擎4(Unreal Engine 4, UE4)作为开放世界开发的主流工具,其 World(世界) 与 Level(关卡) 系统正是为解决这一矛盾而生。从《堡垒之夜》的动态战场到《地狱之刃》的线性叙事,开发者们通过灵活组合Persistent Level、Streaming Levels与World Composition,在引擎底层构建起一套“空间即代码”的规则体系——每一块地形、每一栋建筑不仅是美术资源,更是被精确计算的时空容器,按需加载、动态拼接,最终在玩家眼前编织成无垠的幻想之境。
世界(UWorld)
UWorld是UE里面最顶层UObject对象,代表了一个地图,里面存放各种UObject, AActor对象.
UWorld存在哪些地方
在游戏里,大多数时候只存在一个UWorld对象。而在UE引擎编辑器里, 许多UWorld存在。比如当前正在编辑的关卡是一个UWorld, PIE模式存在一个独立的UWorld, 带着独立渲染Viewport窗口的编辑器工具也存在一个UWorld.
C++访问UWorld
Actor获取所在的主World
UWorld* World = GetWorld()
这里获取的World是间接通过访问Actor所在的Level, 获取Level所在的World.
Level获取所在的主World
Level->OwningWorld
引擎编辑器获取当前的World
UWorld* World = GEditor->GetEditorWorldContext().World();
关卡Level
可以这么理解, World是由一个个Level组成,World容纳各种Actor的实际承载是Level.
关卡的创建
文件格式是umap
世界和关卡的关系
在双击点击一个Level进新的地图后, 代表了进入了一个新OwningWorld或者说是OwningWorld的持续性关卡(PersistentLevel, OwningWorld的PersistentLevel一直不会卸载). 这里比较注意的是每个关卡的默认名都叫“PersistentLevel”,都有自己的World,GetOuter()可以得到关卡GC引用链的World, 这和OwningWorld是两个概念。一般情况关卡的GC引用链的World很少使用)。
比如上图的当前世界的PersistentLevel就是ThirdPersonExampleMap.
关卡管理器(LevelManaer)
打开Window->Level可以打开关卡管理器可以查看当前存在哪些关卡.
图中挂在PersistentLevel下的是子关卡, 也是组成整个World的一部分, 不过子关卡和主关卡不一样的是, 可以随时从整个World关卡列表里面移除,加入, 加载,卸载等操作。
子关卡流程和操作
创建一个子关卡, 像上面已经写有
拖拽关卡到LevelManager
目前蓝色高亮的代表是当前编辑的关卡,放置到场景世界的Actor默认加入到这个关卡中。
C++访问 && 操作ULevel
获取主世界和主关卡(PersistentLevel)
UWorld* MainWorld = GetWorld();
ULevel* MainLevel = GetWorld()->PersistentLevel;
UWorld* TestWorld = Cast<UWorld>(MainLevel->GetOuter());
if(MainWorld == TestWorld)
{
}
获取一个关卡对应的GCWorld
//ULevel* TestLevel;
TestLevel->GetOuter();
获取当前编辑关卡
// 获取编辑器世界的UWorld指针(仅在编辑器模式下有效)
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
if (EditorWorld)
{
// 获取当前关卡(Persistent Level)
ULevel* CurrentLevel = EditorWorld->GetCurrentLevel();
if (CurrentLevel)
{
UE_LOG(LogTemp, Warning, TEXT("Current Level: %s"),
*CurrentLevel->GetOuter()->GetName());
}
}
加载关卡资源并加入当前主世界(Level资源路径加载)
// 关卡路径
FString LevelPackagePath = TEXT("/Game/Maps/C4");
UEditorLevelUtils::AddLevelsToWorld(MainWorld, {LevelPackagePath}, ULevelStreamingDynamic::StaticClass());
其他关卡操作相关参考UEditorLevelUtils库
Level的应用方案
基于 Persistent Level + Streaming Levels 的传统关卡流送
Persistent Level(持久关卡)
作为World的核心,持久关卡是始终加载的主关卡,负责管理其他子关卡的动态加载和卸载。它通常包含基础场景元素(如光照环境、天空盒等),且在运行时无法被卸载
Streaming Levels(流送关卡)
通过流送体积(Level Streaming Volumes)、蓝图或代码动态加载的子关卡。例如:
流送体积:当玩家进入体积区域时触发加载,离开时卸载
蓝图/C++控制:使用Load Stream Level
和Unload Stream Level
函数实现精确控制,可设置加载后是否可见、是否阻塞主线程等
固定加载(Always Loaded):某些子关卡可能与持久关卡同时加载,常用于多人协作开发的分层设计
技术特点
- 适用于中小型场景或需要手动控制加载逻辑的项目。
- 所有流送体积必须存在于持久关卡中
基于 World Composition 的大世界管理
针对开放世界等超大规模场景,World Composition通过自动化层级管理优化关卡流送.
核心机制
主关卡(Persistent Level)不存储流送信息,而是通过扫描指定目录自动识别子关卡(.umap文件)
子关卡按图层(Layer)分类,每个图层定义统一的流送距离。当玩家与关卡边界的距离小于该值时,自动加载对应关卡
层级管理优势
自动流送:根据摄像机位置动态加载/卸载,无需手动设置体积域
图层过滤:可创建自定义图层(如“森林层”“城市层”),并独立设置流送参数
无缝拼接:通过精确对齐关卡边界(需整数倍坐标),实现地形和物件的无缝衔接
两种技术对比
- 传统流送需要手动维护关卡列表,而World Composition通过目录扫描自动管理。
- 支持运行时动态调整流送策略(如
stat levels
命令查看加载状态)
两种模式的应用场景
模式 | 适用场景 | 技术优势 |
---|---|---|
Persistent+Streaming | 中小型场景、线性流程 | 精确控制加载时机,适合剧情关卡切换 |
World Composition | 开放世界、超大地图 | 自动化管理,减少手动配置,支持动态分层流送 |
两种方案总结
两种模式本质都属于关卡流送技术,但实现逻辑不同:传统流送依赖显式的手动配置,而World Composition通过层级化和自动化简化了大世界管理。开发者可根据项目规模选择,甚至混合使用(如在大世界中嵌套局部手动流送)以实现灵活的场景构建
参考资料
[1]World Composition in Unreal Engine | Unreal Engine 5.5 Documentation | Epic Developer Community
[2]Level Streaming in Unreal Engine | Unreal Engine 5.5 Documentation | Epic Developer Community
[3]腾讯元宝: "写一篇关于UE4 World, Level的技术博客"