详解房卡麻将分析系列 "牌局回放" 之 播放处理

所属分类: 软件编程 / Android 阅读数: 19
收藏 0 赞 0 分享

详解房卡麻将分析系列 "牌局回放" 之 播放处理

   昨天红孩儿给大伙讲了讲”牌局回放“的数据记录处理,有了数据的存储,下面就是数据的显示了。

          实话讲,好久没用过 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; i<MAX_PLAYER; i++) 
      { 
        m_pPlayer[i]->stopAniCurrPlayer(); 
      } 
      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<MAX_PLAYER; i++) 
    { 
      m_pPlayer[i]->stopAniCurrPlayer(); 
    } 
    pPlayer->runAniCurrPlayer(); 
  } 
  if (kAction.cbActionType == GameRecordOperateResult::TYPE_OutCard) 
  { 
    Player* pPlayer = m_pPlayer[iChairID]; 
    for (int i = 0;i<MAX_PLAYER;i++) 
    { 
      m_pPlayer[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<MAX_PLAYER;i++) 
    { 
      m_pPlayer[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++; 
  ... 
} 


于是,一场精彩的牌局就被完完整整的回放了。

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

更多精彩内容其他人还在看

Android实现悬浮窗体效果

这篇文章主要为大家详细介绍了Android实现悬浮窗体效果,显示悬浮窗口,窗口可以拖动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Andriod studio 打包aar 的方法

这篇文章主要介绍了Andriod studio 打包aar的方法,非常不错,具有一定的参考借鉴价值 ,需要的朋友可以参考下
收藏 0 赞 0 分享

Android加载loading对话框的功能及实例代码(不退出沉浸式效果)

这篇文章主要介绍了Android加载loading对话框的功能及实例代码,不退出沉浸式效果,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中LayoutInflater.inflater()的正确打开方式

这篇文章主要给大家介绍了关于Android中LayoutInflater.inflater()的正确打开方式,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Delphi在Android下使用Java库的方法

这篇文章主要介绍了Delphi在Android下使用Java库的方法,本文以Android的USB串口通讯库为例,给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Retrofit2日志拦截器的使用

这篇文章主要介绍了Retrofit2日志拦截器的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Android创建外部lib库及自定义View的图文教程

这篇文章主要给大家介绍了关于Android创建外部lib库及自定义View的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Android分享微信小程序失败的一些事小结

这篇文章主要给大家介绍了关于Android分享微信小程序失败一些事,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Android分享微信小程序技巧之图片优化

这篇文章主要给大家介绍了关于Android分享微信小程序技巧之图片优化的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Android Viewpager实现无限循环轮播图

这篇文章主要为大家详细介绍了Android Viewpager实现无限循环轮播图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多