SDL2 遊戲開發日記(九) 單機麻將

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個小時的時間,寫文檔果然是不擅長啊。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章