2 - 游戏模式

腾讯2024游戏客户端公开课笔记,UE的游戏模式部分。

游戏模式

概念

游戏模式就是 在游戏世界里组织数据和运作规则的方式,例如决定游戏玩家数、决定游戏是否允许暂停、设置游戏暂停时的处理等。

UE游戏模式框架

万物之源 UObject

如图,UObject类是UE框架的万物之源,它赋予自身和子类各种各样的功能,包括元数据、反射生成、GC、序列化等。此外也提供了一些通用的属性和接口。

物体的表达 Actor + ActorComponent

UE使用EC架构(Entity-Component Framework)来表达一个物体,通过给物体(Actor)附加多种组件(Component),来让它拥有相应的能力。例如SceneComponent就包含了这个物体的3D变换信息。

世界的表达 UWorld + ULevel

UE用UWorld来表达游戏世界,包括实际游戏中的GameWorld,编辑器中的PIEWorld,Debug预览用的PreviewWorld等。UWorld类中又包含若干关卡ULevel,通常是一个主关卡PersistentLevel和若干子关卡SubLevel。

UE使用LevelStreaming技术来流式异步加载关卡,关卡加载的逻辑主要有下面3种:

  1. UE5新增的WorldPartition;

  2. WorldComposition:

  3. LoadByLogic;

为了加快加载效率以及避免消耗非必要资源,可以通过 “LevelBounds + StreamingDistance分层” 技术来设置关卡大小和加载距离。

此外,还能通过 关卡蓝图 LevelScriptActor 来定义关卡的规则。

世界之上 UGameInstance + UEngine

管理世界和关卡的是UGameInstance类和UEngine类,它俩的职责如下:

  • UGameInstance负责管理世界和关卡,它的信息存在于整个游戏的生命周期,不随着地图的切换而销毁。它非常适合管理全局的非业务逻辑,例如全局的UI、设置、一些预加载等。
  • UEngine则负责管理UGameInstance,它通过一些方法来管理游戏中重要的流程,例如地图加载等。

UE游戏世界的加载流程如下:

  1. UGameEngine::Init:设置并创建本地玩家;
  2. UGameEngine::start:开始游戏实例UGameInstance,同时让UEngine加载世界。
  3. UEngine::LoadMap:首先通过LoadPackage让UWorld和ULevel进行后加载,然后开始设置游戏实例并初始化世界,接着进行游戏模式的设置和关卡流式加载,最后初始化供游玩的Actor,以及初始化玩家的Actor。

游戏模式中的重要对象

AActor

基础概念

AActor类是游戏中最重要的实体,它提供了许多功能:

  • OwnedComponents:各种组件为Actor提供对应功能。
  • RootComponent:根组件提供世界变化信息。
  • Children:为子Actor提供附着功能,例如玩家受伤的枪。
  • 网络同步组件:AActor是网络同步的基础单位,拥有 Owner指针,本地权限Role枚举以及一些网络同步和实例化组件。

生命周期

一个Actor的生命周期如下:

actorlifecycle1

首先需要加载Actor,Actor可被分为两类:

  • 关卡内摆放的静态Actor:在上图的左半边,黄色/深蓝色部分。

  • 通过SpawnActor创建的动态Actor:

    • 本地Spawn加载
    • 网络序列化加载

    在上图的右半边,浅蓝/橙色部分。

接下来开始执行 BeginPlay() 函数,它表示一个Actor开始的生命周期,可以在这里获取和设置它的相关参数。

在Actor的运行期间,会在引擎的每一Tick执行 Tick() 函数,执行并更新相关信息,比如渲染逻辑和物理逻辑等。

如果游戏场景中不再需要这个Actor,则会执行 EndPlay() 函数,可以在这里写一些Actor结束时的逻辑。

最后,该Actor会被标记为待销毁,然后交由GC进行销毁。因此在判断一个Actor是否合法(IsValid)时,除了判断它是否在内存中存在,还要看它是否被标记为待销毁。

APawn

基础概念

APawn类继承AActor类,它表示游戏中可被操控的对象,例如人物、载具等。在Actor的基础上,可通过Controller来控制Pawn,支持一些基础的输入和移动框架。

派生类

APawn还有一些常用的派生类:

  • ADefaultPawn:这是UE提供的简单默认Pawn,它提供了简单球形碰撞组件 USphereComponent、简单外部显示组件 UStaticMeshComponent、简单移动组件 UFloatingPawnMovement,以及基础的输入映射(键盘、手柄);
  • ASpectatorPawn:适用于游戏中的观察者模式,去掉外部显示组件,将移动组件替换为忽略时间缩放的 USpectatorPawnMovement。
  • ACharacter:将在下文详细介绍。

ACharacter

基础概念

继承自APawn,更适合用于人形角色的控制,在APawn的基础上,ACharacter类拥有:

  • 近似人形的胶囊体碰撞盒 UCapsuleComponent:在保证一定真实性的同时,节约性能。
  • 骨骼模型 USkeletalMeshComponent:动画蓝图 + 人物骨骼赋予人物生动表现。
  • 人物移动组件 UCharacterMovementComponent:它配合胶囊体组件完成如走路、掉落、游泳、飞行等多种仿真移动计算;还提供Custom移动模式让开发者自定义移动;并且提供了网络游戏的移动同步功能。

AController

基础概念

可以控制Pawn,Controller通过 Possess(APawn*) 方法来控制Pawn;Pawn通过 PossessedBy(AController*)接受Controller的控制。AController下还有APlayerController和AAIController,将在下文介绍。

APlayerController

专门给玩家用的Controller,通过UInputComponent绑定输入映射,通过APlayerCameraManager来计算相机位置;通过AHUD来展示控制相关UI,但逐渐被更灵活的UMG取代;此外还有网络连接的所有权(主控端和服务器)。

PlayerController类可以视为代表玩家的实体,其本质上是Pawn的核心。它接受来自用户的输入,并将其传递给Pawn和其他类,以便玩家与游戏进行交互。在处理该类时必须注意以下几点:

  • 与Pawn类不同,在一个关卡中只能有一个PlayerController代表玩家。
  • PlayerController类在整个游戏中持续存在,但Pawn类可能不会(例如人物死亡后会重生,但它的Controller不会变)。正因如此,开发者需要记住应该将哪些代码添加到哪个类中。

AAIController

专门给AI用的Controller,让AI的行为树自行决策所控制Pawn的行动。少了例如玩家输入、相机等组件,多了用于寻路的Navigation组件、AI组件、任务Task组件。

AGameMode

基础概念

仅服务器拥有,定义游戏模式用的基础类型,掌握整体游戏流程。AGameModeBase是所有GameMode的基类,是经典AGameMode(UE4.14前)的简化版本。现在的AGameMode是AGameModeBase的子类,它更适用于标准对抗类游戏(如多人射击类),完善了对局和比赛的概念。

AGameState

所有端都共享同步的游戏状态数据,例如团队的分数、目标,还有玩家列表及其PlayerState。

APlayerState

所有端都共享同步的玩家自身状态数据,例如血量、子弹量、物品栏。

参考资料

  • InsideUE5 - 知乎 (zhihu.com)