SDL2 游戏开发日记(九) 单机麻将
单机麻将的基本功能其实年前已经完成了,只是写文档麻烦,再加上懒癌和重度拖延症,就一直拖着没更新。今天周末一个人没什么事干,抽空把它更新了。
麻将的表示
用数组表示,int card[136];值分别是 0-135;
值/4
0-8:表示万,9-17:表示饼,18-26:表示条,27-33:表示东南西北中发白
class MahjongCard : public Renderable{
private :
int mCardNumber; //牌值,0-135
bool 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;
//ai
MahjongAI *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个小时的时间,写文档果然是不擅长啊。