在多人版的游戏开发过程中,我们会经常碰到这样一个问题:由于每个客户端网络环境差异导致接收服务器消息的时间不同,就会导致多个客户端呈现的画面不同(即画面不同步),例如:以彩期开奖为例,客户端A已经收到开奖结果的推送了,但客户端B没有收到,如果不做任何处理,会导致后面画面的差异越来越大。

因为网络环境的差异是一个客观的问题,所以我们并不能保证每个客户端能在同一时间收到服务器推送的消息。但我们可以在代码逻辑上可以避免差异的扩大化,尽量保证之后的差异不受前面的影响。

另外一个大前提:既然是多人版,就应该用的是长连接。
短连接:是指通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。
长连接:多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是短连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,下次处理时直接发送数据包就OK了,不用建立TCP连接。
举一个很容易理解的例子:长短连接可比作为即时通话和语音。

本文以彩期下注开奖为例,做简单的同步,能基本保证画面同步。(长连接)

上图 gameStart为游戏开始(主动请求)、stopBet为停止下注(服务器推送)、gameResult为开奖结果(服务器推送)。
这里gameResult和gameComplete之间的时间是提供给客户端呈现开奖画面的时间(例如:转盘滚动到指定位置)
遇到的主要问题:
1.倒计时不同步(start和result结果之间会有一个开奖倒计时)
2.客户端由于网络延迟导致收到result消息晚了,导致画面不同步。(这里是收到结果之后才开始播动画)
3.两局之间衔接得不是很好(之前的做法是等到了gameComplete,也就是开奖动画结束后才开始请求下一局游戏,如果这个请求延迟了就会导致刚开始就画面不同步的问题)

首先处理问题3:直接给请求下一局预留缓冲,在拿到当前Result时候就去请求下一局的信息并保存下来。假若gameResult和complete之间有20s的时间,那么给这个请求和接收预留的缓冲时间就是20S。再假设20S都没接收到、那么建议是提示玩家重新连接游戏。

问题1和2有一个共性的问题就是:网络延迟。具体一点就是…算了,举例来说吧:假设客户端A给服务器发了一个gameStart的请求,发送这个请求的时间是T0。服务器在S0时收到这个请求,给客户端A发送应答消息。而客户端A收到这个请求的应答时间是T1,在这个gameStart的response数据中,服务端会告诉你它的当前服务器时间S1以及开奖时间S2。(用来做倒计时用)

不难看出,因为服务器时间是一直在走动的,如果发送和接收的时间差比较大的话(例如发送和接收均消耗10S),可能造成你收到的服务器时间误差较大。(你收到的是S1,其实当前服务器时间是S1+10)

