在场景中,美术和游戏逻辑是区分开的,所以有时候需要程序关卡去操控美术关卡的对象,但是 UE 的不同关卡其实是不同的资源,属于不同的 Pacakge,是不能直接跨关卡来选择对象实例的。
选择时会有以下错误:
1 | LogProperty: Warning: Illegal TEXT reference to a private object in external package (StaticMeshActor /Game/Test/Map/Level_Sub2.Level_Sub2:PersistentLevel.Cube_2) from referencer (BP_AActor_C /Game/Test/Map/Level_Sub1.Level_Sub1:PersistentLevel.BP_AActor_2). Import failed... |
这是因为在 PropertyBaseObject.cpp
的FObjectPropertyBase::ImportText_Internal
中对 Object 属性是否可以跨关卡做了检测:
1 | UObject* FObjectPropertyBase::FindImportedObject(const FProperty* Property, UObject* OwnerObject, UClass* ObjectClass, UClass* RequiredMetaClass, const TCHAR* Text, uint32 PortFlags/*=0*/, FUObjectSerializeContext* InSerializeContext /*= nullptr*/, bool bAllowAnyPackage /*= true*/) |
其中 AllowCrossLevel
有两个继承类有覆写:
1 | // Runtime/CoreUObject/Private/UObject/PropertyBaseObject.cpp |
所以,不能够直接通过创建 FObjectPropertyBase
这种硬引用方式的属性从 SubLevel1 选择 SubLevel2 中的 Actor。
那么如何解决这么问题呢?,上面已经列出了两个可以跨平台选择的属性,分别是 FLazyObjectProperty
和FSoftObjectProperty
,那么以 FSoftObjectProperty
为例,可以通过 TSoftObjectPtr
来实现:
1 | TSoftObjectPtr<AActor> Actor; |
TSoftObjectPtr
获取到的其实是 SubLevel2 中的资源的路径:
1 | /Game/Test/Map/Level_Sub2.Level_Sub2:PersistentLevel.Cube_2 |
在运行时访问需要使用以下操作来获取:
上面蓝图中节点 Load Asset Blocking
是UKismetSystemLibrary
中的函数:
1 | // Runtime/Engine/Private/KismetSystemLibrary.cpp |
看来 UE 加载资源时,并没有区分真正的物理资源和场景中的实例,统一使用资源的路径来加载,这一点做的非常爽,可以把另一个关卡中的 Actor 当作资源来读取,并且获取的还就是运行时的那个实例,非常 Nice。