★神経衰弱 ゲームルールの作成★


ゲームの下地は出来ましたので、ルール部分を作っていきます。


神経衰弱のルール作り


神経衰弱は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関数」を呼び出し、非表示にしています。

実行して確かめてみましょう。

<実行結果 クライアント領域のみ>

同じ数字を選択した場合、きちんと消えるようになりました。


次へ

戻る

目次へ