前言
WorldPartition(世界分区)是UE5为大世界管理提供的完整的解决方案,对于制作者而言,它主要解决了以下问题:
- 更灵活的流送配置
- 子关卡划分十分繁琐
- 难以同时审视整个地图
- 多人同时编辑关卡,会冲突
为了解决这些问题,UE5新增了以下几个模块:
网格、流送源提供了更灵活的流送配置,使得关卡流送不再依赖子关卡,也就不再需要为了流送而增加子关卡,所有东西都在一张地图上,自然更加直观,同时OFPA提供了每个Actor单独存储的功能,这样就大大减少了多人同时编辑关卡的冲突。
世界分区主体
启用世界分区
- 创建Open World类型的关卡默认开启
- 用转换工具将旧地图转为世界分区地图
网格
世界分区是将地图分为网格单元,这些网格单元的合集称为网格(Grid),一个地图可以有多个网格,关卡-网格-单元的关系如图:
如下图所示,世界被划分成一个一个格子,圆圈部分是流送源的加载范围,圆圈中心的红点是流送源的位置,在其中间的格子内的Actor会被加载。
可以在World Settings中查看或修改网格的大小、加载范围(圈的大小),以及更多网格相关的设定:
对于每个Actor,可以手动指定它属于哪个网格:
如果不填(None),则使用默认网格。
是否空间加载(Is Spatially Loaded):决定Actor是否由网格控制加载,选否的话Actor会始终加载流送源(Streaming Source)
下图的圆就是实际的加载范围,流送源就是这个圆的圆心,在其范围内的网格内的Actor才会被加载。
绿色的方块表示已经加载的Actor,灰色的块表示未被加载的Actor。
网格单元的加载与卸载往往与玩家的行为有关,所以,玩家控制器(Player Controller)会默认作为一个流送源:
除了玩家控制器之外,还可以通过为Actor添加世界分区流送源组件来使Actor成为流送源:
如果关卡里有多个网格,可以设置流送源对哪些网格生效。调试工具
控制台指令:wp.Runtime.ToggleDrawRuntimeHash2D
个人认为2D的视图比较好用,可以清晰的看出地图中有哪些网格,流送源及其范围,网格单元的划分以及Actor的加载状态等:
控制台指令:wp.Runtime.ToggleDrawRuntimeCellsDetails
显示网格单元的详细信息,主要是可以看到Cell的加载时间(但在编辑器模式下不准,需要打包看)
控制台指令:wp.Runtime.OverrideRuntimeSpatialHashLoadingRange -grid=0 -range=10000
通过指令设置临时的加载范围,可以用来测试加载范围是否合适
窗口-世界分区编辑器(Window-WorldPartitionEditor)
打开之后如图所示:
这里会显示整个地图的网格,可以通过框选的方式来加载或卸载选中的网格单元:
这个工具主要是用来在编辑器下控制加载区域,以减少关卡编辑时的卡顿。
其它相关特性
OFPA(One File Per Actor)
One File Per Actor(以下简称OFPA)是UE5的新特性,目的是为了解决多人协作修改同一个关卡时会冲突的问题(因为WorldPartition不再有Sublevel,所以会加剧这种情况),OFPA可以将Actor在关卡中的实例的数据保存到外部文件中,这样在更改Actor属性时无需修改主关卡文件,从而减少开发人员之间的互相等待。
在WorldPartition中,OFPA是默认开启的,如果在非WorldPartition的Level中使用OFPA,则需要在WorldSettings中手动开启:
开启之后保存Level,关卡中的Actor数据会被保存到一个独立的目录下,最终保存到以Actor Guid命名的文件里:
提交变更
通过上面图片可以发现,很难把某个文件和具体的Actor对应起来,所以当在p4直接提交这些文件的时候就容易出现问题,所以最好的方法是用UE自带的工具提交:
打开View Changes,可以看到修改了哪些Actor,并提交这些修改:
右键点击场景中的某个Actor,可以单独CheckOut,或查看其提交记录。
而p4上看是这样的。。
关卡实例(Level Instance)
关卡实例类似于Prefab,当一些Actor需要在多个关卡被复用时,就可以将其放在一个Level Instance中,然后再在各个关卡引用这个关卡实例,当关卡实例发生了修改,各个引用的关卡也都会同步这些修改。
使用关卡实例
1.选中一个或多个Actor,然后右键单击,在菜单中找到关卡-创建关卡示例:
2.随后会弹出一个提示框:
3.确认选项后会再弹出一个提示框,让我们选择保存的路径:
4.点击保存后,等待读条,关卡实例就会创建被出来了:
5.除了用这种方式创建LevelInstance,还可以用原来的方法创建普通的Level,然后把这个Level拖到场景中时,它会自动添加为LevelInstance:
编辑关卡实例
创建出来的关卡实例中的Actor在场景中会变为不可编辑状态,如果需要编辑可以选中关卡实例后点编辑:
编辑完成后可以点击保存:
这时对关卡实例的修改会同步到主关卡中。
非运行时
关卡实例只在编辑器下存在,运行时关卡实例下所有的Actor都会被嵌入到大地图中,通过世界分区网格来管理其加载卸载。
创建打包关卡Actor(Packed Level Actor)
打包关卡Actor是关卡实例的另外一种类型,它与普通关卡实例的区别是会试图将静态网格的Actor合并,使关卡实例中的 Actor数量尽可能少,这会在性能上有一定帮助。
上面两种LevelInstance可以替代现在的Prefab功能,所以后面Prefab应该是不用了。
LevelInstance变体
UE5.5版本添加了对LevelInstance属性覆盖的支持,需要在编辑器设置中开启此实验性功能:
同时需要在DefaultEngine.ini中添加Override类设置:
[/Script/Engine.LevelInstanceSettings]
PropertyOverridePolicyClass=/Script/Engine.LevelInstancePropertyOverrideSamplePolicy
LevelInstancePropertyOverrideSamplePolicy是官方给出的示例,也可以自定义一个Policy类,来满足不同的需求。
然后在场景中右键点击某个LevelInstance,可以看到多了一个Override选项:
点击Override,关卡实例将进入属性覆盖编辑模式,这与常规关卡实例编辑类似,可以注意到在轮廓中,关卡实例以蓝色而非绿色显示。
通过这种方式覆盖属性,不会修改源LevelInstance,也就是说,其它引用此关卡实例的地方不会受影响。
被覆盖的属性不会随着源LevelInstance的修改而变化,其它属性则会同步。
数据层-Data Layer
数据层(Data Layers)是世界分区中的一个系统,用于在编辑器中和在运行时整理Actor。
可以理解为将Level中的Actor进行分组,在编辑器中或运行时批量加载卸载,或控制其显隐。
使用
创建
可以在内容浏览器中创建DataLayer:
类型
Data Layers分为两种类型:编辑器(Editor)或运行时(Runtime),区别在于编辑器DataLayer只能在编辑器中生效,比如只是想对Level中的Actor进行打组分类,以便于更好的开发,则可以设置为编辑器类型。
如果涉及到具体的业务需求(如黑夜白天的切换,RS切换),则需要设置为运行时类型。
可以在DataLayer的详细面板中更改它的类型: https://d1iv7db44yhgxn.cloudfront.net/documentation/images/c20b5715-696b-430b-8da2-ed616d86d030/data-layers-editor-options.png
创建实例
刚才创建的DataLayer可以理解为一个模板,要使其在Level中生效,需要在Level中创建它的实例,可以在Window/WorldPartition/Data Layers Outliner打开DataLayers面板:
面板如下图所示,可以右键点击Level,通过Create New Data Layer With Asset来创建Data Layer实例:
创建完成后DataLayers面板显示如下:
添加Actor到DataLayer
通过DataLayers面板
先在Level检视面板中选中要添加的Actor(可以多选):
然后右键点击一个DataLayer,选择Add Selected Actors to Selected Data Layer:
通过Actor的细节面板(Details)
选中某个Actor,找到Details面板中的Data Layers选项卡,点击加号,添加DataLayerAssets后选择想要添加的DataLayer: