4.3 KiB
title, date, excerpt, tags, rating
title | date | excerpt | tags | rating |
---|---|---|---|---|
在帧同步战斗上加入UE4的DS(专有服务器)的简单尝试 | 2022-12-09 15:10:14 | Online | ⭐ |
原文地址
帧同步框架下添加状态同步记录 https://zhuanlan.zhihu.com/p/399047125
在帧同步战斗上加入UE4的DS(专有服务器)的简单尝试 https://zhuanlan.zhihu.com/p/480154978
其他工程
https://github.com/HiganFish/UE4SpaceShipBattleOL
实现细节
DS本质上使用的是状态同步,那么大思路是参考我之前的一个文章参考帧同步框架下添加状态同步记录。
下面主要讲下实现的一些细节:
分离服务器和客户端逻辑 这个工作主要是把战斗中只需要在服务器执行的逻辑分离出来,比如属性数值计算相关,攻击碰撞检测,技能,buff释放逻辑,子弹释放逻辑,怪物AI等。大思路是服务器只下发角色属性和状态信息,客户端根据逻辑进行相应的状态切换(包括技能释放)但不会执行和真实逻辑有关的计算。
服务器和客户端通信方式 这里使用UE4提供的RPC调用。使用UStruct定义的结构作为协议。省去了自己实现序列化和反序列化的工作。
调整框架 因为使用DS后,GameModeBattle只存在于服务端。固客户端上的BaseBattle就需要另外找个地方可以更新。一番研究后选择了NetPlayerController(继承自PlayerController)。
根据Replication,客户端的NetPlayerController是由客户端连上服务器后,服务器创建然后复制给客户端的。RPC调用也是写在NetPlayerController里,不管是服务器调用客户端,还是客户端调用服务器。
调整单位创建流程 之前文章里的服务器其实只要跑逻辑部分,不需要Native层相关的资源。现在因为要使用CharacterMovementComponent和移动预测,服务器上的单位也必须把GameActor创建出来。创建后是由Replication复制到客户端,并且同时复制这个单位的逻辑唯一ID属性(PID)。
原本逻辑上是由BeActor创建GeActor并且创建GameActor。现在需要改成客户端收到服务器创建单位的消息后创建BeActor(也会设置PID)并且创建GeActor,但是不创建GameActor。等GameActor从服务器复制到客户端后在GameActor的StartPlay里启动绑定流程,把这个GameActor绑定到相同PID的BeActor的GeActor上。PID是服务器和客户端标识同一单位的属性。
删除的时候也是同理。客户端收到删除消息后,把BeActor以及GeActor删除,GameActor由Replication同步来删除。
这里顺便提下子弹 的做法。子弹因为一般都是以一定速度沿特定轨迹移动,所以没有继承CharacterMovementComponent。为了优化流量消耗,子弹的位置可以不需要服务器每帧更新。只需在创建信息把速度,创建轨迹等参数下发,客户端就可以自行创建这个子弹以及轨迹移动做表现。
使用UE4 CharacterMovementComponent 要使用CharacterMovementComponent,需要使用Character。于是原本的基于Actor的GameActor改为继承Character,并且设置相关的参数,调整碰撞胶囊体的大小。 修改逻辑自带的移动组件,主要是每帧把逻辑层的速度设置给MovementComponent的Velocity。并且每帧取得组件Location反设给自带移动组件。因为逻辑上层还是通过访问自带移动组件来进行位置的判断。 服务器上也需要每帧把逻辑的信息更新给CharacterMovementComponent,包括位置,旋转和缩放 使用移动预测 拥有CharacterMovementComponent的Character需要是ROLE_AutonomousProxy才可以进行预测。而且现在的框架上NetPlayerController是先创建,然后才会创建GameActor,因此需要在服务器上执行PlayerController的Posses函数来设置控制的Actor。 本地客户端对于ROLE_AutonomousProxy的GameActor需要在Run和Idle对CharacterMovementComponent设置Velocity来驱动组件移动。这样对于移动和停止的Idle,本地客户端不会等服务器的Replication就会立马进行。 而对于其他玩家和怪物,则是ROLE_SimulatedProxy,全程由Replication来进行位置变化 怪物寻路 使用navmesh,直接在服务器端调用navmesh寻路接口返回得到路径点,在原来的AI移动逻辑上调整代码沿着路径点行走即可。