在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(); }