カードの表示が出来たので、カードをめくるところまで作ります。
まずはカードをシャッフルします。
シャッフルの方法は、ポーカーと同じ方法で行います。
「Memory.h」を開き、プロトタイプ宣言とシャッフル回数の定数を追加します。
//前方参照 class Card; class Memory { public: Memory(); ~Memory(); void Initialize(); void Shuffle(); void DrawCard(Engine *pEngine); private: const int ADJUST_X; //中央に転送するための調整用X座標 const int ADJUST_Y; //中央に転送するための調整用Y座標 const int SHUFFLE; //シャッフル回数 //カードクラス配列用ポインタ Card *m_pCard; }; |
「Memory.cpp」を開き、コンストラクタ関数で定数の初期値を設定します。
Memory::Memory()
: ADJUST_X(60)
, ADJUST_Y(120)
, SHUFFLE(2000)
, m_pCard(NULL)
{
}
|
「Initialize関数」の下に「Shuffle関数」の本体を追加します。
※プロトタイプ宣言の順番と同じように本体も書きましょう。
void Memory::Shuffle() { const int CARD_MAX = Card::SUIT * Card::NUMBER; int idx1; int idx2; Card work; for (int i = 0; i < SHUFFLE; i++) { idx1 = rand() % CARD_MAX; idx2 = rand() % CARD_MAX; work = m_pCard[idx1]; m_pCard[idx1] = m_pCard[idx2]; m_pCard[idx2] = work; } } |
「SceneGame.cpp」を開き、「Start関数」でMemoryクラスの「Shuffle関数」を呼び出しましょう。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { m_pEngine->AddTexture(TEXTURE_TRUMP); m_memory.Initialize(); m_memory.Shuffle(); } |
実行して確認しましょう。
<実行結果 クライアント領域のみ>
シャッフル出来ているようです。
カードが表になったままでは、神経衰弱は出来ません。
カードを裏返しておき、クリックしたら表になるようにしましょう。
まずは「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; 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; }; |
まず、「表フラグ」を追加しました。
値がtrueであれば「表」、falseであれば「裏」になります。
また、「裏」のカードの転送元座標用の定数も追加しました。
「Set関数」に引数を1つ追加し、初期状態が表か裏か選べるようにしています。
さらに、新しいメンバ関数を3つ追加しています。
カードを「表」にする「FaceUp関数」、「裏」にする「FaceDown関数」、「表」かどうか調べる「IsFaceUp関数」です。
これらの変更に伴い「Card.cpp」も色々変更します。
まず、static定数の初期値を代入します。
const int Card::SUIT = 4;
const int Card::NUMBER = 13;
const int Card::SMALL_CARD_WIDTH = 40;
const int Card::SMALL_CARD_HEIGHT = 60;
const int Card::SMALL_CARD_X = 0;
const int Card::SMALL_CARD_Y = 750;
const int Card::SMALL_BACK_X = 0;
const int Card::SMALL_BACK_Y = 990;
|
「Set関数」の引数を追加し、内容も追加します。
void Card::Set(const int number, const int suit, const bool bFaceUp) { m_number = number; m_suit = suit; m_bFaceUp = bFaceUp; } |
「Draw関数」の下に3つのメンバ関数の本体を追加します。
void Card::FaceUp() { m_bFaceUp = true; } void Card::FaceDown() { m_bFaceUp = false; } bool Card::IsFaceUp() const { return m_bFaceUp; } |
「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);
}
}
}
|
falseを渡すので、最初は「伏せてある」状態になります。
とは言え、今はまだ「伏せてある」状態にはなりません。
「Card.cpp」の「Draw関数」を変更します。
void Card::Draw(Engine *pEngine, const int destX, const int destY) { 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); } |
「表フラグ」がfalseの時は「裏」を表示するようにしました。
実行して確認してみましょう。
<実行結果 クライアント領域のみ>
出来ました!
次は選択したカードを「表」にします。
マウスのボタン入力や座標の取得は「SceneGame.cpp」で行い、実際に「表」にするのは「Memory.cpp」で行います。
先に、マウス関係の処理を追加しますので「SceneGame.cpp」の「Update関数」にコードを追加します。
//=============================================================================
// シーンの実行時に繰り返し呼び出される更新処理関数
//=============================================================================
void SceneGame::Update()
{
if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) {
POINT point = m_pEngine->GetMousePosition();
}
}
|
「Memory.h」を開き、メンバ関数を1つと定数を追加します。
//前方参照 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; }; |
「FaceUp関数」はクリック座標の参照を受け取り、カードを「表」にする関数です。
「Memory.cpp」を開き、コンストラクタ関数で定数の初期値を設定します。
Memory::Memory()
: ADJUST_X(60)
, ADJUST_Y(120)
, SHUFFLE(2000)
, RIGHT_LIMIT(ADJUST_X + Card::NUMBER * Card::SMALL_CARD_WIDTH)
, BOTTOM_LIMIT(ADJUST_Y + Card::SUIT * Card::SMALL_CARD_HEIGHT)
, m_pCard(NULL)
{
}
|
どちらも計算式が長いので、定数にしてまとめました。
次に「Memory.cpp」の「Shuffle関数」の下に「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(); } } } |
受け取った座標が、カードが並べられている範囲内にあるかどうか調べます。
範囲内であれば、2次元配列の座標に変換します。
さらに扱いやすいように、1次元配列の座標に変換します。
該当するカードが「裏」の場合、「表」に変更します。
最後に「SceneGame.cpp」を開き、「Update関数」でMemory.cppの「FaceUp関数」を呼び出します。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); m_memory.FaceUp(point); } } |
実行してみましょう。
<実行結果 クライアント領域のみ>
クリックした箇所が「表」になればOKです。