100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 网络斗地主游戏的完整设计与实现(四)游戏状态更新机制与心跳机制

网络斗地主游戏的完整设计与实现(四)游戏状态更新机制与心跳机制

时间:2022-11-06 11:10:46

相关推荐

网络斗地主游戏的完整设计与实现(四)游戏状态更新机制与心跳机制

引言

在前一篇文章中讲解了通过入口存储过程动态调用业务过程的原理。下面来说明如何实现游戏状态的更新。

项目的源码可在CSDN资源中下载

实现原理

由于http协议是无状态的请求响应式协议,用户可以主动向服务器发起请求,得到回复。但如果服务器状态发生了变化,却不能直接地推送消息给用户。

在web应用中,消息推送是一个长期讨论的话题。现在已经有了比较成熟的解决方案,比如websocket。

不过本项目使用的是最基本的轮询方式,即客户端定时向服务器发起一个请求,检查是否有留给自已的消息,如果有属于自己的消息,则根据消息更新浏览器上显示的内容。与此同时,定时向服务器发起的请求,也是一个心跳信号,定时向服务器报告自己还活着。如果在指定的时间期限过后,还未收到某客户的心跳信号,服务器则会认为该客户已离线。

具体实现

项目引入了jquery.timers-1.2.js,这是一个可以实现定时功能的jquery扩展。

现在看一下源文件:GameEvents.js

//游戏过程中的各种事件,通过不断查询数据库中的公告信息,形成各种游戏事件处理框架function GameEvents(deskID,playerNo,onEnterRoom,onReady,onDealCards,onBid,onBidOver,onPlayCard,onGameOver,onExitRoom,onNoneBidOver,onSurrenderonTimeTick){//处理各种公告信息this.OnReceivedNoteInfo=function(result){var resObj=eval("("+result+")");//enter roomif (resObj.noteType == 1) {onEnterRoom(resObj.content);} ......}var eventHandler = this.OnReceivedNoteInfo;this.StartTime=new Date();this.start=function(){this.StartTime=new Date();//$('body').everyTime //$('body').oneTime $('body').everyTime ('1s','pluse',function(){callProc("readNote" , deskID +","+playerNo , eventHandler); onTimeTick();},0,true);} this.stop = function(){$('body').stopTime ('pluse');}this.ElapsedMinutes = function(){var nowTime = new Date();return parseInt(Math.abs(nowTime - this.StartTime)/1000/60);}}

其中的this.start方法

this.start=function(){this.StartTime=new Date(); $('body').everyTime ('1s','pluse',function(){callProc("readNote" , deskID +","+playerNo , eventHandler); onTimeTick();},0,true);}

实现每秒1次的定时请求,在这个请求中调用 callProc(“readNote” , deskID +","+playerNo , eventHandler);

按照上一篇文章的说明,这里调用了存储过程 readNote。现在看一下readNote存储过程

CREATEprocedure readNote(@deskID int,@playerNo int,@outMsg varchar(500) out)asbegin--更新到访时间update deskPlayer set lastTime = getdate()where deskID = @deskID and playerNo = @playerNo--接收通告declare @noteID intselect @noteID = min(noteID) from v_notewhere deskID = @deskID and receiverNo = @playerNoif @noteID is nullbeginset @outMsg='{noteType:0}'return 0enddeclare @noteType int,@content varchar(500)select @content = content,@noteType = noteType from note where noteID = @noteIDdelete noteRecipient where noteID = @noteID and playerNo=@playerNodelete note where noteID not in(select noteID from noteRecipient)set @outMsg='{noteType:'+cast(@noteType as varchar)+',content:' +@content + '}'return 0end

从以上代码可知,这个存储过程实现了两个功能,

一是将本次请求的访问时间记录在数据表 deskPlayer当中

二是从note 表中取出属于自己的通告消息

下面先看一下deskPlayer表

其中的lastTime列记录了每次用户的心跳,也就是调用存储过程readNote的时刻。

现在看一下检查用户是否离线的存储过程

CREATE procedure checkOffLineasbegin--检查是否有人离线declare @offPlayer table(idx int identity(1,1),roomID int,playerID int)insert into @offPlayer(roomID,playerID)select roomID,playerID from v_roomPlayer where dateDiff(second,lastTime,getdate()) > 5 -- off line secondsdeclare @roomID int,@offplayerID int, @offPlayerCnt intselect @offPlayerCnt = count(*) from @offPlayerdeclare @outMsg varchar(100)declare @i intset @i=1while @i <= @offPlayerCntbeginselect @roomID = roomID,@offplayerID = playerID from @offPlayer where idx = @iset @i = @i +1exec exitRoom @roomID,@offplayerID,@outMsg outendreturn 0end

其中的核心查询语句是

insert into @offPlayer(roomID,playerID)select roomID,playerID from v_roomPlayer where dateDiff(second,lastTime,getdate()) > 5 -- off line seconds

这个语句从v_roomPlayer 视图,该视图基于表deskPlayer,查找出当前时间与心跳报告时间之差大于5秒的记录。也就是说超过5秒,服务器都没有收到浏览器的心跳报告,就会被认为已经离线。

针对每一个被判定已经离线的用户,调用exitRoom存储过程,而在exitRoom存储过程向其它应该接收消息的用户留下公告消息,在1秒之后,其它活跃用户将会再次向服务器发起请求,就会得到用户离线的公告消息。

接下来看一下接收公告消息的实现

由playNo得到要接收的消息的noteID.

--接收通告declare @noteID intselect @noteID = min(noteID) from v_notewhere deskID = @deskID and receiverNo = @playerNo

在这里要解释一下,为什么不用用户的ID,而是要用playerNo做为查询的依据。 playerNo是在一张牌桌上用户的编号,取值只能是1,2,3中的一个,分别代表西,南,东三个方位的玩家。而playerID是用户的唯一ID,但这个ID不能代表玩家在牌桌上的方位。 而且比较有趣的一点是,对于每个浏览器前的用户而言,他的方位永远是南方,但是它分配得到的playerNo在用户没有离开时永远保持不变。

下面先看一下note表,此表中记录的所有的公告消息

以上的公告消息在readNote过程中,如果已经被读取,则会被删除掉。

小结

将心跳机制与公告消息机制结合起来,运用轮询的方式实现游戏状态的定时更新。在未引入websocket的前提下,该方案不失为一种简单方便的解决方案。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。