关卡切换

前言

UE4 中主要有两种转移方式:无缝和非无缝方式

我们平时用的最多的OpenLevel节点就是非无缝的, 本文主要对这些方式记录一番

OpenLevel

image-20210519170513578

这是我们最常用的关卡切换的方法, 本质上都是从客户端调用了GEngine->SetClientTravel()函数, 然后到下一帧的时候调用 UEngine::Browse()

UEngine::Browse

  • 就像是加载新地图时的硬重置。
  • 将始终导致非无缝切换。
  • 将导致服务器在切换到目标地图前与当前客户端断开连接。
  • 客户端将与当前服务器断开连接。
  • 专用服务器无法切换至其他服务器,因此地图必须存储在本地(不能是 URL)。

引用官网的一段话来解释这个方法

UWorld::ServerTravel

此方式为无缝切换

先引用一个端官网的话

  • 仅适用于服务器。
  • 会将服务器跳转到新的世界/场景。
  • 所有连接的客户端都会跟随。
  • 这就是多人游戏在地图之间转移时所用的方法,而服务器将负责调用此函数。
  • 服务器将为所有已连接的客户端玩家调用 APlayerController::ClientTravel

比如多个玩家在完成连接了以后一起下副本就需要使用此方法讲所有人一起传送到指定关卡中, 不然就断开了

此方法需要cpp的支持, 纯蓝图无法完成这个操作;

蓝图无法调用这个方法, 我们先封装一个函数库

1
2
3
4
5
6
7
8
9
10
11
bool UFlib_Utilities::ServerTravel(const UObject* WorldContextObject, const FString& InURL, bool bAbsolute, bool bShouldSkipGameNotify)
{
if (WorldContextObject)
{
if (UWorld* wd = WorldContextObject->GetWorld())
{
return wd->ServerTravel(InURL, bAbsolute, bShouldSkipGameNotify);
}
}
return false;
}

image-20210520102036305

GameMode

首先要开启传送选项

1
bUseSeamlessTravel = true;

然后需要重写如下方法

1
virtual void GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList) override;

为了方便蓝图扩展, 我们声明一个蓝图方法来添加额外的传送对象

1
2
UFUNCTION(BlueprintImplementableEvent)
TArray<AActor*> BP_GetSeamlessTravelActorList();
  • 最终形态
1
2
3
4
5
6
7
8
9
10
11
AUtilityGameModeBase::AUtilityGameModeBase()
{
bUseSeamlessTravel = true;
}
void AUtilityGameModeBase::GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList)
{
//父类方法添加了PlayerController等, 必须得调用
Super::GetSeamlessTravelActorList(bToTransition, ActorList);
ActorList.Append(BP_GetSeamlessTravelActorList());
}

image-20210519172551789

PlayerController

服务器将为所有已连接的客户端玩家调用 APlayerController::ClientTravel

所以在玩家控制器里, 同样有方法支持传送目标

  • 最终形态
1
2
3
4
5
6
void AMyPlayerController::GetSeamlessTravelActorList(bool bToEntry, TArray<class AActor*>& ActorList)
{
Super::GetSeamlessTravelActorList(bToEntry, ActorList);
ActorList.Append(BP_GetSeamlessTravelActorList());
}

过渡地图

image-20210519171342531

我们可以在项目设置里设置一个过渡地图, 不过因为这个地图就一瞬间就完成了, 个人觉得意义不大

总结

  1. 只有服务端可以发起传送
  2. 玩家和玩家控制器会默认传送
  3. 多数状态(变量)不会传送, BeginPlay()等会重新执行一遍
  4. 测试发现对新创建的对象的静态模型修改材质/Scale3D等会传送到新关卡
  5. 玩家模型修改材质\Scale或者修改动画状态都无法传送到新关卡(问号脸)
  6. 如果是放置/Spawn在世界空间的对象, 传送以后会出现在相同位置
  7. Attach等操作无法传送, 如果一把武器在0点创建后Attach到玩家手上并添加到传送列表,传送以后还是出现在0点并不会Attach到玩家手上
  8. 对于GameMode的传送对象, 如果未开启同步, 那么只会在服务端传送
  9. 对于PlayerController的传送对象, 如果未开启同步, 只会在本地传送

测试

录制_2021_05_19_18_27_22_113

  1. 服务端创建cube
  2. 客户端创建sphere
  3. 创建5秒以后修改scale和材质为红色
  4. 传送以后颜色和scale传递了过去

录制_2021_05_19_18_32_04_186

  1. 修改玩家模型的材质和缩放
  2. 无法传送这些状态