UE的Gameplay框架(一) —— GameMode与GameState

本系列简单总结下UE的Gameplay框架是怎么样的,基本上是博主看文档+实践之后得到的个人理解,如果有问题欢迎评论区指出。



简单框架


这里引用UE官网文档的框架图,首先游戏本身有 GameModeGameState 两大类,GameMode由游戏的基础规则构成,而基于游戏规则发生的事件产生的信息由 GameState 保存并同步给客户端。

玩家通过 PlayerController 加入到游戏中,既然是和玩家直接交互,必然要提供一些与玩家相关的接口/功能,比如 Input 接收玩家的输入(键盘/鼠标/手柄),HUD 提供UI显示(比如玩家的血条),PlayerCameraManager 管理玩家的相机。

而且 PlayerController 作为中间层,接收到玩家的输入,会去操作其管理的 Pawn,比如移动、攻击等。这里也可以看到 Pawn 既可以被 PlayerController 控制也可以被 AIController 控制,并且需要注意的是,PlayerController 可以随时 Possess 和 UnPossess 一个 Pawn,可以想象一个玩家其实可以切换不同角色进行游戏的,而且这些角色本身对于玩家的输入可以有不同的响应,通过 PlayerController 这一层将玩家(玩家的输入/提供给玩家的画面/UI)和玩家操作的角色解耦是很直观的吧。

这里还需要注意的是,有些数据/属性是玩家固有的(比如玩家的命数/玩家获得的金币数),这些信息保存在 Pawn 里是不合适的,保存在 PlayerController 也是不那么合适的,特别是考虑的多人游戏的场景,PlayerController 本身是不会同步到其它的客户端的,那么其它客户端想获取这个数据就困难了。所以UE里还有一个类 PlayerState 用来保存与玩家强相关的数据/属性。


GameMode 和 GameState

下面引用自UE官方文档

两个主要类负责处理进行中游戏的相关信息:Game ModeGame State
即使最开放的游戏也拥有基础规则,而这些规则构成了 Game Mode。在最基础的层面上,这些规则包括:

  • 出现的玩家和观众数量,以及允许的玩家和观众最大数量。
  • 玩家进入游戏的方式,可包含选择生成地点和其他生成/重生成行为的规则。
  • 游戏是否可以暂停,以及如何处理游戏暂停。
  • 关卡之间的过渡,包括游戏是否以动画模式开场。

基于规则的事件在游戏中发生,需要进行追踪并和所有玩家共享时,信息将通过 Game State 进行存储和同步。这些信息包括:

  • 游戏已运行的时间(包括本地玩家加入前的运行时间)。
  • 每个个体玩家加入游戏的时间和玩家的当前状态。
  • 当前 Game Mode 的基类。
  • 游戏是否已开始。

从官网文档给出的定义能看出 GameMode 用来定义和实现规则,GameState 用存储和同步游戏中的信息(这里的信息感觉是和个体无关的,是整个游戏的信息),对于多人联机游戏来说, GameMode 本身只存在于服务器,所以要同步信息需要一个 GameState,其随 GameMode 创建,之后被复制到所有远程客户端。

在大钊的InsideUE5中有提到UE将逻辑和资源场景进行了解耦,World 更多的是逻辑的概念,而Level是资源场景表示,一场游戏中,玩法再复杂但也只有一个,场景却可以无限大,所有可以有很多个场景区域拼接组装而成,因此是World包含Level,而不是反过来。而 GameModeGameState 我个人理解就是依附于 World 存在的。

下面我们从 GameModeGameState 给出的方法和属性出发,更具体地分析一下。

GameMode

首先4.14版本之前,AGameModeGameMode 的基类,因为做UE的公司本身自己也做游戏嘛,主要是做带有竞技性的多人联机游戏,那么可能对于一些游戏类型,AGameMode 本身太过庞大了,有些功能是没必要的。所以在 4.14 版本加入了 AGameModeBase 作为所有 Game Mode 的新基类,其本身更简洁高效,是新代码项目中包含的全新默认游戏模式。

然后还需要注意的是,并不是一款游戏只能有一个 GameMode,对于游戏的不同比赛模式、任务类型或特殊区域都可以创建不同类型的 GameMode。但是一个时间只能使用一个 Game Mode,每次关卡进行游戏实例化时 Game Mode Actor 将通过 UGameEngine::LoadMap() 函数进行实例化。

GameMode的功能可以简单总结如下:

  1. 游戏内实体的spawn
    我们在GameMode中指定的一些类,就是为了让GameMode能够知道具体要创建的对象的类
  2. 游戏内状态
    比如生成一个玩家pawn(重生玩家),暂停游戏
  3. Level的切换
    准确地说是World的切换时的行为,比如决定刚进入一场游戏的时候是否应该播放开场动画(cinematic),切换到下一个关卡是否要使用无缝漫游(bUseSeamlessTravel),一旦使用无缝漫游,可以重载 GameModePlayerControllerGetSeamlessTravelActorList 方法来指定哪些Actors不被释放而进入下一个World的Level。

无论是否使用无缝漫游,当前的World都会被释放掉,然后加载创建新的World,所以要小心GameMode 里保存的状态消失。

void AGameMode::GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList)
{
	UWorld* World = GetWorld();

	// Get allocations for the elements we're going to add handled in one go
	const int32 ActorsToAddCount = World->GameState->PlayerArray.Num() + (bToTransition ?  3 : 0);
	ActorList.Reserve(ActorsToAddCount);

	// always keep PlayerStates, so that after we restart we can keep players on the same team, etc
	ActorList.Append(World->GameState->PlayerArray);

	if (bToTransition)
	{
		// keep ourselves until we transition to the final destination
		ActorList.Add(this);
		// keep general game state until we transition to the final destination
		ActorList.Add(World->GameState);
		// keep the game session state until we transition to the final destination
		ActorList.Add(GameSession);

		// If adding in this section best to increase the literal above for the ActorsToAddCount
	}
}
  1. 多人游戏的步调同步
    AGameMode 提供的一些额外的功能以支持多人游戏。其包含一个跟踪比赛状态或整体游戏流程的状态机。

GameState

GameState 正如前文所述,其应该管理所有已连接客户端已知的信息(特定于 GameMode 但不特定于任何个体玩家)。它能够追踪游戏层面的属性:

  • 已连接玩家的列表,通过 PlayerArray 获取到所有连接玩家的 APlayerState 对象的阵列
  • 同步服务器的时间戳,通过 GetServerWorldTimeSeconds 将在客户端和服务器上同步
  • 使用 HasBegunPlay 判断一个Actor是否调用过 BeginPlay
  • 保存并同步其它与游戏有关而与个人无关的数据,比如开放世界游戏中已完成的任务,夺旗游戏中的团队得分等。

参考资料

Game Mode 和 Game State

《InsideUE4》GamePlay架构(七)GameMode和GameState

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值