前言
- 多图, 不想在源代码写注释, 不想贴代码块, 看的不清楚
- 版本4.21混4.22, 区别不大
- 文章属于旧有文章搬运, 之前在csdn上面
- 2019.10.27修改一版
物体位置信息同步, 或者说物体的移动同步, 是一个很大的坑, 从个人目前魔改UE4位置同步后, 感觉至少要考虑以下几点
- 位置信息的数据结构
- 要减少单次网络同步时的传输数据大小, 但也要包含所需要的完整的位置信息.
- 同时在降低精度的情况下减少一些数据的大小, 例如降低Location和Rotation的精度, 用更少的位数传播
- 位置信息的同步触发时间, 生成时间
- 指控制什么时候位置进行网络同步, 什么时候不需要同步. 以及什么时候生成需要同步的位置信息
- 位置信息的权威端
- 以哪一端或者哪里的物体位置, 当做最新位置同步, 作为权威端
- 如果权威端只在服务器, 那很简单.
- 如果权威端只在单一客户端, 服务器做验证处理, 此时逻辑也比较简单, 客户端发送位置到服务器, 服务器直接应用(不考虑防作弊, 防作弊的话此时权威端还是服务器, 实现会很复杂和麻烦)
- 如果权威端在多个客户端和服务器之间切换, 嗯, 坑很深....
- 接受到位置信息之后的处理, 减少网络传输的延迟频率丢失的一些位置信息带来的影响, 使得整个物体移动平滑, 例如游戏中的角色运动同步
- 这里面学问很深, 自行百度谷歌(找不到当初看学习的文章了)
- 判断位置同步信息是否有意义, 丢弃掉无用的位置信息
- 对旧的信息不做处理, 主要是解决网络的丢包, 延迟等带来的问题
- 对不是权威端的信息不做处理, 解决一些事件调用先后顺序有别, 状态同步不及时等等的时序问题
UE4 的位置同步是一个比较常用的功能, 实现也比较简单, 只是服务器当方向向客户端同步物体的位置信息.
下文将深扒一下位置同步的代码实现, 以及对一些有坑的地方进行描述.
关键函数和结构体信息
/** Returns the properties used for network replication */
virtual void AActor::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const// 在属性同步前调用的一个函数, 这里生成需要同步的位置信息, 并重写是否需要位置同步
/*** Called on the actor right before replication occurs. * Only called on Server, and for autonomous proxies if recording a Client Replay.*/
virtual void AActor::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker )// 生成物体同步信息的函数
/** Fills ReplicatedMovement property */
virtual void GatherCurrentMovement();// 位置同步的结构体信息
/** Used for replication of our RootComponent's position and velocity */
UPROPERTY(EditDefaultsOnly, ReplicatedUsing=OnRep_ReplicatedMovement, Category=Replication, AdvancedDisplay)
struct FRepMovement ReplicatedMovement;// Attach相关的结构体信息
/*** Used for replicating attachment of this actor's RootComponent to another actor.* This is filled in via GatherCurrentMovement() when the RootComponent has an AttachParent.*/
UPROPERTY(Transient, ReplicatedUsing=OnRep_AttachmentReplication)
struct FRepAttachment AttachmentReplication;
同步属性相关
从最开始的地方说起, UE4中物体位置同步是靠Actor本身属性同步实现的, 如下:
- bReplicateMovement 控制是否进行同步
- AttachmentReplication 同步Attach相关, 是一个FRepAttachment, 即Relative Position(相对位置)
可以看到这个结构体里面是一个相对位置的同步信息
- ReplicatedMovement 同步位置信息, 绝对位置
同步基础的位置信息, 会同步物理状态
LocationQuantizationLevel, VelocityQuantizationLevel, RotationQuantizationLevel三个值是精度, 可以控制Vector和Rotator用多少位传输
控制属性同步及生成位置信息
在属性同步前, 需要生成位置同步信息, 并修改同步条件
ReplicatedMovement同步条件 bReplicateMovement为True
AttachmentReplication同步条件 根组件存在并且根组件不同步
然后我们看一下GatherCurrentMovement函数
- 该函数在每次属性同步前都会被调用, 以生成相应的位置信息.
- bReplicateMovement 生成 ReplicatedMovement
- RootComponent->GetAttachParent() 生成 AttachmentReplication
- 判断是否开启物理, 物理的同步和没有物理的同步方式不一样
- 开启物理时
- 会同步位置旋转速度和是否休眠
- 同时注意在Welded时, 不会进行物理同步(没有接触过)
- 没有开启物理的情况下
- 如果有父组件, 相对位置, 生成AttachementReplication
- 如果无, 绝对位置, 生成ReplicatedMovement
/*** 因为工作项目对物体同步相关进行过魔改* 有时候会碰到服务器和客户端物体缩放不同步, 不确定是魔改后的问题还是UE4的问题* 这个问题未深入研究, 是否存在? 发生条件等都不明确* 可能什么时候深扒Actor的生成和初始化同步会明白些 */
同步后的处理
这个时候的处理就比较简单了, 在这两个函数中将这些信息设置到本地就行了
OnRep_ReplicatedMovement
有兴趣的自己扒吧
OnRep_AttachmentReplication
判断AttachParent是否存在是Attach还是Detach
Detach就很简单了, 直接调用DetachFromActor然后判断是否同步位置, 如果同步, 则调用用OnRep_ReplicatedMovement, 应用绝对位置
有坑见下文
一个的问题
注意一下这段长长的注释, 绝对是4.21版本修复的.
Attach相关的相对同步, 会造成上面说的那个问题
这个问题会导致什么呢?
Detach相关的函数同步处理时, 会调用OnRep_ReplicateMovement函数
但由于没有开启bReplicateMovement, ReplicatedMovement属性为空, 是无效值
但由于数据不存在, 会让Actor位置, 旋转归零.
所以, 如果版本较低的请注意了
4.19前绝对有这个bug, 那时候魔改物体同步时, 踩过这个坑
4.20 应该也没有, 工作用的20, 最近再次碰到过这个坑
但自己电脑上只装了15和21(其他的都卸载了), 没有办法(懒)验证了
4.21版本才修复4.21版本才修复4.21版本才修复
结语
- 能用UE4最新的版本就有最新的版本, 虽然会踩很多新坑, 但比踩那些已知bug待修复的坑好的多
- 2019.10.27, 有时候踩坑踩着, 最后查到官方, 一句已知bug, 某某版本修复.... 很无语...
- UE4同步相关的处理做好, 这里位置同步的是实现感觉很简单了
- 骗赞了, 骗评论了, 不要再一次单机啊.
- 2019.10.27, 看到这个单机.... 嗯, 没有单机了....