★神経衰弱 カードをめくる★


カードの表示が出来たので、カードをめくるところまで作ります。


カードのシャッフル


まずはカードをシャッフルします。

シャッフルの方法は、ポーカーと同じ方法で行います。

「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です。


次へ

戻る

目次へ