《Exploring in UE4》游戏角色的移动原理(下)

本文深入分析了UE4(Unreal Engine 4)游戏中,多个玩家角色移动同步的处理方法,包括服务器角色的正常移动流程、客户端自治(Autonomous)角色和模拟(Simulated)角色的移动流程。移动同步基于RPC不可靠传输,通过移动组件的RPC函数实现。文章探讨了移动带宽优化、移动合并策略,以及如何处理客户端的移动预测和服务器的移动修正,确保网络游戏中角色移动的一致性。此外,还介绍了Simulate角色的移动流程,包括客户端的模拟更新和服务器数据的接收与修正。
摘要由CSDN通过智能技术生成

前言

上一篇主要从单机角色的移动原理进行分析。今天这篇文章会详细的分析多个玩家的移动同步是如何处理的。文章的内容可能比较深,需要读者有一定游戏开发经验,而且结合引擎源码才能更好的理解,建议收藏找时间慢慢阅读。

知乎原文链接:https://zhuanlan.zhihu.com/p/34257208

下篇

四.移动同步解决方案

前面关于移动逻辑的细节处理都是在PerformMovement里面实现的,我们可以把函数PerformMovement当成一个完整的移动处理流程。这个流程无论是在客户端还是在服务器都必须要执行,或者作为一个单机游戏,这一个接口基本上可以满足我们的正常移动了。不过,在网络游戏中,为了让所有的玩家体验一个几乎相同的世界,需要保证一个具有绝对权威的服务器,这个服务器可以修正客户端的不正常移动行为,保证各个客户端的一致性。相关同步的操作都是基于UCharacterMovement组件实现的,所以我们的角色必须要使用这个移动组件。

移动组件的同步全都是基于RPC不可靠传输的,你会在UCharacterMovement头文件里面看到多个以Server或者Client开头的RPC函数。

关于移动组件的同步思路,建议选阅读一下官方文档的内容,回头看可能更为清晰一点。现在我们把整个移动细节作为一个接口封装起来,宏观的研究移动组件的同步细节。

另外,如果还没有完全搞清Authority,AutonomousProxy以及SimulatedProxy的概念,请参考我的知乎文章 “UE4网络同步详解(一)——理解同步规则”。这里举个例子,一个服务器上有一个玩家ServerA和一个NPC ServerB,客户端上拥有从服务器复制过来的这个玩家ClientA与NPC ClientB。由于ServerA与ServerB都是在服务器上生成的,所以他们两在服务器上的所有权Role都是ROLE_Authority。ClientA在客户端上由于被玩家控制,他的Role是ROLE_AutonomousProxy。ClientB在客户端是完全通过服务器同步来控制的,他的Role就是ROLE_SimulatedProxy。

4.1 服务器角色正常的移动流程

第三章节里面的图3-1就是单机或者ListenServer服务器执行的移动流程。作为一个本地控制的角色,他只需要认真的执行正常的移动(PerformMovement)逻辑处理即可,所以ListenServer服务器移动不再赘述。

但是对于DedicateServer,他的本地没有控制的角色,对移动的处理就有差异了。分为两种情况:

  • 该角色在客户端是模拟(Simulate)角色,移动完全由服务器同步过去,如各类AI角色。这类移动一般是服务器上行为树主动触发的。

  • 该角色在客户端是拥有自治(Autonomous)权利的Character,如玩家控制的主角。这类移动一般是客户端接收玩家输入数据本地模拟后,再通过RPC发给服务器进行模拟的。

从下面的代码可以了解到这两种情况的处理(注意注释):

// UCharacterMovementComponent:: TickComponent
// simulate的角色在服务器执行IsLocallyControlled也会返回true
// Allow root motion to move characters that have no controller.
if( CharacterOwner->IsLocallyControlled() || (!CharacterOwner->Controller && bRunPhysicsWithNoController) || (!CharacterOwner->Controller && CharacterOwner->IsPlayingRootMotion()) )
{
   {
       SCOPE_CYCLE_COUNTER(STAT_CharUpdateAcceleration);


       // We need to check the jump state before adjusting input acceleration, to minimize latency
       // and to make sure acceleration respects our potentially new falling state.
       CharacterOwner->CheckJumpInput(DeltaTime);


       // apply input to acceleration
       Acceleration = ScaleInputAcceleration(ConstrainInputAcceleration(InputVector));
       AnalogInputModifier = ComputeAnalogInputModifier();
   }


   if (CharacterOwner->Role == ROLE_Authority)
   {
       // 单机或者DedicateServer控制simulate角色移动
       PerformMovement(DeltaTime);
   }
   else if (bIsClient)
   {
       ReplicateMoveToServer(DeltaTime, Acceleration);
   }
}
else if (CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy)
{
   //DedicateServer控制自治客户端角色移动
   // Server ticking for remote client.
   // Between net updates from the client we need to update position if based on another object,
   // otherwise the object will move on intermediate frames and we won't follow it.
   MaybeUpdateBasedMovement(DeltaTime);
   MaybeSaveBaseLocation();


   // Smooth on listen server for local view of remote clients. We may receive updates at a rate different than our own tick rate.
   if (CharacterMovementCVars::NetEnableListenServerSmoothing && !bNetworkSmoothingComplete && IsNetMode(NM_ListenServer))
   {
       SmoothClientPosition(DeltaTime);
   }
}

这两种情况详细的流程我们在下面两个小结分析。

4.2 Autonomous角色

一个客户端的角色是完全通过服务器同步过来的,他身上的移动组件也一样是被同步过来的,所以游戏一开始客户端的角色与服务器的数据是完全相同的。对于Autonomous角色,大致的实现思路如下:

客户端通过接收玩家的Input输入,开始进行本地的移动模拟流程,移动前首先创建一个移动预测数据结构FNetworkPredictionData_Client _Character,执行PerformMovement移动,随后保存当前的移动数据(速度,旋转,时间戳以及移动结束后的位置等信息)到前面的FNetworkPredictionData里面的SavedMoves列表里面,并通过RPC将当前的Move数据发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值