十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
详解房卡麻将分析系列 "牌局回放" 之 播放处理
因为努力和真诚,有更多的客户和我们聚集在一起,为了共同目标,成都创新互联在工作上密切配合,从创业型企业到如今不断成长,要感谢客户对我们的高要求,让我们敢于面对挑战,才有今天的进步与发展。从网站到重庆小程序开发公司,软件开发,app软件开发,10年企业网站建设服务经验,为企业提供网站设计,网站托管、服务器租用一条龙服务.为企业提供成都全网营销推广,按需定制开发,原创设计,10年品质,值得您的信赖.
昨天红孩儿给大伙讲了讲”牌局回放“的数据记录处理,有了数据的存储,下面就是数据的显示了。
实话讲,好久没用过 SQL Server 来做数据库了, 网狐的服务器是基于WIN,IOCP, SQL Server 这套路子。配置好后,可以在QPTreasureDB数据库中看到三个牌局相关的表。
其中dbo.PrivateGameRecord是存储当前游戏的房间及玩家,最终胜负信息的。
dbo.PrivateGameRecordChild是存储当前游戏的每一局的牌局回放,也就是咱们上篇文中所讲述的每一场牌局详情和操作数据。
dbo.PrivateGameRecordUserRecordID是记录ID与玩家ID的对应关系。
我们打开dbo.PrivateGameRecord,可以看到有一个属性字段UserData存储着一堆二进制数据。也就是我们上节中通过Stream_VALUE来将结构数据填充为字节流后存进来的。
当客户端在进入战绩界面时,会向登录服务器发送SUB_GP_GAME_RECORD_LIST消息,请求当前玩家的所有参与过的房间据,也就是dbo.PrivateGameRecord中与玩家相关的数据列表。这个可以在CGPGameRecord.cpp的CB_GetGameRecordList函数中看到。
在登录服务器的AttemperEngineSink.cpp中,我们可以看到登录服务器会在收到消息后转发数据库请求,数据库再通过存储过程拉数据出来。之后返回给客户端。
客户端收到后通过StreamValue将数据流解析到结构tagPrivateRandTotalRecord中显示出来。
当玩家看到这条信息后,如果想查看每一局的战局,会再点击"详情"按钮,这时客户端会向登录服务器再次发送SUB_GP_GAME_RECORD_CHILD消息,同上面的流程大体一致,经过这样一个来回,客户端会得到房间中每局的详细数据,收到后通过StreamValue将数据流解析到结构tagPrivateRandRecordChild中显示出来。
玩家现在能看到每一局的详情了,他如果想看牌局回放,会再调用GameScene的StartRecord(datastream kDataStream)来将tagPrivateRandRecordChild中的数据流转化为当前玩家牌局信息和操作信息。之后显示游戏场景和回放操作按钮菜单。有了具体的数据,通过按钮菜单来控制播放的速度,上一步,下一步并不复杂。在GameScene的NextRecordAction函数中,我们可以看到如何根据当前的操作类型来进行相应的操作复现玩家的出牌和操作。
void GameScence::NextRecordAction() { ... GameRecordOperateResult& kAction = m_pGameRecord->kAction[m_iActRecordIdex]; int iChairID = (m_wRecordSelfChairID-kAction.wOperateUser+MAX_PLAYER)%MAX_PLAYER; int iProvideUser = (m_wRecordSelfChairID-kAction.wProvideUser+MAX_PLAYER)%MAX_PLAYER; if (kAction.cbActionType == GameRecordOperateResult::TYPE_OperateResult) { Player* pPlayer = m_pPlayer[iChairID]; CMD_S_OperateResult kTempCMD; kTempCMD.cbOperateCard = kAction.cbOperateCard; kTempCMD.cbOperateCode = kAction.cbOperateCode; kTempCMD.wOperateUser = kAction.wOperateUser; kTempCMD.wProvideUser = kAction.wProvideUser; Player* pProvidePlayer = m_pPlayer[iProvideUser]; if (pProvidePlayer &&(kAction.cbOperateCode == WIK_PENG || kAction.cbOperateCode == WIK_LEFT || kAction.cbOperateCode == WIK_CENTER || kAction.cbOperateCode == WIK_RIGHT || (kAction.cbOperateCode == WIK_GANG && kAction.wOperateUser != kAction.wProvideUser ))) { pProvidePlayer->removeHandOutCard(kAction.cbOperateCard); pProvidePlayer->setActOutCard(-1); //设置当前玩家 for (int i = 0; istopAniCurrPlayer(); } pProvidePlayer->runAniCurrPlayer(); } pPlayer->setOperateResoult(&kTempCMD); pPlayer->showCard(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_SendCard) { XPlayer* pPlayer = m_pPlayer[iChairID]; if (kAction.cbOperateCard != 0) { pPlayer->addNewInCard(kAction.cbOperateCard); } pPlayer->showCard(); //设置当前玩家 for (int i = 0; i stopAniCurrPlayer(); } pPlayer->runAniCurrPlayer(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_OutCard) { Player* pPlayer = m_pPlayer[iChairID]; for (int i = 0;i setActOutCard(-1); } pPlayer->sendOutCard(kAction.cbOperateCard); pPlayer->showCard(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_ChiHu) { Player* pPlayer = m_pPlayer[iChairID]; for (int i = 0;i setActOutCard(-1); } pPlayer->setChiHuCard(kAction.cbOperateCard); pPlayer->showEffect("Hu"); if (kAction.wOperateUser != kAction.wProvideUser) { XZDDPlayer* pDestPlayer = m_pPlayer[iChairID]; pPlayer->showHandCard(); pPlayer->showStatusImagic("Hu"); pDestPlayer->runAniHu(); } else { pPlayer->showStatusImagic("ZiMo"); pPlayer->runAniZiMo(); } pPlayer->showCard(); } m_iActRecordIdex++; ... }
于是,一场精彩的牌局就被完完整整的回放了。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!