★スライドパズル ゲームシーン2★


シャッフルされた画像をスライドさせるプログラムを作ります。


画像のスライド


番号が「0」のパネルの「上」か「右」か「下」か「左」のパネルをクリックすると画像が入れ替わり、スライドしたように見せます。

そこまで難しいプログラムでは無いと思いますので、一気に書いておきます。

「SceneGame.cpp」の「Update関数」に追加します。

//=============================================================================
// シーンの実行時に繰り返し呼び出される更新処理関数
//=============================================================================
void SceneGame::Update()
{
    if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) {

        POINT point = m_pEngine->GetMousePosition();

        if (point.x >= 0 && point.x < PUZZLE_WIDTH && point.y >= 0 && point.y < PUZZLE_HEIGHT) {

            int x = point.x / m_panelWidth;
            int y = point.y / m_panelHeight;

            int work;

            if (y - 1 >= 0) {
                if (m_pField[(y - 1) * m_gameData.m_split + x] == 0) {
                    work = m_pField[(y - 1) * m_gameData.m_split + x];
                    m_pField[(y - 1) * m_gameData.m_split + x] = m_pField[y * m_gameData.m_split + x];
                    m_pField[y * m_gameData.m_split + x] = work;
                }
            }

            if (x + 1 < m_gameData.m_split) {
                if (m_pField[y * m_gameData.m_split + (x + 1)] == 0) {
                    work = m_pField[y * m_gameData.m_split + (x + 1)];
                    m_pField[y * m_gameData.m_split + (x + 1)] = m_pField[y * m_gameData.m_split + x];
                    m_pField[y * m_gameData.m_split + x] = work;
                }
            }

            if (y + 1 < m_gameData.m_split) {
                if (m_pField[(y + 1) * m_gameData.m_split + x] == 0) {
                    work = m_pField[(y + 1) * m_gameData.m_split + x];
                    m_pField[(y + 1) * m_gameData.m_split + x] = m_pField[y * m_gameData.m_split + x];
                    m_pField[y * m_gameData.m_split + x] = work;
                }
            }

            if (x - 1 >= 0) {
                if (m_pField[y * m_gameData.m_split + (x - 1)] == 0) {
                    work = m_pField[y * m_gameData.m_split + (x - 1)];
                    m_pField[y * m_gameData.m_split + (x - 1)] = m_pField[y * m_gameData.m_split + x];
                    m_pField[y * m_gameData.m_split + x] = work;
                }
            }
        }
    }
}

マウスの左ボタンが押されたら、座標を取得し領域判定を行います。

領域内であれば、パネルの幅と高さで割り算して2次元配列の縦横座標に変換します。

クリックした場所の「上下左右」のどこかに「空(番号が0)」のパネルがあれば入れ替えます。

実行してみましょう。

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


情報画面の転送


画面の右側にはゲームに使っていない「黒い」領域があります。

この部分を活用するために、↓の画像を用意しました。

画像サイズは「512×512ピクセル」で画面右の「黒い」領域にぴったりはまるようなパーツが書かれています。

上の方の「赤く塗りつぶしてある領域」には完成形の画像を表示するための領域。

下の「赤い枠が3つ並んでいる領域」には残り時間を設定し表示するための領域。

※プロジェクトフォルダの「Resource\\Textureフォルダ」に「Information.png」と言うファイル名で保存してください。

「GameBase.h」を開き、ファイル名を定数化します。

//-----------------------------------------------------------------------------
//ゲーム中で使用するテクスチャ、BGM、SE、フォントのパス付ファイル名を書きます。
//-----------------------------------------------------------------------------
namespace KeyString
{
    const std::string TEXTURE_TITLE = "Resource\\Texture\\PuzzleTitle.png";

    const std::string TEXTURE_PUZZLE3 = "Resource\\Texture\\omelette_square.png";

    const std::string TEXTURE_PUZZLE4 = "Resource\\Texture\\gang.png";

    const std::string TEXTURE_INFO = "Resource\\Texture\\Information.png";
}

「SceneGame.cpp」の「Start関数」で画像を追加します。

