前言
在UE4版本中中,Actor是保存在关卡文件中的,也就是说,如果要编辑关卡中的某些Actor,需要签出关卡文件进行编辑,这种编辑粒度有可能会造成多人协作中工作流上的冲突,比如有多人想编辑某个关卡中的Actors,那么他们必须等待前一个人编辑完后才能编辑
因此,在UE5中细化了编辑粒度,将关卡中的每个Actor保存到一个单独的文件中而非关卡中,即所谓的一个Actor一个文件(One File Per Actor,OFPA),这意味着协作工作者只需签出自己想要编辑的Actor进行编辑即可,解决了工作流冲突问题
一、OFPA怎么用
如果是WP关卡,那么关卡中的Actor会默认被自动保存为外部文件,就拿游戏模板中第三人称关卡(ThirdPersonMap)来看,如上文所说,这是一个WP关卡
在创建工程之后,会在如下目录保存关卡中的所有Actor文件,并且会为关卡会生成一个同名文件夹,关卡中的Actor文件就保存在对应的文件夹中
选中关卡中的任意一个Actor(在关卡编辑区域或OutLiner都可以),然后鼠标右键,点击Copy Actor Path菜单,可以查看Actor的具体路径
这个时候大家应该猜的的到如果不是WP关卡的话,是创建的普通关卡,默认是禁用将Actor保存为外部文件的,它们仍然被保存在关卡中,举例如下:
再之前的普通关卡NoWP或者重新场景一个普通关卡,然后给它放一个Actor,然后右键拷贝路径会发现
会发现普通关卡复制的路径是直接指定关卡文件,就是说Actor仍然是被保存在关卡文件(.umap)中的,那如果我想要在普通关卡中开启这个One File Per Actor 一个文件一个Actor要怎么弄呢?这个时候就要打开编辑器设置开启了,操作如下:
开启后,在关卡的WorldSettings中的World部分有个Use External Actors,勾上后保存关卡(Ctrl+S)会使该关卡的所有Actor被保存为外部文件
就会发现变成和开启世界分区关卡一样的存储路径了。
普通关卡中的Actor还可以指定是否开启OFPA,具体操作如下:
选中Actor,然后去到它的Details面板,展开其中的Actor部分中的Advanced,其中有一个Packaging Mode(可以直接搜Packaging),然后选择External或Internal
External,该Actor会被保存为外部文件
Internal,该文件会被保存到关卡文件中
有了OFPA之后,我们可以针对Actor进行修改,并不会导致关卡被修改,如下图我修改了关卡中的SM_ChamferCube的位置,只会影响该Actor并不会影响当前关卡
官方文档有说基于当前关卡的所有子关卡需要手动勾选Use External Actors应该是预览版才需要这样做,正式版本中会默认保持和父关卡一致,即使在非WP关卡中创建子关卡也有一个默认勾选的选项
二、OFPA怎么用
那么文件是如何与关卡中的Actor关联起来的?
如何将关卡中的Actor保存为外部文件的代码比较简单,起始位置为ULevel::ConvertAllActorsToPackaging,最终调用HashObjectExternalPackage方法,该方法就是将Actor对象与外部文件对应起来的关键
void HashObjectExternalPackage(UObjectBase* Object, UPackage* Package)
{
if (Package)
{
FUObjectHashTables& ThreadHash = FUObjectHashTables::Get();
FHashTableLock LockHash(ThreadHash);
UPackage* OldPackage = AssignExternalPackageToObject(ThreadHash, Object, Package);
if (OldPackage != Package)
{
//将Object、Package放入PackageToObjectListMap中
AddToPackageMap(ThreadHash, Object, Package);
}
}
else
{
UnhashObjectExternalPackage(Object);
}
}
值得注意的是,OFPA机制只存在于编辑器中,在运行时候,Actor还是会被添加进Level中,代码如下:
AActor* UWorld::SpawnActor( UClass* Class, FTransform const* UserTransformPtr, const FActorSpawnParameters& SpawnParameters )
{
//...
// actually make the actor object
AActor* const Actor = NewObject<AActor>(LevelToSpawnIn, Class, NewActorName, ActorFlags, Template, false/*bCopyTransientsFromClassDefaults*/, nullptr/*InInstanceGraph*/, ExternalPackage);
//添加到Level中
LevelToSpawnIn->Actors.Add( Actor );
}
总结
以上就是今天要讲的内容,本文仅仅简单讲解了OFPA机制要解决的根本问题就是关卡的编辑粒度问题,OFPA机制只存在于编辑器中,在运行时候,Actor还是会被添加进Level中