【UE5】将UObject改造成类似UGameInstance的功能

在UE的多人合作开发过程中可能会多人同时使用到GameInstance,这就会导致冲突事件,所以在一般情况下我们都在GameInstance中添加一个自己的UObject对象,由GameInstance管理,生命周期与GameInstance一致,用于处理各自的逻辑,这样不同开发的逻辑放在各自的UObject中,在GameInstance初始化时调用各个UObject的初始化函数,可以尽可能避免上面出现的冲突情况。

但是UObject无法像GameInstance一样可以使用蓝图函数库,或是其他有用到WorldContext的节点,如PrintString等,这是因为UObject是UE中最基础的对象类型,本身不存储任何关于World的引用,所以任何使用了WorldContext的接口均无法在UObject中使用。

但是我们又观察到UGameInstance也继承自UObject,而UGameInstance却可以使用WorldContext,查看源码可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
UWorld* UGameInstance::GetWorld() const
{
return WorldContext ? WorldContext->World() : NULL;
}

// ...

void UGameInstance::InitializeStandalone(const FName InPackageName, UPackage* InWorldPackage)
{
// Creates the world context. This should be the only WorldContext that ever gets created for this GameInstance.
WorldContext = &GetEngine()->CreateNewWorldContext(EWorldType::Game);
WorldContext->OwningGameInstance = this;

// In standalone create a dummy world from the beginning to avoid issues of not having a world until LoadMap gets us our real world
UWorld* DummyWorld = UWorld::CreateWorld(EWorldType::Game, false, InPackageName, InWorldPackage);
DummyWorld->SetGameInstance(this);
WorldContext->SetCurrentWorld(DummyWorld);

Init();
}

void UGameInstance::InitializeForMinimalNetRPC(const FName InPackageName)
{
check(!InPackageName.IsNone());

// Creates the world context. This should be the only WorldContext that ever gets created for this GameInstance.
WorldContext = &GetEngine()->CreateNewWorldContext(EWorldType::GameRPC);
WorldContext->OwningGameInstance = this;

UPackage* NetWorldPackage = nullptr;
UWorld* NetWorld = nullptr;
CreateMinimalNetRPCWorld(InPackageName, NetWorldPackage, NetWorld);

NetWorld->SetGameInstance(this);
WorldContext->SetCurrentWorld(NetWorld);

Init();
}

可以看到UGameInstance自己有维护一个WorldContext,那么只要我们让UObject也拥有一个WorldContext,这样UObject就具备了UGameInstance一样的能力了。

改造方法也比较简单,直接重写UObject的GetWorld函数,返回一个有效的World即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// .h
UCLASS(BlueprintType, Blueprintable)
class ZDDEVTEAMLOGIC_API UUserConfigManagerBase : public UObject
{
GENERATED_BODY()

private:
// 用于缓存 Owner 的弱指针
TWeakObjectPtr<UObject> Owner;

public:
virtual UWorld* GetWorld() const override;
// 可选:提供一个初始化函数,方便在蓝图中设置 Owner
UFUNCTION(BlueprintCallable, Category = "MyObject")
void Initialize(UObject* InOwner);
};

// .cpp
UWorld* UUserConfigManagerBase::GetWorld() const
{
//如果Owner存在,尝试从Owner获取World
if (Owner.IsValid())
{
// 如果Owner是Actor,可以直接获取World
if (AActor* OwnerAsActor = Cast<AActor>(Owner))
{
return OwnerAsActor->GetWorld();
}
// 如果Owner是ActorComponent,也可以通过它获取World
if (UActorComponent* OwnerAsComp = Cast<UActorComponent>(Owner))
{
return OwnerAsComp->GetWorld();
}
// 如果Owner是GameInstance或其它UObject,尝试获取其Outer的World
if (UObject* Outer = Owner->GetOuter())
{
return Outer->GetWorld();
}
}

// 如果Owner不存在,则通过GEngine遍历所有可用的WorldContexts
else if (GEngine)
{
// 遍历所有WorldContext,返回第一个有效的GameWorld
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if (Context.WorldType == EWorldType::Game && Context.World())
{
return Context.World();
}
}
}

return nullptr;
}

void UUserConfigManagerBase::Initialize(UObject* InOwner)
{
Owner = InOwner;
}

这样继承自这个UObject的蓝图Object就可以使用WorldContext了。


【UE5】将UObject改造成类似UGameInstance的功能
http://example.com/2026/05/14/【UE5】将UObject改造成类似UGameInstance的功能/
作者
Goulandis
发布于
2026年5月14日
许可协议