有很多人的做法是取 S1+(T1 - T0)/2 作为当前服务器时间,这样做有一定的效果,但是当发送和接收消耗的时间差距较大时(例如发送到服务端时间为1S,消息应答从服务器返回消耗了19S),按上述计算出当前服务器时间为S1+10,但实际却为S1+19。

    Service.gameStart(data,this._newGame,this);this._sendTime = new Date().getTime();_newGame:funciton(data){this._receiveTime = new Date().getTime();   var currTime = data.currTime;//服务器当前时间var curServerTime = 0;var timeDiff = (this._receiveTime - this._sendTime)/2;if(timeDiff  < 500 || Math.abs(currTime -   ServerTimeUtils.getServerTime()) > 1000){curServerTime = ServerTimeUtils.updateServerTime(currTime+timeDiff);}else{curServerTime = ServerTimeUtils.getServerTime();}}

思路,即本地记录保存服务器时间LS,设置个clock让其一直走。
在上述公式基础上,加上判断:如果发送接收时间差小于1S,就按公式来即S1+(T1 - T0)/2。
如若大于1S,则服务器时间按LS来。
“Math.abs(currTime - ServerTimeUtils.getServerTime()) > 1000”这个判断只是为了第一次的LS初始化。

ServerTimeUtils(全局变量):

var ServerTimeUtils = {_serverTime: new Date().getTime(),serverTimeClock:function(){var self = this;global.timers.setInterval(function(){self._serverTime = self._serverTime + 1000;},1000)},getServerTime: function(){return this._serverTime;},updateServerTime: function(newServerTime){this._serverTime = newServerTime;}
}ServerTimeUtils.serverTimeClock();

问题2的遗留问题:即接收Result的快慢导致开奖转盘不同步问题,这里由于我的项目中转盘做的变减速运动、很难保证每个时间点转盘画面都同步。这里我是采取了一个折中的办法

    var turnTime = this._turnSeconds;var timeDiff = resultTime - ServerTimeUtils.getServerTime();//resultTime是服务端返result时返的服务器当前时间if(Math.abs(timeDiff) > 1000){if(resultTime > ServerTimeUtils.getServerTime()){turnTime = turnTime - Math.abs(timeDiff)/1000;}}else{ServerTimeUtils.updateServerTime(resultTime);}

思路:如果接收result时间慢了几秒,那么就让转盘转到目的位置的时间少消耗几秒。(即提高了速度)
这样保证了转盘指针到目的地的时间是一致的,即多个客户端即使受到result时间不同,到达目的地的时间也相同。这样做保证能同时进入下一局游戏。

时间画面同步个人感觉是一个比较复杂的问题、特别是前端逻辑以及动画比较复杂的环境。上述只能处理较简单的小游戏问题,而且还有部分极端情况未做处理(用重新登录去处理)。

cocos2dx 多人小游戏时间同步问题(简单版)相关推荐

  1. JS实现简单的吃豆人小游戏

    吃豆人小游戏 今天练习了一下JS,写了一个吃豆人的小demo Html以及CSS部分 首先定义一个div,用来存放吃豆人的一些元素,我们给他加一个id="game",然后我们在这d ...

  2. 基于C++控制台(Windows平台)的一个吃豆人小游戏

    PacManX --南京大学2019秋季学期 "高级程序设计 "课程设计一 基于C++控制台(Windows平台)的一个吃豆人小游戏 已实现的目标: 地图支持自定义编辑(可编辑地图 ...

  3. 整活~使用webAI做一个网页AR吃豆人小游戏

    一个好习惯,先给结论 使用网页端深度学习框架识别人脸,做一个AR吃豆人小游戏.吃豆人会随着人脸在镜头内的移动而移动,吃完全部豆子即为获胜. 在线体验地址:点我预览 代码地址:点我github 本文首发 ...

  4. 可怜的博主跟小豆人杠起来啦!Python制作的吃豆人小游戏,快来围观!!

    相关文件 关注小编,私信小编领取哟! 当然别忘了一件三连哟~~ 对了大家可以关注小编的公众号哟~~ Python日志 开发环境 Python版本:3.6.4 相关模块: pygame模块: 以及一些P ...

  5. CocosCreator 微信小游戏云函数简单使用

    转自  CocosCreator 微信小游戏云函数简单使用 - 简书 六边形站神关注IP属地: 湖南 2021.09.09 16:33:41字数 201阅读 554 后台编写云函数 首先在后台开通云开 ...

  6. 吊死人小游戏 2.0版本

    游戏名称: 吊死人小游戏2.0版本(4位数字版) 游戏玩法: 选择被吊的人物 每次输入4个数字 如果猜对其中至少一个数字,看做猜对了 如果一个也没猜中,看做猜错,被吊人物画一笔 全部猜中,并且被吊人物 ...

  7. 吊死人小游戏 1.0版本

    游戏名称: 吊死人小游戏1.0版本(4位数字版本) 游戏玩法: 每次输入一个4位数,表示你所猜4个数字. 如果你猜对了其中的几个数字,那么下方的4个问号中与你所猜对数字对应的数字将显现出来. 如果你猜 ...

  8. 用JAVA实现吃豆人小游戏

    用JAVA实现吃豆人小游戏 游戏运行效果 Model.java Pacman.java 完整的游戏代码及资源文件 游戏运行效果 Model.java package pacman;import jav ...

  9. C语言实现吃豆人小游戏(转载)

    c语言实现吃豆人小游戏(转载) 游戏内还有一些bug,凑活着来玩一玩吧! #include <stdio.h> #include <iostream> #include < ...

  10. Python 开发接豆人小游戏 TurnipBit

    Python 开发接豆人小游戏 TurnipBit 最近入手了一款MicroPython的开发板-TurnipBit,这个板子比较适合单片机入门,以及青少年编程,因为它有配备的在线图形编程. 官网地址 ...

最新文章

  1. LeetCode Elimination Game(递推法)
  2. linux的线程要makefile,Linux内核线程之父pid=2的kthreadd线程
  3. 【iOS XMPP】使用XMPPFramewok(五):好友列表
  4. 前端学习(2554):第一个vue程序
  5. 树莓派使用STEP8:使能串口调试
  6. python爬取知乎页面的LaTeX公式
  7. 如鹏网学习笔记(十二)HTML5
  8. Linux学习总结(2)——linux常用命令大全
  9. 8 -- 深入使用Spring -- 6...2 Spring支持的事务策略
  10. C 线性表的链式存储实现及插入、删除等操作示例
  11. 国内外接口文档工具哪家强?
  12. python用Selenium爬取携程网机票信息
  13. Linux 下 TC 命令原理及详解<一>
  14. 对抗样本论文学习:Deep Neural Networks are Easily Fooled
  15. LVGL学习——初识动画 lv_anim_t
  16. ant-design-vue 中标签页tab上额外的元素(tabBarExtraContent) , tab选项卡头增加文字
  17. 【逐梦旅程Windows游戏编程学习笔记 ①】基本GDI绘图
  18. 币圈神话的成就者,谷歌团队首发PlusFo
  19. Three.js--关于立体图像的设置
  20. C语言——函数递归实现

热门文章

  1. smartforms SE73 上传字体
  2. A星寻路算法(A* Search Algorithm),转载,见过最好的文章
  3. 为什么4S店一听到我要全款买车,就说没现车,朋友去问说贷款买,就说有现车?
  4. [免费]新增日期控件的下载
  5. 验证“哥德巴赫猜想” (20分)
  6. oracle标点占24个字符,oracle汉字占用字节长度,oracle汉字字节
  7. 华为云会议,助您轻松实现远程智能办公
  8. CSU 1976: 搬运工小明(二分)
  9. 微信+工业4.0定制化商品的分布式自动生产系统
  10. C\C++ Thread 分析线程detach()