在C++定义了一个继承UObject的类型UTestObject后,当蓝图继承UTestObject时没有办法访问带有WorldContextObject的函数,而访问子系统时将会有编译错误:ContextObject must have a connect。
在找了一番解决方案后解决了该问题,由此记录一下。
先看UE源码两处关键代码,其一是UObject::GetWorld(),可以看到默认获取outer的World,如果我们的UObject在NewObject时都正常传入outer的情况下是可以获取到world的,但在下面会有个bGetWorldOverridden的变量,如果为false则表示着调用到了该UObject基类上来了,派生类没有重写这个函数。
class UWorld* UObject::GetWorld() const
{
if (UObject* Outer = GetOuter())
{
return Outer->GetWorld();
}
#if DO_CHECK
bGetWorldOverridden = false;
#endif
return nullptr;
}
在看另一个函数UObject::ImplementsGetWorld(),这个函数会返回一个布尔值,其中会先将bGetWorldOverriden默认设置为true,然后调用GetWorld,如果派生类没有重写GetWorld函数则会调用上面介绍的UObject自身的GetWorld,这样bGetWorldOveridden就会被置为false并返回。UE就是通过调用这个函数来确定一个类型有没有重写GetWorld函数的,所以我们只需要想办法让这个函数返回true即可。
bool UObject::ImplementsGetWorld() const
{
#if DO_CHECK
bGetWorldOverridden = true;
GetWorld();
return bGetWorldOverridden;
#else
return true;
#endif
}
我们对自己定义的类型进行重写GetWorld函数,结果获取Outer的World即可。另外还有一种情况就是没有Outer或者当前对象是CDO,CDO对象的outer为UPackage对象,所以要对这两种情况进行特殊判断并返回空值。
UWorld* UTestObject::GetWorld() const
{
auto Outer = GetOuter();
if (!Outer || Cast<UPackage>(Outer))
{
return nullptr;
}
return Outer->GetWorld();
}