下面是他们从「广州站」发来的照片: 我是怎么样勾搭上腾讯大佬的,云游戏帧同步初探!_3d 我是怎么样勾搭上腾讯大佬的,云游戏帧同步初探!_客户端_02

 

不说费话了,今天带来的是社区大佬「如若清风」这几天对腾讯云联机对战引擎的实践分享,并且他与腾讯大佬进行了深度交流,真的是获益匪浅!最近在用腾讯的小游戏联机对战引擎做一个帧同步游戏,由于是第一次写帧同步,当中遇到了很多问题。

 

一直在跟负责这个引擎框架的前端负责人交流(刘),请教他相关的问题。我其实很薄面子的,不太喜欢一直麻烦别人,无奈昨天的问题我各种尝试还是百思不得其解。于是,昨天晚上十一点多又向刘请教了帧同步的同步问题,直到一点才结束。

 

真的是非常感谢刘的帮助,每次都很耐心的给我这个小白讲解。我整理了其中比较有用的对话,以方便以后查看和参考。

 

视频是我最初做出来的效果,看起来同步的效果一般,还有很大的优化空间。另外,最后有个bug,我就是卡到这了。

 

谈话内容整理:

 

我:哈喽,还要麻烦你一下 。我做帧同步,人物摇杆移动,有时候会停不下来。想问下,这一帧会有很多个指令吧?我应该怎么把它复制到表现层呢。

 

刘:这一帧会计算出最终的状态,使用这个最终的就行了。

 

我:你指的最终状态是位置吗?那中间的位置,我怎么平滑,这一帧有很多个指令,需要顺序执行。

 

刘:你的游戏里面需要计算的全部状态。一个广播帧应该不需要的。

 

我:啥意思,一个广播帧,就计算最终位置就行吗?比如一个玩家这一帧有好几个位置和方向,就同步最后一个位置吗。这样会很卡的。比如有两个玩家,这个item length会大于2 ,比如是4,一个玩家就会在一个广播帧有两个指令,怎么处理。。移动的指令比较密集。客户端每次移动,我都会sendframe,然后会导致,一个广播帧会有多个指令。

 

刘:你可以等到回包之后再发下一个指令。密集发的话没有必要。即便密集发,合并在一个帧里面的操作也不好分割吧。。。建议在一个帧里面的操作,计算一个最终状态就行了。

 

我:对的,现在就是遇到这个情况,我也不知道咋分,客户端什么时候sendFrame呢?怎么知道什么时候回包?

 

刘:收到回调函数时回包。还有就是建议等到发送成功了之后再发下一个指令。

 

我:你这个意思是,客户端发送帧消息不要太密集了是吗。

 

刘:对的。

 

我:两种方式,1.不控制客户端sendframe的频率,这样会导致一个广播帧会有多个指令。这个时候,就计算最后一个指令的状态,同步到表现层。2.控制下客户端sendFrame的频率,相当于每个广播帧就是每个玩家只有一个指令。是这样吗?

 

刘:1.如果你的游戏有发射子弹、改变方向两个指令,这都要处理吧,不是说只处理最后一个,就是每个都要处理,计算出最终的状态。2.只是收到回调后发送下一个指令(针对摇杆),这里没有保证每个广播只有一个指令。

 

我:1.最终状态,是计算出来每个指令的最终状态,然后每个状态都同步到表现层吗?2.不保证只有一个指令,那还是跟第一种情况一样,每个指令都要计算是吗?

 

刘:计算整个游戏的逻辑状态,你应该有个地方保存了每个玩家的位置、子弹的位置吧。

 

我:那就需要存储一个数组。顺序的是吗,每个指令最终状态存放在一个state对象。

 

刘:嗯嗯,这就是你的游戏逻辑状态。是的。

 

我:那一个广播帧,我把所有指令的最终逻辑状态都计算出来,怎么同步到表现层。表现层我是通过 cocos的update的dt驱动的。上一个最终状态到下一个状态的时间间隔也是不确定的。我需要把一个广播帧下的所有指令都同步到表现层,才能保证表现层知道下一步动作啊

 

刘:广播计算游戏逻辑状态,比如当前玩家位置、速度、方向;然后把这个状态拷贝给表现层。表现层在update里面,使用dt、当前玩家位置、速度、方向,计算出新的位置,这个流程。计算状态时根据当前状态、时间间隔,计算出下一时刻的状态。逻辑层时间间隔是66ms,表现层时间间隔是dt。

 

我:对于摇杆移动,我的信息有摇杆方向和人物移动速度,还有人物当前位置。这哪些是指令哪些是状态呢。

 

刘:这个指令就是你发的帧消息,那我们就把它叫做指令。然后在帧广播里面拿了这个指令之后,他就是用来计算逻辑状态了,然后表现层的话应该是,从这个逻辑状态继续去计算出表现层的状态。

 

刘:比如说你现在正在做一个匀加速直线运动。然后你发了一个帧消息,把这个加速度突然变成了两倍,这样收到这个广播之后,首先要根据这个帧广播计算出玩家从上一个帧到这一帧最新的位置,他现在的加速度是多少,他现在的速度是多少,他现在的方向是什么,这就是你的逻辑状态了。然后,把这个逻辑状态拷贝到表现层。表现层会继续沿着这个逻辑状态使用一个dt去推算最新的位置。

 

我:我这摇杆的逻辑状态好像包括了指令,比如方向和速度。给我搞迷糊了。

 

刘:你现在这里的指令的话,确实是会包含在逻辑状态里面,因为你这边指令就是速度,具体速度的值。

 

我:我想着的是,一个广播帧下有多个指令,每个指令都计算了逻辑状态,也会同步到表现层。

 

刘:这样你不好控制,每个指令渲染多久呀。

 

我:是的,我现在就没计算渲染多久,直接把每个指令直接同步给表现层了。

 

blablabla以上暴露出来的问题太多,不好具体分析,于是就讨论我目前遇到的问题,为什么会出现移动时停不下来。

 

刘的分析是,发送消息sendframe都是异步的, 所以没办法保证哪个消息先到哪个后到的。也就是说我touchMove时传的isMoving为true,然后touchEnd时传isMoving为false,不保证消息传过去的最后一个isMoving是false。

 

建议等sendframe发送消息响应成功之后,也就是在回调函数里边再发送下一条指令,去保证消息的先后顺序。每次帧广播时,itemFrame长度大于0时,把内容打印出来。

 

由于我现在代码已经改的面目全非了。所以,今天的计划,是把代码先还原回去,然后确定下是否是因为消息的先后顺序原因。然后再做调整和优化。

 

道路阻且长啊!欢迎有帧同步经验的小伙伴留言,一起交流学习。 我是怎么样勾搭上腾讯大佬的,云游戏帧同步初探!_3d_03