最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

房卡麻將分析系列 "牌局回放" 之 數(shù)據(jù)設(shè)計(jì)詳解及實(shí)例

 更新時(shí)間:2017年03月08日 09:06:55   投稿:lqh  
這篇文章主要介紹了房卡麻將分析系列 "牌局回放" 之 數(shù)據(jù)設(shè)計(jì)詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下

房卡麻將分析系列 "牌局回放" 之 數(shù)據(jù)設(shè)計(jì)                                                                   

             最近幾個(gè)月,”房卡“棋牌游戲成為了資本追逐的熱點(diǎn),基于微信的廣大用戶和社交屬性,”房卡”棋牌發(fā)展迅速。紅孩兒團(tuán)隊(duì)因?yàn)橹皫啄暧羞^(guò)相關(guān)項(xiàng)目的經(jīng)驗(yàn)積累,鑒于未來(lái)廣闊的地方棋牌市場(chǎng)和”開(kāi)發(fā)間“機(jī)制的發(fā)展前景,也開(kāi)始轉(zhuǎn)向基于”開(kāi)房間“棋牌游戲的項(xiàng)目開(kāi)發(fā)中。為了更好的與開(kāi)發(fā)者進(jìn)行交流學(xué)習(xí),特開(kāi)設(shè)”房卡麻將游戲分析系列“。

                                                                            紅孩兒團(tuán)隊(duì)研發(fā)的"大贏家"紅中麻將

           本套麻將分析基于網(wǎng)絡(luò)上流傳的“網(wǎng)狐”房卡麻將源碼做為基礎(chǔ),按照功能模塊分為"架設(shè)指南",”服務(wù)器框架","后臺(tái)系統(tǒng)","胡牌算法","客戶端界面",“防作弊功能”等等細(xì)節(jié)做一些分析和指導(dǎo),幫助廣大的棋牌游戲開(kāi)發(fā)者迅速掌握“房卡”麻將的研發(fā)原理和技巧設(shè)計(jì)。也希望有興趣的朋友多多關(guān)注。

       第一次開(kāi)公眾號(hào),挑個(gè)簡(jiǎn)單的下手,先來(lái)講一講房卡麻將中一個(gè)重要功能:“牌局回放”,我們都知道,棋牌類游戲注重公平真實(shí)不作弊,如果玩家感覺(jué)到游戲的過(guò)程有作弊,我相信他一定會(huì)對(duì)這款游戲失去興趣。但作弊與否,玩家并不容易進(jìn)行判斷。這時(shí)候提供一個(gè)“牌局回放”功能給玩家進(jìn)行分析就尤為重要。

       “網(wǎng)狐”等一些長(zhǎng)期耕耘在棋牌領(lǐng)域的企業(yè),在這方面都有完整的經(jīng)驗(yàn)和框架,通過(guò)參考,我發(fā)現(xiàn)它是通過(guò)下面一套流程來(lái)完成”牌局回放“功能的。

        首先,在游戲服務(wù)器的房間類CTableFrameSink里需要有一個(gè)GameRecord結(jié)構(gòu),這個(gè)結(jié)構(gòu)對(duì) 玩家信息,手牌以及每一步的動(dòng)作都可以進(jìn)行相應(yīng)的記錄:

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;            //供應(yīng)用戶 
  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數(shù)據(jù)流的宏,能夠?qū)?shù)據(jù)放入到數(shù)據(jù)流中或從中拿出。

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

          好了,有了這樣一個(gè)結(jié)構(gòu),在游戲開(kāi)始的時(shí)候,我們就可以開(kāi)始記錄本局了。

//游戲開(kāi)始 
void CTableFrameSink::GameStart() 
{ 
    ... 
    //填充四個(gè)玩家的基礎(chǔ)信息 
  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]); 
    } 
        //存儲(chǔ)到當(dāng)前記錄結(jié)構(gòu)中的玩家信息容器。 
    m_sGameRecord.kPlayers.push_back(tNewRecordPlayer); 
  } 
} 

        然后我們開(kāi)始記錄操作,分別在玩家出牌,以及玩家應(yīng)答吃,碰,杠,胡等操作時(shí)加入記錄。

//用戶出牌 
bool CTableFrameSink::OnUserOutCard(WORD wChairID, BYTE cbCardData) 
{ 
     ... 
  //記錄動(dòng)作數(shù)據(jù) 
  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); 
     ... 
} 


//用戶操作 
bool CTableFrameSink::OnUserOperateCard(WORD wChairID, BYTE cbOperateCode, BYTE cbOperateCard) 
{ 
     ... 
//記錄動(dòng)作數(shù)據(jù) 
    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); 
     ... 
} 

          就這樣,基本的操作記錄也完成了。最后當(dāng)牌局結(jié)束時(shí),我們需要將記錄提交到數(shù)據(jù)庫(kù)中。

//游戲結(jié)束 
bool CTableFrameSink::OnEventGameConclude(WORD wChairID, IServerUserItem * pIServerUserItem, BYTE cbReason) 
{ 
  switch (cbReason) 
  { 
  case GER_NORMAL:    //常規(guī)結(jié)束 
    { 
         ... 
            //將記錄轉(zhuǎn)化為數(shù)據(jù)流。 
      datastream kDataStream; 
      m_sGameRecord.StreamValue(kDataStream, true);  
            //除去寫分等處理,這里最后一個(gè)參數(shù)即是數(shù)據(jù)流。 
            m_pITableFrame->WriteTableScore(ScoreInfoArray, CountArray(ScoreInfoArray), kDataStream); 
 
         ... 
        } 
    } 
}  

           在私人場(chǎng)服務(wù)器中,會(huì)通過(guò)WriteTableScore這個(gè)函數(shù)調(diào)用PrivateTableInfo的writeSocre,它將將數(shù)的流記錄下來(lái)。

          并最終在牌局結(jié)束時(shí)DismissRoom(pTableInfo);發(fā)給了數(shù)據(jù)庫(kù)。

             數(shù)據(jù)庫(kù)最終會(huì)通過(guò)一個(gè)存儲(chǔ)過(guò)程的執(zhí)行完成將數(shù)據(jù)流入庫(kù)的工作。具體的代碼就不再展示了,大家可以參考