//=============================================================================
// シーンの実行時に1度だけ呼び出される開始処理関数
//=============================================================================
void SceneGame::Start()
{
    m_pEngine->AddTexture(TEXTURE_INFO);

    m_panelWidth = PUZZLE_WIDTH / m_gameData.m_split;
    m_panelHeight = PUZZLE_HEIGHT / m_gameData.m_split;

    int size = m_gameData.m_split * m_gameData.m_split;

    m_pField = new int[size];

    for (int i = 0; i < size; i++) {
        m_pField[i] = i;
    }

    int x1, y1;
    int x2, y2;

    int work;

    int shuffle_num = m_gameData.m_split * SHUFFLE;

    x1 = y1 = x2 = y2 = 0;

    for (int i = 0; i < shuffle_num; i++) {

        switch (rand() % 4) {

        case 0:
            if (y1 - 1 >= 0) {
                x2 = x1;
                y2 = y1 - 1;
            }
            break;

        case 1:
            if (x1 + 1 < m_gameData.m_split) {
                x2 = x1 + 1;
                y2 = y1;
            }
            break;

        case 2:
            if (y1 + 1 < m_gameData.m_split) {
                x2 = x1;
                y2 = y1 + 1;
            }
            break;

        case 3:
            if (x1 - 1 >= 0) {
                x2 = x1 - 1;
                y2 = y1;
            }
            break;
        }

        work = m_pField[y1 * m_gameData.m_split + x1];
        m_pField[y1 * m_gameData.m_split + x1] = m_pField[y2 * m_gameData.m_split + x2];
        m_pField[y2 * m_gameData.m_split + x2] = work;

        x1 = x2;
        y1 = y2;
    }
}

次に「SceneGame.h」を開き、座標用の定数を追加します。

private:

    const int PUZZLE_WIDTH;  //元画像の幅
    const int PUZZLE_HEIGHT; //元画像の高さ

    const int SHUFFLE; //シャッフル回数

    const int INFO_SOUR_X; //転送元左座標
    const int INFO_SOUR_Y; //転送元上座標
    const int INFO_DEST_X; //転送先左座標
    const int INFO_DEST_Y; //転送先上座標
    const int INFO_WIDTH;  //画像の幅
    const int INFO_HEIGHT; //画像の高さ

    int m_panelWidth;  //パネル1枚の幅
    int m_panelHeight; //パネル1枚の高さ

    int *m_pField; //フィールド
};

「SceneGame.cpp」のコンストラクタ関数で初期値を代入します。

//=============================================================================
// コンストラクタ
// 引 数:Engine* エンジンクラスのアドレス
//=============================================================================
SceneGame::SceneGame(Engine *pEngine) : Scene(pEngine)
    , PUZZLE_WIDTH(480)
    , PUZZLE_HEIGHT(480)
    , SHUFFLE(100)
    , INFO_SOUR_X(0)
    , INFO_SOUR_Y(0)
    , INFO_DEST_X(480)
    , INFO_DEST_Y(0)
    , INFO_WIDTH(160)
    , INFO_HEIGHT(480)
    , m_pField(NULL)
{

}

ヘッダファイルで宣言した順に初期値を代入しなければなりませんので、順番には気を付けてください。

「Draw関数」で転送しましょう。

//=============================================================================
// シーンの実行時に繰り返し呼び出される描画処理関数
//=============================================================================
void SceneGame::Draw()
{
    for (int i = 0; i < m_gameData.m_split; i++) {
        for (int j = 0; j < m_gameData.m_split; j++) {

            if (m_pField[i * m_gameData.m_split + j] != 0) {

                SetRect(&m_sour,
                    (m_pField[i * m_gameData.m_split + j] % m_gameData.m_split) * m_panelWidth,
                    (m_pField[i * m_gameData.m_split + j] / m_gameData.m_split) * m_panelHeight,
                    (m_pField[i * m_gameData.m_split + j] % m_gameData.m_split) * m_panelWidth + m_panelWidth,
                    (m_pField[i * m_gameData.m_split + j] / m_gameData.m_split) * m_panelHeight + m_panelHeight);

                SetRect(&m_dest,
                    j * m_panelWidth,
                    i * m_panelHeight,
                    j * m_panelWidth + m_panelWidth,
                    i * m_panelHeight + m_panelHeight);

                m_pEngine->Blt(&m_dest, m_gameData.m_strGraphicName, &m_sour);
            }
        }
    }

    SetRect(&m_sour,
        INFO_SOUR_X,
        INFO_SOUR_Y,
        INFO_SOUR_X + INFO_WIDTH,
        INFO_SOUR_Y + INFO_HEIGHT);


    SetRect(&m_dest,
        INFO_DEST_X,
        INFO_DEST_Y,
        INFO_DEST_X + INFO_WIDTH,
        INFO_DEST_Y + INFO_HEIGHT);

    m_pEngine->Blt(&m_dest, TEXTURE_INFO, &m_sour);
}

