UE5-MPTPS-2
前言
今天完成了教程的 34-37 小节,对应 GitHub 上 2022-2-17 这一天的提交,内容主要为网络设置及武器的简易基类,以及一些 UI。
虽然内容并不多,但是网络部分设计的知识点比较多,这里记录一下。
多人游戏中的关卡切换
无缝 ( seamless ) 与非无缝 ( non-seamless ) 切换
UE4中,Server有2种主要的travel方式:Seamless和non-seamless。Swamless travel是非阻塞的操作,non-seamless是阻塞操作。Travel后,所连接的客户端会一起进入新的地图。当客户端执行non-seamless travel时,client会先和当前server断开,然后重新连接到这个server,此时新的map已经就绪,会再经历一次PreLogin、Login、PostLogin事件。UE4推荐使用seamless travel,更平滑,可以避免重新连接过程中的不稳定因素,而且可以使用一个自定义的TransitionMap来掩盖加载地图的耗时,给玩家一个更好的体验。
有三种情形中必然产生非无缝转移:
-
初次加载地图时
-
初次作为客户端连接服务器时
-
想要终止一个多人模式游戏并启动新游戏时
有三个用来驱动转移的主要函数:UEngine::Browse
、UWorld::ServerTravel
和 APlayerController::ClientTravel
。
UEngine::Browse
-
就像是加载新地图时的硬重置。
-
将始终导致非无缝切换。
-
将导致服务器在切换到目标地图前与当前客户端断开连接。
-
客户端将与当前服务器断开连接。
-
专用服务器无法切换至其他服务器,因此地图必须存储在本地(不能是 URL)。
UWorld::ServerTravel
-
仅适用于服务器。
-
会将服务器跳转到新的世界/场景。
-
所有连接的客户端都会跟随。
-
这就是多人游戏在地图之间转移时所用的方法,而服务器将负责调用此函数。
-
服务器将为所有已连接的客户端玩家调用
APlayerController::ClientTravel
。
APlayerController::ClientTravel
-
如果从客户端调用,则转移到新的服务器。
-
如果从服务器调用,则要求特定客户端转移到新地图(但仍然连接到当前服务器)。
启用无缝切换
要启用无缝切换,需要设置一个过渡地图。这需要通过 UGameMapsSettings::TransitionMap
属性进行配置。该属性默认为空,如果游戏保持这一默认状态,ue 就会为过渡地图创建一个空地图。
Transition map 为什么需要,是因为当前必须有一个 world 被加载(拥有map),因此当我们 loading 新地图时不能释放老地图,于是需要一个体积很小的 transition map 作为中转。这样便可以从当前地图转移到过渡地图,再从那里转移到最终的地图。由于过渡地图非常小,因此在 “中转” 当前地图和最终地图时不会造成太大的资源消耗。
设置 AGameModeBase::bUseSeamlessTravel
为 true
,就可以使用 seamless travel。
SeamlessTravel 流程
通过GetSeamlessTravelActorList保留Actor的大致流程为:
- 标记保留到Transition Level的actors
- Travel 到Transition Level
- 标记保留到Destination Level的actors
- Travel到final level
SeamlessTravel 过程中保留 actors
SeamlessTravel 到新的 Level 后,原 Level 的大部分对象都会销毁,但 Seamless travel 可以保留当前 level 的一些 actors 到新的level。这比较有用,我们可以把一些actor带到下个地图继续使用,还可以把一些需要传递的信息封装成actor,从而完成信息的跨地图传递,如道具栏物品和玩家等
默认这些actors会被自动保留:
- GameMode actor(server only) 以及任何通过
AGameModeBase::GetSeamlessTravelActorList
额外添加的任何 actors - 任何拥有有效
PlayerState
的 Controllers(server only) - 所有
PlayerControllers
(server only) - 所有
local PlayerControllers
(server和client)以及通过APlayerController::GetSeamlessTravelActorList
(在local PlayerControllers
上调用)额外添加的任何 actors
由于 seamless travel 的流程为 current map -> transition map -> destination map
,因此 “保留” 的含义是可以在 map 之间保留,而至于是保留到 TransitionMap,还是保留到 DestinationMap,不同的 Actor 有些不同。比如 GameMode
,默认只会保留到TransitionMap,而 PlayerController
默认会保留到 DestinationMap。至于我们自己通过 GetSeamlessTravelActorList
添加的Actor,则可以自定义要传递到 TransitionMap 还是 DestinationMap 。
ENetRole
AActor
中有个 ENetRole Role
变量用来识别角色的 Actor 的身份。ENetRole
是一个枚举类型:
1 | /** The network role of an actor on a local/remote network context */ |
在项目中,为 OverheadWidget
定义如下函数:
1 | void UOverheadWidget::ShowPlayerNetRole(APawn* InPawn) |
启动三个游戏实例,其中一个作为 Listen Server,其余作为 Client,结果如下:
可以看出,Server 端的全部角色都是 ROLE_Authority
枚举类型。
- Client 端
相比较而言,两个客户端则只有自己控制的角色是 ROLE_AutonomousProxy
类型而其余角色均为 ROLE_SimulatedProxy
类型。
看起来十分合理,但是更深层次的内容还是得继续学习。