CDataBaseEngineSink::OnRequestPrivateGameRecord()。            

           這樣一套完整的回放數(shù)據(jù)流程就結(jié)束了。      

           好,今天的分析就到這里,紅孩兒歡迎大家下次繼續(xù)聽(tīng)課哦~

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Kotlin?RecyclerView滾動(dòng)控件詳解

    Kotlin?RecyclerView滾動(dòng)控件詳解

    RecyclerView是Android一個(gè)更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實(shí)現(xiàn)數(shù)據(jù)縱向滾動(dòng),也可以實(shí)現(xiàn)橫向滾動(dòng)(ListView做不到橫向滾動(dòng))。接下來(lái)講解RecyclerView的用法
    2022-12-12
  • Android實(shí)現(xiàn)圖片選擇上傳功能實(shí)例

    Android實(shí)現(xiàn)圖片選擇上傳功能實(shí)例

    這篇文章主要介紹了Android實(shí)現(xiàn)圖片選擇以及圖片上傳的功能,有需要的朋友跟著學(xué)習(xí)下吧。
    2017-12-12
  • Android使用ViewPager實(shí)現(xiàn)啟動(dòng)引導(dǎo)頁(yè)

    Android使用ViewPager實(shí)現(xiàn)啟動(dòng)引導(dǎo)頁(yè)

    這篇文章主要為大家詳細(xì)介紹了Android使用ViewPager實(shí)現(xiàn)第一次啟動(dòng)引導(dǎo)頁(yè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Android提高Service優(yōu)先級(jí)的方法分析

    Android提高Service優(yōu)先級(jí)的方法分析

    這篇文章主要介紹了Android提高Service優(yōu)先級(jí)的方法,簡(jiǎn)單講述了Service優(yōu)先級(jí)的功能,并對(duì)比分析了1.5與1.0設(shè)置Service的技巧,需要的朋友可以參考下
    2016-06-06
  • 基于RxJava實(shí)現(xiàn)酷炫啟動(dòng)頁(yè)

    基于RxJava實(shí)現(xiàn)酷炫啟動(dòng)頁(yè)

    本文介紹怎樣利用RxJava來(lái)實(shí)現(xiàn)Android的啟動(dòng)頁(yè),啟動(dòng)頁(yè)的效果非??幔行枰呐笥褌兛梢詤⒖?。
    2016-07-07
  • Android開(kāi)發(fā)中Dialog半透明背景消失

    Android開(kāi)發(fā)中Dialog半透明背景消失

    這篇文章主要介紹了Android開(kāi)發(fā)中Dialog半透明背景消失的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • Android中使用adb命令通過(guò)IP地址連接手機(jī)

    Android中使用adb命令通過(guò)IP地址連接手機(jī)

    這篇文章主要介紹了Android中使用adb命令通過(guò)IP地址連接手機(jī)的方法,本文給大家分享兩種解決方法 ,需要的朋友可以參考下
    2018-07-07
  • Android Parcelable接口使用方法詳解

    Android Parcelable接口使用方法詳解

    這篇文章主要介紹了 Android Parcelable接口使用方法詳解的相關(guān)資料,實(shí)現(xiàn)Parcelable就是為了進(jìn)行序列化,需要的朋友可以參考下
    2017-08-08
  • Android SeekBar在刷新使用中需要注意的問(wèn)題

    Android SeekBar在刷新使用中需要注意的問(wèn)題

    SeekBar在刷新使用中需要注意的問(wèn)題:在使用SeekBar的過(guò)程中需要注意刷新頻率,避免頻繁刷新造成的性能問(wèn)題;同時(shí),需要對(duì)SeekBar的監(jiān)聽(tīng)事件進(jìn)行適當(dāng)?shù)膬?yōu)化,減少回調(diào)次數(shù),提高響應(yīng)速度
    2023-05-05
  • Android集成微信登錄的步驟詳解

    Android集成微信登錄的步驟詳解

    這篇文章給大家整理Android集成微信登錄的詳細(xì)步驟,通過(guò)文章整理的內(nèi)容,大家只需要幾行代碼就可以實(shí)現(xiàn)微信登錄的功能了,剛興趣的朋友們下面來(lái)一起看看吧。
    2016-09-09

最新評(píng)論

乌兰县| 五台县| 万盛区| 吴江市| 吴忠市| 安宁市| 许昌县| 民权县| 宜州市| 卓尼县| 鄂尔多斯市| 江阴市| 涟源市| 平邑县| 光泽县| 许昌县| 青冈县| 肥东县| 新平| 中山市| 万年县| 聊城市| 印江| 宜州市| 康保县| 平南县| 兰考县| 滁州市| 云南省| 石城县| 克什克腾旗| 布尔津县| 林芝县| 邹平县| 潞城市| 隆安县| 镇江市| 沅江市| 雷山县| 定南县| 奉新县|