ゲームの下地は出来ましたので、ルール部分を作っていきます。
神経衰弱は2枚めくって、同じ数字であれば次もチャレンジ出来るルールです。
違う数字であれば、2枚とも伏せる必要があります。
次はそこを作ってみましょう。
「Memory.h」を開き、変数を追加します。
//前方参照 class Card; class Memory { public: Memory(); ~Memory(); void Initialize(); void Shuffle(); void FaceUp(const POINT &refPoint); void DrawCard(Engine *pEngine); private: const int ADJUST_X; //中央に転送するための調整用X座標 const int ADJUST_Y; //中央に転送するための調整用Y座標 const int SHUFFLE; //シャッフル回数 const int RIGHT_LIMIT; //領域判定用の右端 const int BOTTOM_LIMIT; //領域判定用の下端 //カードクラス配列用ポインタ Card *m_pCard; int m_gameStatus; //ゲームステータス int m_savePos[2]; //座標保存用 }; |
ゲームステータスは、ゲームの進行を管理する変数です。
座標保存用の配列は、選択した2箇所の「添え字」を保管しておく場所として用意しました。
「Memory.cpp」の「Initialize関数」でステータスの初期化をしましょう。
void Memory::Initialize()
{
m_pCard = new Card[Card::SUIT * Card::NUMBER];
for (int i = 0; i < Card::SUIT; i++) {
for (int j = 0; j < Card::NUMBER; j++) {
m_pCard[i * Card::NUMBER + j].Set(j + 1, i, false);
}
}
m_gameStatus = 0;
}
|
ここからは少しずつ書きます。
「Memory.cpp」の「FaceUp関数」に次のコードを追加します。
void Memory::FaceUp(const POINT &refPoint)
{
if (refPoint.x >= ADJUST_X && refPoint.x < RIGHT_LIMIT && refPoint.y >= ADJUST_Y && refPoint.y < BOTTOM_LIMIT) {
POINT idx;
idx.x = (refPoint.x - ADJUST_X) / Card::SMALL_CARD_WIDTH;
idx.y = (refPoint.y - ADJUST_Y) / Card::SMALL_CARD_HEIGHT;
int index = idx.y * Card::NUMBER + idx.x;
if (!m_pCard[index].IsFaceUp()) {
m_pCard[index].FaceUp();
m_savePos[m_gameStatus] = index;
m_gameStatus++;
}
}
}
|
クリックする度に座標を配列に保存していきます。
しかし、保存するのは2つの座標だけでよく、2つのカードを選択した後は判定にはいらなければならないので、もう少しプログラムを追加します。
void Memory::FaceUp(const POINT &refPoint) { if (m_gameStatus < 2) { if (refPoint.x >= ADJUST_X && refPoint.x < RIGHT_LIMIT && refPoint.y >= ADJUST_Y && refPoint.y < BOTTOM_LIMIT) { POINT idx; idx.x = (refPoint.x - ADJUST_X) / Card::SMALL_CARD_WIDTH; idx.y = (refPoint.y - ADJUST_Y) / Card::SMALL_CARD_HEIGHT; int index = idx.y * Card::NUMBER + idx.x; if (!m_pCard[index].IsFaceUp()) { m_pCard[index].FaceUp(); m_savePos[m_gameStatus] = index; m_gameStatus++; } } } else { m_gameStatus = 0; } } |
「m_gameStatus」が「0」の時は「m_savePos」の「0番目」に添え字を格納します。
「m_gameStatus」が「1」の時は「m_savePos」の「1番目」に添え字を格納します。
「m_gameStatus」が「2」になったら「m_gameStatus」を「0」に戻します。。
「m_gameStatus」が「2」になった時に、それまで保存しておいた2つのカードを比較し、同じかどうか調べます。
そのためには、カードを比較する仕組みが必要です。
2枚のカードが同じかどうか比較するため、「==演算子」をオーバーロードしましょう。
「Card.h」を開き、プロトタイプを書き加えます。
class Card { public: static const int SUIT; static const int NUMBER; static const int SMALL_CARD_WIDTH; //小さいカードの幅 static const int SMALL_CARD_HEIGHT; //小さいカードの高さ Card(); void Set(const int number, const int suit, const bool bFaceUp); void Draw(Engine *pEngine, const int destX, const int destY); void FaceUp(); void FaceDown(); bool IsFaceUp() const; bool operator==(const Card &rhs) const; private: static const int SMALL_CARD_X; //小さいカードの左座標 static const int SMALL_CARD_Y; //小さいカードの上座標 static const int SMALL_BACK_X; //小さいカード裏の左座標 static const int SMALL_BACK_Y; //小さいカード裏の上座標 int m_number; int m_suit; bool m_bFaceUp; //表フラグ RECT m_sour; RECT m_dest; }; |
「Card.cpp」を開き、「IsFaceUp関数」の下に本体を追加します。
bool Card::operator==(const Card &rhs) const { return m_number == rhs.m_number; } |
次に「Memory.cpp」の「FacdUp関数」にコードを追加します。
void Memory::FaceUp(const POINT &refPoint)
{
if (m_gameStatus < 2) {
if (refPoint.x >= ADJUST_X && refPoint.x < RIGHT_LIMIT && refPoint.y >= ADJUST_Y && refPoint.y < BOTTOM_LIMIT) {
POINT idx;
idx.x = (refPoint.x - ADJUST_X) / Card::SMALL_CARD_WIDTH;
idx.y = (refPoint.y - ADJUST_Y) / Card::SMALL_CARD_HEIGHT;
int index = idx.y * Card::NUMBER + idx.x;
if (!m_pCard[index].IsFaceUp()) {
m_pCard[index].FaceUp();
m_savePos[m_gameStatus] = index;
m_gameStatus++;
}
}
}
else {
if (m_pCard[m_savePos[0]] == m_pCard[m_savePos[1]]) {
}
else {
m_pCard[m_savePos[0]].FaceDown();
m_pCard[m_savePos[1]].FaceDown();
}
m_gameStatus = 0;
}
}
|
カードが同じ場合は何もしていませんが、違う場合はCardクラスの「FaceDown関数」を呼び出し、カードを「裏」に戻しています。
実行して確かめてみましょう。
<実行結果 クライアント領域のみ>
今のままでは同じ数のカードが残ってしまいますので、同じ数字のカードは表示をしない設定を追加します。
「Card.h」を開き、変数や関数を追加します。
class Card { public: static const int SUIT; static const int NUMBER; static const int SMALL_CARD_WIDTH; //小さいカードの幅 static const int SMALL_CARD_HEIGHT; //小さいカードの高さ Card(); void Set(const int number, const int suit, const bool bFaceUp, const bool bShow = true); void Draw(Engine *pEngine, const int destX, const int destY); void FaceUp(); void FaceDown(); bool IsFaceUp() const; void Show(); void Hide(); bool IsShow() const; bool operator==(const Card &rhs) const; private: static const int SMALL_CARD_X; //小さいカードの左座標 static const int SMALL_CARD_Y; //小さいカードの上座標 static const int SMALL_BACK_X; //小さいカード裏の左座標 static const int SMALL_BACK_Y; //小さいカード裏の上座標 int m_number; int m_suit; bool m_bFaceUp; //表フラグ bool m_bShow; //表示フラグ RECT m_sour; RECT m_dest; }; |
まず、「表示フラグ」を追加しました。
「Set関数」の引数で初期値を代入しますが、基本的には「表示」されると思いますので、デフォルトをtrueにしています。
また、3つのメンバ関数を追加しました。
表示する「Show関数」、消す「Hide関数」、表示中かどうか調べる「IsShow関数」です。
「Card.cpp」を開き、本体を作りましょう。
まず、「Set関数」を変更します。
void Card::Set(const int number, const int suit, const bool bFaceUp, const bool bShow) { m_number = number; m_suit = suit; m_bFaceUp = bFaceUp; m_bShow = bShow; } |
次に「IsFaceUp関数」の下に3つの関数の本体を追加します。
void Card::Show() { m_bShow = true; } void Card::Hide() { m_bShow = false; } bool Card::IsShow() const { return m_bShow; } |
最後に「Draw関数」を変更します。
void Card::Draw(Engine *pEngine, const int destX, const int destY) { if (m_bShow) { if (m_bFaceUp) { SetRect(&m_sour, SMALL_CARD_X + (m_number - 1) * SMALL_CARD_WIDTH, SMALL_CARD_Y + m_suit * SMALL_CARD_HEIGHT, SMALL_CARD_X + (m_number - 1) * SMALL_CARD_WIDTH + SMALL_CARD_WIDTH, SMALL_CARD_Y + m_suit * SMALL_CARD_HEIGHT + SMALL_CARD_HEIGHT ); } else { SetRect(&m_sour, SMALL_BACK_X, SMALL_BACK_Y, SMALL_BACK_X + SMALL_CARD_WIDTH, SMALL_BACK_Y + SMALL_CARD_HEIGHT); } SetRect(&m_dest, destX, destY, destX + SMALL_CARD_WIDTH, destY + SMALL_CARD_HEIGHT); pEngine->Blt(&m_dest, TEXTURE_TRUMP, &m_sour); } } |
これで「表示フラグ」によって、「表示」「非表示」が選べるようになりました。
では、「Memory.cpp」の「FaceUp関数」に戻り、今の変更を反映させるコードを追加します。
void Memory::FaceUp(const POINT &refPoint) { if (m_gameStatus < 2) { if (refPoint.x >= ADJUST_X && refPoint.x < RIGHT_LIMIT && refPoint.y >= ADJUST_Y && refPoint.y < BOTTOM_LIMIT) { POINT idx; idx.x = (refPoint.x - ADJUST_X) / Card::SMALL_CARD_WIDTH; idx.y = (refPoint.y - ADJUST_Y) / Card::SMALL_CARD_HEIGHT; int index = idx.y * Card::NUMBER + idx.x; if (!m_pCard[index].IsFaceUp() && m_pCard[index].IsShow()) { m_pCard[index].FaceUp(); m_savePos[m_gameStatus] = index; m_gameStatus++; } } } else { if (m_pCard[m_savePos[0]] == m_pCard[m_savePos[1]]) { m_pCard[m_savePos[0]].Hide(); m_pCard[m_savePos[1]].Hide(); } else { m_pCard[m_savePos[0]].FaceDown(); m_pCard[m_savePos[1]].FaceDown(); } m_gameStatus = 0; } } |
if文に「表示されている場合」を追加しました。
また、カードの数字が同じ場合「Hide関数」を呼び出し、非表示にしています。
実行して確かめてみましょう。
<実行結果 クライアント領域のみ>
同じ数字を選択した場合、きちんと消えるようになりました。