FWorldContext

在 UE 中存在多种 World:

1
2
3
4
5
6
7
8
9
10
11
12
namespace EWorldType
{
enum Type
{
None,
Game,
Editor,
PIE,
Preview,
Inactive
};
};

FWorldContext

FWorldContext 则负责管理这些 World,使用指针 ThisCurrentWorld 指向当前的 world,对 world 的切换已经在引擎内部实现

FWorldContext 还保存 world 中 level 切换的上下文,不过这里只负责传入要切换的目标 level,真正执行的位置在 UEngine::TickWorldTravel 中执行 level 切换

思考:Level 的切换信息不放在 World 中?

  • 通过 OpenLevel 打开一个 PersistentLevel 时,引擎会释放当前 world 并创建一个新 world,如果将 Level 切换信息存放在 World 中,那么在这个过程中就又需要在释放 world 前把 level 的切换信息保存下来
  • 对于其他关卡(作为流式关卡),在加载的时候只是在 world 中载入对象,不需要释放 world,所以可以存放在 world 中

思考:为何 World 和 Level 的切换要放在下一帧执行?

  • Level 加载需要载入 Map、Mesh、Material 等,加载必然很慢,需要异步操作
  • 异步操作的两种方式
    • 先记录信息,再执行
    • 通过命令模式向队列中压入命令再执行

UGameInstance

UGameInstance

UGameInstance 中保存当前 FWorldContext 以及其他游戏的整体信息

可以将一些独立于 Level 的逻辑或数据放在 UGameInstance 中存储

UEngine

UEngine

UEngine 派生出两个重要子类:UGameEngine 和 UEditorEngine,UEngine 自身用一个全局 GEngine 变量保存

因为 UE 的编辑器也是 UE 渲染出来的,为了区别编辑器和游戏,这里分成了两个子类来管理

  • 对于编辑器,EditorWorld 的作用是预览,严格来说和 GameInstance 关系不大,所以没有 OwingGameInstance,而 PlayWorld 会保存一个 OwningGameInstance
  • GameWorld 是 UGameEngine 唯一创建出来的,也就是 StandaloneGame,也会保存 GameInstance 指针

UGameplayStatics

1
2
UCLASS ()
class UGameplayStatics : public UBlueprintFunctionLibrary

UGameplayStatics 作为一个静态类,给蓝图暴露了一些静态方法,当然这些方法也可以在 C++中使用

比如将屏幕上一点投射到世界空间,在 【Demo】多人TPS项目中用来计算准星发出的射线和世界空间物体的交点

1
UGameplayStatics::DeprojectScreenToWorld()

以及生成粒子发射器

1
UGameplayStatics::SpawnEmitterAttached()

总结

UE 使用 Object -> Actor + Component -> Level -> World -> WorldContext -> GameInstance -> Engine 这一套用来描述游戏世界的各个对象,接下来需要了解如何在这些对象的数据结构上表达游戏逻辑。

参考链接