房卡麻将分析系列 "牌局回放" 之 数据设计详解及实例

房卡麻将分析系列 "牌局回放" 之 数据设计详解及实例,第1张

概述房卡麻将分析系列\"牌局回放\"之数据设计                           

房卡麻将分析系列 "牌局回放" 之 数据设计                                                                   @H_403_3@

             最近几个月,”房卡“棋牌游戏成为了资本追逐的热点,基于微信的广大用户和社交属性,”房卡”棋牌发展迅速。红孩儿团队因为之前几年有过相关项目的经验积累,鉴于未来广阔的地方棋牌市场和”开发间“机制的发展前景,也开始转向基于”开房间“棋牌游戏的项目开发中。为了更好的与开发者进行交流学习,特开设”房卡麻将游戏分析系列“。

                                                                            红孩儿团队研发的"大赢家"红中麻将

           本套麻将分析基于网络上流传的“网狐”房卡麻将源码做为基础,按照功能模块分为"架设指南",”服务器框架","后台系统","胡牌算法","客户端界面",“防作弊功能”等等细节做一些分析和指导,帮助广大的棋牌游戏开发者迅速掌握“房卡”麻将的研发原理和技巧设计。也希望有兴趣的朋友多多关注。

       第一次开公众号,挑个简单的下手,先来讲一讲房卡麻将中一个重要功能:“牌局回放”,我们都知道,棋牌类游戏注重公平真实不作弊,如果玩家感觉到游戏的过程有作弊,我相信他一定会对这款游戏失去兴趣。但作弊与否,玩家并不容易进行判断。这时候提供一个“牌局回放”功能给玩家进行分析就尤为重要。

       “网狐”等一些长期耕耘在棋牌领域的企业,在这方面都有完整的经验和框架,通过参考,我发现它是通过下面一套流程来完成”牌局回放“功能的。

        首先,在游戏服务器的房间类CtableFrameSink里需要有一个GameRecord结构,这个结构对 玩家信息,手牌以及每一步的动作都可以进行相应的记录:

struct GameRecordplayer {   DWORD DWUserID;   std::string khead;   std::string kNickname;   std::vector<BYTE> cbCardData;   voID StreamValue(datastream& kData,bool bSend)   {     Stream_VALUE(DWUserID);     Stream_VALUE(khead);     Stream_VALUE(kNickname);     Stream_VECTOR(cbCardData);   } };  struct GameRecordOperateResult {   enum Type   {     TYPE_NulL,TYPE_OperateResult,TYPE_SendCard,TYPE_OutCard,TYPE_ChiHu,};    GameRecordOperateResult()   {     cbActionType = 0;     wOperateUser = 0;     wProvIDeUser = 0;     cbOperateCode = 0;     cbOperateCard = 0;   }    BYTE    cbActionType;   WORD    wOperateUser;            // *** 作用户   WORD    wProvIDeUser;            //供应用户   BYTE    cbOperateCode;           // *** 作代码   BYTE    cbOperateCard;           // *** 作扑克    voID StreamValue(datastream& kData,bool bSend)   {     Stream_VALUE(cbActionType);     Stream_VALUE(wOperateUser);     Stream_VALUE(wProvIDeUser);     Stream_VALUE(cbOperateCode);     Stream_VALUE(cbOperateCard);   } };  struct GameRecord {   std::vector<GameRecordplayer>   kPlayers;   std::vector<GameRecordOperateResult> kAction;      voID StreamValue(datastream& kData,bool bSend)   {     StructVecotrMember(GameRecordplayer,kPlayers);     StructVecotrMember(GameRecordOperateResult,kAction);   }    voID CleanUp()   {     kPlayers.clear();     kAction.clear();   } }; 

          在datastream.h中,有一套set,get数据流的宏,能够将数据放入到数据流中或从中拿出。

#define Stream_VALUE(name) \   if(bSend)      \ {              \   kData.pushValue(name);\ }\ else\ {\   kData.popValue(name);\ }\ 