実行してみましょう。

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


完成形の転送


情報画面の「赤く塗りつぶされた領域」に完成画像を転送します。

「SceneGame.h」を開き、座標用の定数を追加します。

private:

    const int PUZZLE_WIDTH;  //元画像の幅
    const int PUZZLE_HEIGHT; //元画像の高さ

    const int SHUFFLE; //シャッフル回数

    const int INFO_SOUR_X; //転送元左座標
    const int INFO_SOUR_Y; //転送元上座標
    const int INFO_DEST_X; //転送先左座標
    const int INFO_DEST_Y; //転送先上座標
    const int INFO_WIDTH;  //画像の幅
    const int INFO_HEIGHT; //画像の高さ

    const int ANSWER_DEST_X; //転送先左座標
    const int ANSWER_DEST_Y; //転送先上座標
    const int ANSWER_WIDTH;  //転送元左座標
    const int ANSWER_HEIGHT; //転送元左座標

    int m_panelWidth;  //パネル1枚の幅
    int m_panelHeight; //パネル1枚の高さ

    int *m_pField; //フィールド
};

「SceneGame.cpp」のコンストラクタ関数で初期値を代入します。

//=============================================================================
// コンストラクタ
// 引 数:Engine* エンジンクラスのアドレス
//=============================================================================
SceneGame::SceneGame(Engine *pEngine) : Scene(pEngine)
    , PUZZLE_WIDTH(480)
    , PUZZLE_HEIGHT(480)
    , SHUFFLE(100)
    , INFO_SOUR_X(0)
    , INFO_SOUR_Y(0)
    , INFO_DEST_X(480)
    , INFO_DEST_Y(0)
    , INFO_WIDTH(160)
    , INFO_HEIGHT(480)
    , ANSWER_DEST_X(490)
    , ANSWER_DEST_Y(100)
    , ANSWER_WIDTH(140)
    , ANSWER_HEIGHT(140)
    , m_pField(NULL)
{

}

「Draw関数」で転送します。

//=============================================================================
// シーンの実行時に繰り返し呼び出される描画処理関数
//=============================================================================
void SceneGame::Draw()
{
    for (int i = 0; i < m_gameData.m_split; i++) {
        for (int j = 0; j < m_gameData.m_split; j++) {

            if (m_pField[i * m_gameData.m_split + j] != 0) {

                SetRect(&m_sour,
                    (m_pField[i * m_gameData.m_split + j] % m_gameData.m_split) * m_panelWidth,
                    (m_pField[i * m_gameData.m_split + j] / m_gameData.m_split) * m_panelHeight,
                    (m_pField[i * m_gameData.m_split + j] % m_gameData.m_split) * m_panelWidth + m_panelWidth,
                    (m_pField[i * m_gameData.m_split + j] / m_gameData.m_split) * m_panelHeight + m_panelHeight);

                SetRect(&m_dest,
                    j * m_panelWidth,
                    i * m_panelHeight,
                    j * m_panelWidth + m_panelWidth,
                    i * m_panelHeight + m_panelHeight);

                m_pEngine->Blt(&m_dest, m_gameData.m_strGraphicName, &m_sour);
            }
        }
    }

    SetRect(&m_sour,
        INFO_SOUR_X,
        INFO_SOUR_Y,
        INFO_SOUR_X + INFO_WIDTH,
        INFO_SOUR_Y + INFO_HEIGHT);


    SetRect(&m_dest,
        INFO_DEST_X,
        INFO_DEST_Y,
        INFO_DEST_X + INFO_WIDTH,
        INFO_DEST_Y + INFO_HEIGHT);

    m_pEngine->Blt(&m_dest, TEXTURE_INFO, &m_sour);

    SetRect(&m_sour,
        0,
        0,
        PUZZLE_WIDTH,
        PUZZLE_HEIGHT);

    SetRect(&m_dest,
        ANSWER_DEST_X,
        ANSWER_DEST_Y,
        ANSWER_DEST_X + ANSWER_WIDTH,
        ANSWER_DEST_Y + ANSWER_HEIGHT);

    m_pEngine->Blt(&m_dest, m_gameData.m_strGraphicName, &m_sour);
}

実行してみましょう。

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


次回は時間の計測や表示を行います。


次へ

戻る

目次へ