SDL2 游戏开发日记(九) 单机麻将

单机麻将的基本功能其实年前已经完成了,只是写文档麻烦,再加上懒癌和重度拖延症,就一直拖着没更新。今天周末一个人没什么事干,抽空把它更新了。

麻将的表示

用数组表示,int card[136];值分别是 0-135;

值/4

0-8:表示万,9-17:表示饼,18-26:表示条,27-33:表示东南西北中发白

class MahjongCard : public Renderable{
private :int mCardNumber; //牌值,0-135bool mIsSelected;    //是否被选中的状态,玩家鼠标选择出牌时用Vector2I mOffset;   //选中后的位置偏移量,鼠标选择出牌时用
public :void SetCardNumber(int cardNumber){mCardNumber = cardNumber;}int GetCardNumber(){return mCardNumber;}bool IsSelected(){return mIsSelected;}void SetSelected(bool bSelected){mIsSelected = bSelected;}void SetOffset(int xOffset, int yOffset){mOffset.x = xOffset;mOffset.y = yOffset;}Vector2I &GetOffset(){return mOffset;}};

麻将算法

分为胡牌算法和出牌ai

胡牌算法:声明一个辅助数组 int cardAssists[38],用0填充。如果是判断自摸,则遍历手上的牌并根据index的值填充辅助数组。如果是判断吃胡,则遍历手上的牌和最后一张打出的牌。并根据index的值填充辅助数字。

index = 具体的牌值/4:如果值小于等于8,cardAssists[index+1] ++;即cardAssists数组的1-9表示万,

如果index的值大于等于9并且小于等于17,cardAssists[index+2] ++;即11-19表示饼

如果index的值大于等于18并且小于等于26,cardAssists[index+3]++;即21-29表示条。

如果index的值大于等于27,cardAssists[index+4] ++;即31-37表示字牌。