          好了,有了这样一个结构,在游戏开始的时候,我们就可以开始记录本局了。

//游戏开始 voID CtableFrameSink::GameStart() {     ...     //填充四个玩家的基础信息   for (int i = 0; i < 4; i++)   {     GameRecordplayer  tNewRecordplayer;              tagUserInfo *  tpUserInfo = m_pItableFrame->GettableUserItem(i)->GetUserInfo();     tNewRecordplayer.DWUserID = tpUserInfo->DWUserID;     tNewRecordplayer.kNickname = tpUserInfo->szNickname;              //取得手牌信息     BYTE cbCardData[MAX_COUNT];     m_GameLogic.SwitchAllToCardData(m_cbCardindex[i],cbCardData);      for (int j = 0; j < MAX_COUNT ; j++)     {       tNewRecordplayer.cbCardData.push_back(cbCardData[j]);     }         //存储到当前记录结构中的玩家信息容器。     m_sGameRecord.kPlayers.push_back(tNewRecordplayer);   } } 

        然后我们开始记录 *** 作,分别在玩家出牌,以及玩家应答吃,碰,杠,胡等 *** 作时加入记录。

//用户出牌 bool CtableFrameSink::OnUserOutCard(WORD wChairID,BYTE cbCardData) {      ...   //记录动作数据   GameRecordOperateResult  tNewRecordOperateResult;   tNewRecordOperateResult.cbActionType =    GameRecordOperateResult::TYPE_OutCard;   tNewRecordOperateResult.cbOperateCard = cbCardData;   tNewRecordOperateResult.cbOperateCode = WIK_NulL;   tNewRecordOperateResult.wOperateUser = wChairID;   tNewRecordOperateResult.wProvIDeUser = wChairID;   m_sGameRecord.kAction.push_back(tNewRecordOperateResult);      ... } 

@H_403_3@

//用户 *** 作 bool CtableFrameSink::OnUserOperateCard(WORD wChairID,BYTE cbOperateCode,BYTE cbOperateCard) {      ... //记录动作数据     GameRecordOperateResult  tNewRecordOperateResult;       tNewRecordOperateResult.cbActionType = XZDDGameRecordOperateResult::TYPE_OperateResult;     tNewRecordOperateResult.cbOperateCard = cbOperateCard;     tNewRecordOperateResult.cbOperateCode = cbOperateCode;     tNewRecordOperateResult.wOperateUser = wChairID;     tNewRecordOperateResult.wProvIDeUser = m_wProvIDeUser;     m_sGameRecord.kAction.push_back(tNewRecordOperateResult);      ... } 

          就这样,基本的 *** 作记录也完成了。最后当牌局结束时,我们需要将记录提交到数据库中。@H_403_3@

//游戏结束 bool CtableFrameSink::OnEventGameConclude(WORD wChairID,IServerUserItem * pIServerUserItem,BYTE cbReason) {   switch (cbReason)   {   case GER_norMAL:    //常规结束     {          ...             //将记录转化为数据流。       datastream kDataStream;       m_sGameRecord.StreamValue(kDataStream,true);              //除去写分等处理,这里最后一个参数即是数据流。             m_pItableFrame->Writetablescore(scoreInfoArray,CountArray(scoreInfoArray),kDataStream);           ...         }     } }  

           在私人场服务器中,会通过Writetablescore这个函数调用PrivatetableInfo的writeSocre,它将将数的流记录下来。

          并最终在牌局结束时dismissRoom(ptableInfo);发给了数据库。

             数据库最终会通过一个存储过程的执行完成将数据流入库的工作。具体的代码就不再展示了,大家可以参考@H_403_3@

cdataBaseEnginesink::OnRequestPrivateGameRecord()。            @H_403_3@

           这样一套完整的回放数据流程就结束了。      @H_403_3@

           好,今天的分析就到这里,红孩儿欢迎大家下次继续听课哦~

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

总结

以上是内存溢出为你收集整理的房卡麻将分析系列 "牌局回放" 之 数据设计详解及实例全部内容,希望文章能够帮你解决房卡麻将分析系列 "牌局回放" 之 数据设计详解及实例所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1146705.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存