请参加腾讯云沙龙「广州站」的伙伴,如果你通过公众号报名,并且邀好友同行的请来找我,为你们领取一本《腾讯游戏开发精萃》。目前已经有两位伙伴来领取了,分别是:
不说费话了
,今天带来的是社区大佬「
如
若清风
」
这
几天对腾讯云联机对战引擎的实践分享,并且他与腾讯大佬进行了深度交流,真的是获益匪浅!
最近在
用腾讯的小游戏联机对战引擎做一个帧同步游戏,由于是第一次写帧同步,当中遇到了很多问题。
一直在跟负责这个引擎框架的前端负责人交流(刘),请教他相关的问题。
我其实很薄面子的,不太喜欢一直麻烦别人,无奈昨天的问题我各种尝试还是百思不得其解。
于是,昨天晚上十一点多又向刘请教了帧同步的同步问题,直到一点才结束。
真的是非常感谢刘的帮助,每次都很耐心的给我这个小白讲解。
我整理了其中比较有用的对话,以方便以后查看和参考。
视频是我最初做出来的效果,看起来同步的效果一般,还有很大的优化空间。
另外,最后有个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时,把内容打印出来。
由于我现在代码已经改的面目全非了。
所以,今天的计划,是把代码先还原回去,然后确定下是否是因为消息的先后顺序原因。
然后再做调整和优化。
道路阻且长啊!
欢迎有帧同步经验的小伙伴留言,一起交流学习。
白玉无冰
阿海



Creator3D守护你的球球-uv动画与天空盒
Creator3D打砖块-子弹发射与摄像机平滑移动
Creator3D打砖块-场景材质与物理引擎
终于将 Shader 移植到 Cocos Creator 2.2.0 上了
如何在 Creator3D 中切换模型贴图,超级简单