class MahjongAI{//递归调用bool IsHu(){int sum = 0;for (int i = 0; i < 38; i++){sum += mCardAssistArray[i];}     if (sum == 0){//匹配完了,如果有找到将牌,表示可以胡牌了。if (mIsFindJiang)return true;else return false;}int index = 0;//跳过没有的牌for (index = 0; index < 38 && mCardAssistArray[index] == 0; index++);//如果是一刻,把这一刻去掉if (mCardAssistArray[index] >= 3){mCardAssistArray[index] -= 3;//再判断剩下的牌是否胡牌。if (IsHu()){return true;}           //没有胡牌,把这一刻加回去mCardAssistArray[index] += 3;}//如果是一对,并且还未找到将牌,if (mCardAssistArray[index] >= 2 && !mIsFindJiang){mIsFindJiang = true;mCardAssistArray[index] -= 2;//去掉,并判断剩下的牌能不能胡if (IsHu()){return true;}mIsFindJiang = false;//不能胡,加回去mCardAssistArray[index] += 2;}//索引大于30的不判断顺子if (index > 30)return false;//判断如果能组成顺子,把顺子牌拿掉,if (mCardAssistArray[index + 1] >= 1 && mCardAssistArray[index + 2] >= 1){mCardAssistArray[index] --;mCardAssistArray[index + 1] --;mCardAssistArray[index + 2] --;//判断剩下的牌能不能胡牌if (IsHu()){return true;}//不能胡牌,加回数组中mCardAssistArray[index] ++;mCardAssistArray[index + 1] ++;mCardAssistArray[index + 2] ++;}return false;}}

出牌ai:判断有没有单独的字牌和单独的牌->拆掉那些不是对子并且不是顺子的牌->判断最佳的听牌组合->经过上面的方法还选不出来该出的牌?那就随机出牌。

MahjongCard *MahjongAI::GetBestOutCard(){MahjongCard *card = NULL;QueryInCards();vector<MahjongCard*> randomCardList,allCardList;CardMap &inHandcard = mPlayer->GetInHandCard();printf("inhandcard size:%d\n",inHandcard.size());CardMap::reverse_iterator iter = inHandcard.rbegin();while (iter != inHandcard.rend()){int cardIndex = GetCardIndex(iter->second);if (cardIndex > 30){if (mCardAssistArray[cardIndex] == 1){//printf("单独的字牌:%d\n", cardIndex);randomCardList.push_back(iter->second);}}else{if (mCardAssistArray[cardIndex] == 1){if (mCardAssistArray[cardIndex - 1] == 0 && mCardAssistArray[cardIndex+1] == 0){//printf("单独的牌:%d\n", cardIndex);randomCardList.push_back(iter->second);}}}allCardList.push_back(iter->second);iter++;printf("%d,",cardIndex);}printf("\n");if (randomCardList.size() == 0){      printf("不知道打什么牌1:进一步选择");while (iter != inHandcard.rend()){int cardIndex = GetCardIndex(iter->second);if (cardIndex > 30){break;}else{if (mCardAssistArray[cardIndex] == 1){if (mCardAssistArray[cardIndex - 1] >= 1 && mCardAssistArray[cardIndex + 1] >= 1){iter++;continue;}else if (mCardAssistArray[cardIndex + 1] >= 1 && mCardAssistArray[cardIndex + 2] >= 1){iter++;continue;}else{if (cardIndex % 10>2){if (mCardAssistArray[cardIndex - 2] >= 1 && mCardAssistArray[cardIndex - 1] >= 1){iter++;continue;}}}card = iter->second;printf(":%d\n", GetCardIndex(card));break;                 }}                      }}else{int index = rand() % randomCardList.size();card = randomCardList[index];}if (card == NULL){printf("进一步选择失败,判断ting\n");int assistArray[38];int bestIndex = -1, bestTingCount = -1;for (int i = 0; i < 38; i++){if (mCardAssistArray[i] == 0)continue;mCardAssistArray[i] --;memcpy(assistArray, mCardAssistArray, sizeof(assistArray));int tingCount = TingCount(assistArray);if (tingCount > 0){printf_s("Ting:%d,cardIndex:%d\n",tingCount,i);if (tingCount > bestTingCount){bestTingCount = tingCount;bestIndex = i;}}mCardAssistArray[i]++;}if (bestIndex == -1){int index = rand() % allCardList.size();card = allCardList[index];printf_s("最后还是随机出:%d\n", GetCardIndex(card));}else{iter = inHandcard.rbegin();while (iter != inHandcard.rend()){int cardIndex = GetCardIndex(iter->second);//printf("%d-----%d\n",cardIndex,bestIndex);if (bestIndex == cardIndex){printf_s("TING:%d\n",iter->second->GetCardNumber());card = iter->second;break;}iter++;}}}printf("%s-----out:%d\n",typeid(*mPlayer).name(), GetCardIndex(card));return card;
}

玩家

一个玩家,三个AI

#include "MahjongCard.h"
#include "MahjongAI.h"
#include <map>
#include <vector>
#include <deque>
#include <cassert>
using namespace std;typedef map<int, MahjongCard*> CardMap;
typedef vector<MahjongCard*> CardVector;
typedef deque<MahjongCard*>CardQueue;class Player : public Renderable{
protected://手上的牌CardMap mInHandCard;//打出去的牌CardVector mOutCard;//碰或者杠的牌CardVector mSpecialCard;//未知的牌CardQueue mUnknownCardList;//牌的位置Vector2I mInHandCardPos, mOutCardPos, mSpecialCardPos, mUnknownCardPos;//aiMahjongAI *mAI;MahjongCard *mNewCard;bool mIsChange;//下家Player *mNextPlayer;bool mIsGameEnd;
public:Player(){mAI = new MahjongAI(this);mNextPlayer = NULL;}virtual ~Player(){if (mTexture != NULL){SDL_DestroyTexture(mTexture);mTexture = NULL;}SAFE_DELETE(mAI);}MahjongAI *GetAI(){return mAI;}//设置牌的位置void SetInHandCardPos(int x, int y){mInHandCardPos.x = x;mInHandCardPos.y = y;}void SetOutCardPos(int x, int y){mOutCardPos.x = x;mOutCardPos.y = y;}void SetSpecialCardPos(int x, int y){mSpecialCardPos.x = x;mSpecialCardPos.y = y;}void SetUnknownCardPos(int x, int y){mUnknownCardPos.x = x;mUnknownCardPos.y = y;}//创建纹理void CreateRenderTexture(int x,int y,int width, int height);virtual void Update(float time_step){}  virtual void HandleEvent(SDL_Event &ev){}//把牌放到未知的牌中void PutUnknowCard(MahjongCard*card){mUnknownCardList.push_back(card);mIsChange = true;}//获取一张未知的牌virtual MahjongCard* PopUnknownCard(){MahjongCard *card = NULL;if (!mUnknownCardList.empty()){card = mUnknownCardList.back();mUnknownCardList.pop_back();          mIsChange = true;}     return card;}//手上的牌的数量int GetInHandCardCount(){return mInHandCard.size();}//出牌void PopCardOut(MahjongCard *outCard){PopCardOut(outCard->GetCardNumber());}//出牌void PopCardOut(int cardNumber){CardMap::iterator it = mInHandCard.find(cardNumber);if (it != mInHandCard.end()){mOutCard.push_back(it->second);mInHandCard.erase(it);}mNewCard = NULL;mIsChange = true;}//把最后一张出的牌移走,被/碰/杠时用void RemoveOutCard(){mOutCard.pop_back();mIsChange = true;}//摸牌void PutCardIn(MahjongCard *card,bool IsStart = true){assert(card != NULL && "<Player::PutCcardIn>: CARD IS NULL.");mIsChange = true;mInHandCard.insert(make_pair(card->GetCardNumber(),card));if (IsStart){mNewCard = card;}}//碰,杠 把牌放到特殊列表里void PutToSpecialCard(MahjongCard*card,int count){CardMap::iterator it = mInHandCard.begin();mSpecialCard.push_back(card);while(it != mInHandCard.end()){MahjongCard *c = it->second;if (c->GetCardNumber() / 4 == card->GetCardNumber() / 4 && c != card){mSpecialCard.push_back(c);it = mInHandCard.erase(it);count--;if (count == 0)break;}else{it++;}}mIsChange = true;}//重新开始void Restart(){SetGameEnd(false);mInHandCard.clear();mOutCard.clear();mSpecialCard.clear();mUnknownCardList.clear();}CardMap &GetInHandCard(){return mInHandCard;}CardVector &GetSpecialCard(){return mSpecialCard;}virtual void Render();    virtual void RenderUnknowCard() = 0;virtual void RenderInHandCard() = 0;virtual void RenderOutCard() = 0;virtual void RenderSpecialCard() = 0;  virtual MahjongCard* HandleMouseEvent(int type, int x, int y){ return NULL; }Player *GetNextPlayer(){return mNextPlayer;}void SetNextPlayer(Player*nextPlayer){mNextPlayer = nextPlayer;}//设置游戏结束状态,游戏结束时,所有人的牌都能被看到void SetGameEnd(bool IsEnd){mIsGameEnd = IsEnd;mIsChange = true;}
};class MyPlayer : public Player{
private:public:virtual void Update(float time_step);virtual void HandleEvent(SDL_Event &ev);virtual void RenderUnknowCard();virtual void RenderInHandCard();virtual void RenderOutCard();virtual void RenderSpecialCard();  virtual MahjongCard* HandleMouseEvent(int type ,int x, int y);
};
class NextPlayer :public Player{
private :public:virtual void Update(float time_step);virtual void RenderUnknowCard();virtual void RenderInHandCard();virtual void RenderOutCard();virtual void RenderSpecialCard();
};
class OppositePlayer :public Player{
public:virtual void Update(float time_step);virtual void RenderUnknowCard();virtual void RenderInHandCard();virtual void RenderOutCard();virtual void RenderSpecialCard();
};
class PrevPlayer :public Player{
private :public:virtual void Update(float time_step);virtual void RenderUnknowCard();virtual void RenderInHandCard();virtual void RenderOutCard();virtual void RenderSpecialCard();
};#include "stdafx.h"
#include "Player.h"
#include "../SDLGame/SDLGame.h"void Player::CreateRenderTexture(int x,int y,int width, int height){mTexture = SDL_CreateTexture(theGame.getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);   if (mRenderRect == NULL)mRenderRect = new SDL_Rect();mTextureWidth = width;mTextureHeight = height;mRenderRect->w = width;mRenderRect->h = height;SetPos(x, y);mIsChange = true;
}
void Player::Render(){if (mIsChange){SDL_SetRenderTarget(theGame.getRenderer(), mTexture);SDL_SetRenderDrawColor(theGame.getRenderer(), 0x00, 0x00, 0x00, 0x00);SDL_RenderClear(theGame.getRenderer());//       RenderUnknowCard();RenderInHandCard();RenderOutCard();RenderSpecialCard();SDL_SetRenderTarget(theGame.getRenderer(), NULL);SDL_SetTextureBlendMode(mTexture, SDL_BLENDMODE_BLEND);mIsChange = false;}SDL_RenderCopyEx(theGame.getRenderer(), mTexture, mClipRect, mRenderRect, 0, NULL, SDL_FLIP_NONE);
}

麻将场景

包括一个背景,2个对话框(事件对话框,结束对话框),4个玩家,管理0-135共136个牌,处理游戏流程 洗牌->发牌->打牌->游戏结束。

#pragma once
#include "../SDLGame/Scene.h"
#include "../SDLGame/Common.h"
#include "../SDLGame/MessageListener.h"
#include "Player.h"
#include <cstdlib>
#include <ctime>
#include "EventDialog.h"
#include "GameEndDialog.h"
#include "../SDLGame/MessageDispatcher.h"using namespace std;
enum GameState{ START = 0, RIFFLECARD,SEND_CARD, RUNNING, END,WAIT_FOR_INPUT,WAIT_FOR_DIALOG,IDLE,WAIT_FOR_END_DIALOG };enum SCENE_MSG_TYPE{MSG_GIVE_UP = 0,MSG_PENG, MSG_GANG, MSG_HU, MSG_RESTART, MSG_GET_CARD,MSG_OUT_CARD
};//自定义消息的扩展消息
struct EVENT_EXTRA{Player *outPlayer;Player *handlePlayer;MahjongCard *outCard;
};class MahjongScene : public Scene,public MessageListener{
private://背景Renderable *mBackground;//事件对话框EventDialog *mEventDialog;//结束对话框GameEndDialog *mGameEndDialog;//玩家Player *mMyPlayer, *mNextPlayer, *mOppositePlayer, *mPrevPlayer;vector<Player*> mPlayers;Player *mCurrentPlayer;//发牌时用到的标记int mCurrentPopIndex;int mServerIndex;int mCurrentGetIndex;//牌的表示int mCard[136];float mDelayTime = 1.0f;float mTimeElapse = 0.0f;//牌池CardMap mCardPool;//当前游戏状态GameState mCurrentState;//最后一张出的牌MahjongCard *mLastCard;
public:MahjongScene(){//初始化麻将牌for (int i = 0; i < 136; i++){mCard[i] = i;MahjongCard *card = new MahjongCard();card->SetCardNumber(i);mCardPool.insert(make_pair(i, card));}mCurrentState = START;}void NextPopCardIndex(){mCurrentPopIndex--;if (mCurrentPopIndex < 0)mCurrentPopIndex = 3;}void NextGetCardIndex(){mCurrentGetIndex++;if (mCurrentGetIndex > 3)mCurrentGetIndex = 0;}bool IsSendCardComplete(){bool IsComplete = true;for (int i = 0; i < 4; i++){if (mPlayers[i]->GetInHandCardCount() != 13){IsComplete = false;break;}}return IsComplete;}void SetServerIndex(int index){mServerIndex = index;      }void RandServer(){srand((uint32_t)time(NULL));int index = rand() % 4;SetServerIndex(index);}void RandPopIndex(){srand((uint32_t)time(NULL));int index = rand() % 4;mCurrentPopIndex = index;}//处理摸牌消息void HandleCardInEvent(Player *player,MahjongCard *inCard){//调用ai判断摸牌事件int ev = player->GetAI()->CardInEvent(inCard);printf("%s---cardIN EV:%d\n", typeid(*player).name(),ev);if (ev & EVENT_HU){//胡牌,2秒后发送胡牌消息。()Dispatcher.DispatchMsg(2.0f, this, this, MSG_HU);}else if (ev & EVENT_GANG){//杠,把牌放到特殊牌中,2秒后再摸牌player->PutToSpecialCard(inCard,4);Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, player);}else{ //没事件,2秒后出牌          Dispatcher.DispatchMsg(2.0f, this, this, MSG_OUT_CARD, player);}}//其他玩家处理出牌消息void HandleCardOutEvent(MahjongCard *outCard, Player *player){int ev = 0;bool bHandelEvent = false;for (int i = 0; i < 4; i++){//出牌的人不用处理if (mPlayers[i] == player)continue;ev = mPlayers[i]->GetAI()->CardOutEvent(outCard, player);//如果玩家触发了事件,玩家弹出对话框,其他的就不用处理了。//其实按正常的逻辑,是先判断每个人的事件,然后对应的人去选择处理,选择完了后,按照胡牌优先的顺序处理事件。这里单机玩的,所以玩家优先。if (ev >= 0x01 && mPlayers[i] == mMyPlayer){mEventDialog->ShowEvent(ev);mEventDialog->SetTag(player);mCurrentState = WAIT_FOR_DIALOG;mLastCard = outCard;bHandelEvent = true;break;}if (ev & EVENT_HU){printf_s("%s----HU:%d\n", typeid(*mPlayers[i]).name(),i);EVENT_EXTRA *extra = new EVENT_EXTRA();extra->outPlayer = player;extra->handlePlayer = mPlayers[i];extra->outCard = outCard;Dispatcher.DispatchMsg(2.0f, this, this, MSG_HU, extra);bHandelEvent = true;break;}else if (ev & EVENT_GANG){bHandelEvent = true;EVENT_EXTRA *extra = new EVENT_EXTRA();extra->outPlayer = player;extra->handlePlayer = mPlayers[i];extra->outCard = outCard;Dispatcher.DispatchMsg(2.0f, this, this, MSG_GANG, extra);}else if (ev & EVENT_PENG){bHandelEvent = true;EVENT_EXTRA *extra = new EVENT_EXTRA();extra->outPlayer = player;extra->handlePlayer = mPlayers[i];extra->outCard = outCard;Dispatcher.DispatchMsg(2.0f, this, this, MSG_PENG, extra);}}if (!bHandelEvent){//没人触发事件,2秒后下一家摸牌Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, player->GetNextPlayer());}}//弹出一张未知牌MahjongCard *PopUnknownCard(){MahjongCard *card = NULL;int count = 0;while (card == NULL){card = mPlayers[mCurrentPopIndex]->PopUnknownCard();if (card == NULL){NextPopCardIndex();count++;//都没有牌可弹出if (count >= 4)break;}}return card;}//洗牌void RiffleCard(){srand((uint32_t)time(NULL));for (int i = 0; i < 300; i++){int m = rand() % 136;int n = rand() % 136;//随机交换两个牌的位置;int temp = mCard[m];mCard[m] = mCard[n];mCard[n] = temp;}//把交换后的牌分发到每一个玩家的未知牌里for (int i = 0; i < 136; i++){int index = i % 4;          CardMap::iterator it = mCardPool.find(mCard[i]);if (it != mCardPool.end()){MahjongCard *card = it->second;switch (index){case 0:mMyPlayer->PutUnknowCard(card);break;case 1:mNextPlayer->PutUnknowCard(card);break;case 2:mOppositePlayer->PutUnknowCard(card);break;case 3:mPrevPlayer->PutUnknowCard(card);break;}}}}virtual void LoadScene();~MahjongScene(){CardMap::iterator it = mCardPool.begin();while (it != mCardPool.end()){delete (it->second);it++;}mCardPool.clear();}//鼠标事件virtual void HandleEvent(SDL_Event &ev);virtual void Update(float);//自定义事件的处理virtual bool OnMessage(const GameMessage &msg);
};#include "stdafx.h"
#include "MahjongScene.h"
#include "../SDLGame/SDLGame.h"
#include "EventDialog.h"
#include "GameEndDialog.h"
#include "../SDLGame/GameMessage.h"
#include <cassert>void MahjongScene::LoadScene(){mBackground = new Renderable();if (mBackground->LoadTexture("background.png")){this->AddRenderable(mBackground);}int windowWidth = theGame.GetWindowWidth();int windowHeight = theGame.GetWindowHeight();//我mMyPlayer = new MyPlayer();mMyPlayer->CreateRenderTexture(300, windowHeight-320, windowWidth-300, 320);mMyPlayer->SetInHandCardPos(10, 200);mMyPlayer->SetUnknownCardPos(85, 20);mMyPlayer->SetOutCardPos(10, 100);mMyPlayer->SetSpecialCardPos(0,0);this->AddRenderable(mMyPlayer);//下家mNextPlayer = new NextPlayer();mNextPlayer->CreateRenderTexture(windowWidth - 350, 0, 350, windowHeight);mNextPlayer->SetInHandCardPos(300, windowHeight - 250);mNextPlayer->SetUnknownCardPos(0, windowHeight - 250);mNextPlayer->SetOutCardPos(100, windowHeight - 250);this->AddRenderable(mNextPlayer);//上家mPrevPlayer = new PrevPlayer();mPrevPlayer->CreateRenderTexture(0, 0, 350, windowHeight);mPrevPlayer->SetInHandCardPos(50, 210);mPrevPlayer->SetUnknownCardPos(314, 210);mPrevPlayer->SetOutCardPos(220,210);this->AddRenderable(mPrevPlayer);//对家mOppositePlayer = new OppositePlayer();mOppositePlayer->CreateRenderTexture(0, 0, windowWidth, 300);mOppositePlayer->SetInHandCardPos(windowWidth - 240, 30);mOppositePlayer->SetUnknownCardPos(windowWidth - 415, 260);mOppositePlayer->SetOutCardPos(windowWidth - 415, 180);this->AddRenderable(mOppositePlayer);mPlayers.push_back(mMyPlayer);mPlayers.push_back(mNextPlayer);mPlayers.push_back(mOppositePlayer);mPlayers.push_back(mPrevPlayer);mMyPlayer->SetNextPlayer(mNextPlayer);mNextPlayer->SetNextPlayer(mOppositePlayer);mOppositePlayer->SetNextPlayer(mPrevPlayer);mPrevPlayer->SetNextPlayer(mMyPlayer);mCurrentPopIndex = 0;mCurrentGetIndex = 0;//事件对话框EventDialog *diag = new EventDialog();diag->CreateRenderTexture(windowWidth - 368, windowHeight - 300, 368, 206);diag->LoadButtons();diag->SetVisible(false);this->AddRenderable(diag);diag->RegisterListener(this);mEventDialog = diag;//游戏结束对话框GameEndDialog *endDialog = new GameEndDialog();endDialog->CreateRenderTexture((windowWidth - 611)/2, (windowHeight - 600)/2, 611, 600);endDialog->LoadButtons();endDialog->SetVisible(false);this->AddRenderable(endDialog);endDialog->RegisterListener(this);mGameEndDialog = endDialog;}
//处理鼠标事件
void MahjongScene::HandleEvent(SDL_Event &ev){int x = 0, y = 0;   switch (ev.type){case SDL_MOUSEBUTTONDOWN:if (ev.button.button == SDL_BUTTON_LEFT){x = ev.button.x;y = ev.button.y;if (mCurrentState == WAIT_FOR_INPUT){MahjongCard* card = mMyPlayer->HandleMouseEvent(ev.type, x, y);if (card != NULL){mMyPlayer->PopCardOut(card);                                     HandleCardOutEvent(card, mMyPlayer);mCurrentState = RUNNING;}}}break;case SDL_MOUSEMOTION:x = ev.motion.x;y = ev.motion.y;mMyPlayer->HandleMouseEvent(ev.type, x, y);break;}if (mCurrentState == WAIT_FOR_DIALOG){mEventDialog->HandleEvent(ev);}else if (mCurrentState == WAIT_FOR_END_DIALOG){mGameEndDialog->HandleEvent(ev);}
}
void MahjongScene::Update(float time_step){mTimeElapse += time_step;if (mTimeElapse > 1.0f){mTimeElapse -= 1.0f;MahjongCard *card = NULL;        //printf("state:%d\n",mCurrentState);switch (mCurrentState){case START:printf("start\n");mCurrentState = RIFFLECARD;break;case RIFFLECARD:printf("riffle card\n");RiffleCard();mCurrentState = SEND_CARD;break;case SEND_CARD:  //发牌for (int i = 0; i < 4; i++){card = PopUnknownCard();mPlayers[mCurrentGetIndex]->PutCardIn(card,false);printf("%d,",card->GetCardNumber());if (mPlayers[mCurrentGetIndex]->GetInHandCardCount() == 13)break;}printf("\n");NextGetCardIndex();if (IsSendCardComplete()){mCurrentState = RUNNING;//(GameState)((int)MY_TURN + mCurrentGetIndex);//mCurrentPlayer = mMyPlayer;Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, mMyPlayer);}break;case RUNNING:           break;      case END:printf("game end\n");{mGameEndDialog->SetVisible(true);mCurrentState = WAIT_FOR_END_DIALOG;}break;default:break;}for (int i = 0; i < 4; i++){mPlayers[i]->Update(time_step);}}
}
//自定义消息处理
bool MahjongScene::OnMessage(const GameMessage &msg){int ev = msg.message; if (ev == MSG_GIVE_UP){               Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, mCurrentPlayer->GetNextPlayer());mEventDialog->SetVisible(false);}else if (ev == MSG_PENG){EVENT_EXTRA *extra = (EVENT_EXTRA*)msg.ExtraInfo;if (extra != NULL){extra->outPlayer->RemoveOutCard();extra->handlePlayer->PutToSpecialCard(extra->outCard, 2);Dispatcher.DispatchMsg(2.0f, this, this, MSG_OUT_CARD, extra->handlePlayer);}else{Player *lastPlayer = (Player*)mEventDialog->GetTag();if (lastPlayer != NULL){lastPlayer->RemoveOutCard();}mMyPlayer->PutToSpecialCard(mLastCard, 2);mCurrentState = WAIT_FOR_INPUT;mEventDialog->SetVisible(false);mEventDialog->SetTag(NULL);}SAFE_DELETE(extra);}else if (ev == MSG_GANG){EVENT_EXTRA *extra = (EVENT_EXTRA*)msg.ExtraInfo;if (extra != NULL){extra->outPlayer->RemoveOutCard();extra->handlePlayer->PutToSpecialCard(extra->outCard, 3);Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, extra->handlePlayer);}else{Player *lastPlayer = (Player*)mEventDialog->GetTag();if (lastPlayer != NULL){lastPlayer->RemoveOutCard();}mMyPlayer->PutToSpecialCard(mLastCard, 4);Dispatcher.DispatchMsg(2.0f, this, this, MSG_GET_CARD, mMyPlayer);mEventDialog->SetVisible(false);mEventDialog->SetTag(NULL);          }SAFE_DELETE(extra);} else if (ev == MSG_HU){mCurrentState = END;mEventDialog->SetVisible(false);mEventDialog->SetTag(NULL);for (int i = 0; i < 4; i++){mPlayers[i]->SetGameEnd(true);}}else{Player* player;MahjongCard *card;switch (ev){case MSG_RESTART:for (int i = 0; i < 4; i++){mPlayers[i]->Restart();}mCurrentState = START;mGameEndDialog->SetVisible(false);break;case MSG_GET_CARD:card = PopUnknownCard();if (card == NULL){mCurrentState = END;break;}player = (Player*)msg.ExtraInfo;player->PutCardIn(card);mCurrentPlayer = player;if (player == mMyPlayer){mCurrentState = WAIT_FOR_INPUT;int e = mMyPlayer->GetAI()->CardInEvent(card);if (e > 0){mLastCard = card;mEventDialog->ShowEvent(e);mEventDialog->SetTag(NULL);mCurrentState = WAIT_FOR_DIALOG;}}else{HandleCardInEvent(player, card);}break;case MSG_OUT_CARD:player = (Player*)msg.ExtraInfo;card = player->GetAI()->GetBestOutCard();player->PopCardOut(card);HandleCardOutEvent(card, player);break;}}return true;
}

效果图

本来以为这文档会很快写完,谁知到修修改改加上注释,花了将近4个小时的时间,写文档果然是不擅长啊。

SDL2 游戏开发日记(九) 单机麻将相关推荐

  1. java游戏开发入门(九) -音效

    java游戏开发入门(九) - 图像 前言 音频资源 编码 首先完成BGM 紧接着完成音效部分 项目目录 完整代码 总结 完整项目 前言   对于一个游戏来说,音效也是必不可少的一环,自然也不能少了. ...

  2. unity3d模拟树叶飘动_Unity3D独立游戏开发日记(一):动态生成树木

    目前写的独立游戏是一个沙盒类型的游戏.游戏DEMO视频如下: 提到沙盒类型的游戏,就有人给出了这样的定义: 游戏世界离现实世界越近,自由度.随机度越高才叫沙盒游戏.所谓自由度,就是你在游戏里想干啥就干 ...

  3. Unity游戏开发日记(一):独自开发2d横板游戏:Small man(MainMenu主界面)基本构建

    目录 一.独自开发想法 前言: 开发构想: 二.主要内容:MainMenu主界面基本构建 (一)预想功能 (二)功能实现 1.主界面UI设计 2.Option功能设计 3.TypeOption功能设计 ...

  4. 世嘉MD游戏开发【九】:Sprite精灵

    终于讲到Sprite精灵了,我自己也很希望快点讲精灵,但是欲速则不达,自己要是还没研究透彻这个知识点就去讲下一个,感觉文章肯定是写不好的. 我用下图来做演示,SFC幽游白书-魔界最强列传里的雷禅: 怎 ...

  5. 项目游戏开发日记 No.0x000005

    14软二杨近星(2014551622) 还有一周就要交项目了, 看着周围的人也都忙碌了起来, 看着大部分人的项目都已经初具容貌, 我们团队里面也搞得人心惶惶, 一来是, 时间不多了, 还有很多事情要做 ...

  6. Unity3D独立游戏开发日记(二):摆放建筑物

    在沙盒游戏里,能自由建造是很重要的特点,比如说风靡全球的<我的世界>,用一个个方块就能搭建出规模宏大的世界.甚至有偏激的人说,没有自由建造,就不是一个真正的沙盒游戏.的确,沙盒游戏的魅力有 ...

  7. 小米VR一体机游戏开发日记(第一天)

    上周入手一个小米VR一体机,虽说画面颗粒感还是比较强,但那种身临其境的感觉还是非常酷的! 今天在网上看了一些VR的知识后突发奇想,跟儿子一起创作个小游戏试试,正好马上十一了,有七天时间可以利用:). ...

  8. 自学Unity游戏开发日记

    Unity游戏开发的启蒙老师是麦扣老师(在bilibili),讲的非常的棒,后悔没有早点发现麦扣老师. 第一个案例游戏(Sunny Land) 印象最深的问题:在按下空格进行跳跃时,跳不起来,或者说偶 ...

  9. D2D RPG游戏开发日记(一)--准备

    主要是作为自己做的2DRPG游戏日记 采用direct2D vs2015 c++ win32 还在开发中 预计写到3月底应该 简述: 本项目使用D2D API制作一款2DRPG游戏.暂定游戏设计有三个 ...

最新文章

  1. linux安装python3.6_Linux环境下安装python3.6
  2. 关于敏捷开发方法(Agile Software Development)的阅读笔记
  3. 【渝粤教育】电大中专电商运营实操 (18)作业 题库
  4. 安卓log.e函数打印示例_log1p()函数以及C ++中的示例
  5. cmake命令的python库的位置参数-DTORCH_PATH
  6. word中如何优雅的显示代码
  7. 辽宁省计算机考研排名,2014辽宁省大学研究生教育排行榜
  8. 动态IP和静态IP的区别如何使用动态IP
  9. 读笔:《重来也不会好过现在》
  10. 《计算机科学概论》目录—导读
  11. 小朋友适合读增广贤文么,增广贤文适合多大的孩子看?
  12. 手机远程启动汽车,汽车远程启动还是手机控制好!有一种远程手机启动热车系统非常的不错是什么功能知道吗?
  13. jQuery UI框架
  14. 云计算机ppt模板,云计算的PPT模板
  15. C语言面试题--已知整形变量在内存中占4个字节的空间,现有一无符号整形变量a = 0x20190125,请编写函数求出变量a所占内存每个字节的值是多少?
  16. java静态方法详解
  17. 2018年上半年系统分析师上午试题答案
  18. 解决帝国CMS搜索页面模板不支持灵动标签和万能标签的方法
  19. 基于蜉蝣优化算法的函数寻优算法
  20. A.一个部族,一个民族,一个弗雷尔卓德(素数筛+线段树)

热门文章

  1. 图片隐写 安恒ctf_CTF中图片隐写的一些整理总结
  2. Cocos Creator性能优化-2-包体优化
  3. python中wraps是什么意思_【Python】Flask中@wraps的使用
  4. DIY——chrome谷歌浏览器皮肤的manifest.json风格文件和打包
  5. Java PropertyDescriptor对象
  6. 开启宝蓝德中间件的 开发者模式和热部署模式
  7. Pyp 替代sed,awk的文本处理工具
  8. Oracle例外表学习笔记
  9. c语言指针p2等于p1,C语言指针 -- 面试题
  10. 如何优雅地让多个node版本共存--nvm