前回の続きです。
「宝」の場所をクリックしたら「宝」が表示されるように作りましょう。
「SceneGame.cpp」の「Update関数」を変更します。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); if (point.x >= 0 && point.x < CHIP_WIDTH * COL && point.y >= 0 && point.y < CHIP_HEIGHT * ROW) { int x = point.x / CHIP_WIDTH; int y = point.y / CHIP_HEIGHT; if (m_field[y][x].m_status != CHECKED) { if (m_field[y][x].m_bTreasure) { m_field[y][x].m_status = TREASURE; } else { m_field[y][x].m_status = CHECKED; } } } } } |
クリックした場所が「選択済み(CHECKED)」で無かった場合、
「宝」であったら、状態を「宝(TREASURE)」に変更し、
「宝」で無かったら、状態を「選択済み(CHECKED)」にする。
実行してみましょう。
<実行結果 クライアント領域のみ>
5個の「宝」を見つけるまでの、クリック回数が必要ですから、色々付け加えましょう。
「SceneGame.h」を開き、privateに定数と変数を追加します。
private: const int CHIP_X; const int CHIP_Y; const int CHIP_WIDTH; const int CHIP_HEIGHT; const int TREASURE_MAX; const int REQUIRED; //クリアに必要な宝の数 enum { UNCHECKED, CHECKED, TREASURE, }; //フィールド構造体 struct Field { int m_status; bool m_bTreasure; }; enum { ROW = 10, COL = 10, }; Field m_field[ROW][COL]; int m_clickCount; int m_treasureCount; }; |
「SceneGame.cpp」のコンストラクタ関数で定数の初期値を入れます。
//============================================================================= // コンストラクタ // 引 数:Engine* エンジンクラスのアドレス //============================================================================= SceneGame::SceneGame(Engine *pEngine) : Scene(pEngine) , CHIP_X(0) , CHIP_Y(480) , CHIP_WIDTH(32) , CHIP_HEIGHT(32) , TREASURE_MAX(10) , REQUIRED(5) { } |
次に「Start関数」でm_clickCountとm_treasureCountの初期値を設定します。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { m_field[i][j].m_status = UNCHECKED; m_field[i][j].m_bTreasure = false; } } int idxX; int idxY; for (int i = 0; i < TREASURE_MAX; i++) { do { idxX = rand() % COL; idxY = rand() % ROW; } while (m_field[idxY][idxX].m_bTreasure); m_field[idxY][idxX].m_bTreasure = true; } m_clickCount = 0; m_treasureCount = 0; } |
「Update関数」でクリック回数と「宝」を選択した回数をカウントアップします。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); if (point.x >= 0 && point.x < CHIP_WIDTH * COL && point.y >= 0 && point.y < CHIP_HEIGHT * ROW) { int x = point.x / CHIP_WIDTH; int y = point.y / CHIP_HEIGHT; if (m_field[y][x].m_status != CHECKED) { if (m_field[y][x].m_bTreasure) { m_field[y][x].m_status = TREASURE; m_treasureCount++; } else { m_field[y][x].m_status = CHECKED; } m_clickCount++; } } } } |
「Draw関数」で見つけた宝の数を表示します。
フォントを(いつもの)「MS ゴシック」で20ポイントで追加してください。
※内容は書きません。
//============================================================================= // シーンの実行時に繰り返し呼び出される描画処理関数 //============================================================================= void SceneGame::Draw() { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { SetRect(&m_sour, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH, CHIP_Y, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH + CHIP_WIDTH, CHIP_Y + CHIP_HEIGHT); SetRect(&m_dest, j * CHIP_WIDTH, i * CHIP_HEIGHT, j * CHIP_WIDTH + CHIP_WIDTH, i * CHIP_HEIGHT + CHIP_HEIGHT); m_pEngine->Blt(&m_dest, TEXTURE_TREASURE, &m_sour); } } m_pEngine->DrawPrintf(0, 400, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); m_pEngine->DrawPrintf(0, 420, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); } |
実行してみましょう。
<実行結果 クライアント領域のみ>
それでは終了判定を追加します。
「SceneGame.h」を開き、privateに変数を追加します。
private:
const int CHIP_X;
const int CHIP_Y;
const int CHIP_WIDTH;
const int CHIP_HEIGHT;
const int TREASURE_MAX;
const int REQUIRED;
enum {
UNCHECKED,
CHECKED,
TREASURE,
};
//フィールド構造体
struct Field {
int m_status;
bool m_bTreasure;
};
enum { ROW = 10, COL = 10, };
Field m_field[ROW][COL];
int m_clickCount;
int m_treasureCount;
bool m_bFinish;
};
|
「SceneGame.cpp」の「Start関数」で初期化します。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { m_field[i][j].m_status = UNCHECKED; m_field[i][j].m_bTreasure = false; } } int idxX; int idxY; for (int i = 0; i < TREASURE_MAX; i++) { do { idxX = rand() % COL; idxY = rand() % ROW; } while (m_field[idxY][idxX].m_bTreasure); m_field[idxY][idxX].m_bTreasure = true; } m_clickCount = 0; m_treasureCount = 0; m_bFinish = false; } |
「Update関数」に判定を追加します。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); if (point.x >= 0 && point.x < CHIP_WIDTH * COL && point.y >= 0 && point.y < CHIP_HEIGHT * ROW) { int x = point.x / CHIP_WIDTH; int y = point.y / CHIP_HEIGHT; if (m_field[y][x].m_status != CHECKED) { if (m_field[y][x].m_bTreasure) { m_field[y][x].m_status = TREASURE; m_treasureCount++; } else { m_field[y][x].m_status = CHECKED; } m_clickCount++; } } } if (m_treasureCount >= REQUIRED) { m_bFinish = true; } } |
本来であれば、ここでシーンを変えて結果を表示するべきですが、まだ他の事もやりたいのでシーンは追加しません。
今回はゲームが終わったら動かないようにします。
皆さんはシーンを追加していただいても構いません!
「SceneGame.cpp」の「Update関数」を変更します。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (!m_bFinish) { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); if (point.x >= 0 && point.x < CHIP_WIDTH * COL && point.y >= 0 && point.y < CHIP_HEIGHT * ROW) { int x = point.x / CHIP_WIDTH; int y = point.y / CHIP_HEIGHT; if (m_field[y][x].m_status != CHECKED) { if (m_field[y][x].m_bTreasure) { m_field[y][x].m_status = TREASURE; m_treasureCount++; } else { m_field[y][x].m_status = CHECKED; } m_clickCount++; } } } if (m_treasureCount >= REQUIRED) { m_bFinish = true; } } } |
これで5個の宝を見つけたらゲームが止まります。
やってみてください。
<実行結果 クライアント領域のみ>
これで完成です!
元画像を見ると左下に背景画像があります。
これを使って「見た目」を変えてみます。
今回は定数設定を考えていますので、「SceneGame.h」を開き、定数を追加します。
private:
const int CHIP_X;
const int CHIP_Y;
const int CHIP_WIDTH;
const int CHIP_HEIGHT;
const int BACK_SOUR_X; //背景の転送元左座標
const int BACK_SOUR_Y; //背景の転送元上座標
const int BACK_DEST_X; //背景の転送先左座標
const int BACK_DEST_Y; //背景の転送先上座標
const int BACK_WIDTH; //背景の幅
const int BACK_HEIGHT; //背景の高さ
const int TREASURE_MAX;
const int REQUIRED; //クリアに必要な宝の数
enum {
UNCHECKED,
CHECKED,
TREASURE,
};
//フィールド構造体
struct Field {
int m_status;
bool m_bTreasure;
};
enum { ROW = 10, COL = 10, };
Field m_field[ROW][COL];
int m_clickCount;
int m_treasureCount;
};
|
「SceneGame.cpp」のコンストラクタ関数で初期値を入れます。
//============================================================================= // コンストラクタ // 引 数:Engine* エンジンクラスのアドレス //============================================================================= SceneGame::SceneGame(Engine *pEngine) : Scene(pEngine) , CHIP_X(0) , CHIP_Y(480) , CHIP_WIDTH(32) , CHIP_HEIGHT(32) , TREASURE_MAX(10) , REQUIRED(5) , BACK_SOUR_X(0) , BACK_SOUR_Y(544) , BACK_DEST_X(0) , BACK_DEST_Y(0) , BACK_WIDTH(640) , BACK_HEIGHT(480) { } |
配置が変わる事も考えて定数化しました。
「Draw関数」で背景を転送しましょう。
//============================================================================= // シーンの実行時に繰り返し呼び出される描画処理関数 //============================================================================= void SceneGame::Draw() { SetRect(&m_sour, BACK_SOUR_X, BACK_SOUR_Y, BACK_SOUR_X + BACK_WIDTH, BACK_SOUR_Y + BACK_HEIGHT); SetRect(&m_dest, BACK_DEST_X, BACK_DEST_Y, BACK_DEST_X + BACK_WIDTH, BACK_DEST_Y + BACK_HEIGHT); m_pEngine->Blt(&m_dest, TEXTURE_TREASURE, &m_sour); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { SetRect(&m_sour, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH, CHIP_Y, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH + CHIP_WIDTH, CHIP_Y + CHIP_HEIGHT); SetRect(&m_dest, j * CHIP_WIDTH, i * CHIP_HEIGHT, j * CHIP_WIDTH + CHIP_WIDTH, i * CHIP_HEIGHT + CHIP_HEIGHT); m_pEngine->Blt(&m_dest, TEXTURE_TREASURE, &m_sour); } } m_pEngine->DrawPrintf(0, 400, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); m_pEngine->DrawPrintf(0, 420, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); } |
実行してみましょう。
<実行結果 クライアント領域のみ>
ずれてますよね。
背景は真ん中に白い領域があります。
サイズはフィールドと同じ「320×320ピクセル」です。
と言う事は転送先の開始座標は、左座標が
(640 - 320) / 2 = 160
で、上座標が、
(480 - 320) / 2 = 80
です。
この数値は定数化します。
「SceneGame.h」を開き、privateに定数を追加しましょう。
private:
const int CHIP_X;
const int CHIP_Y;
const int CHIP_WIDTH;
const int CHIP_HEIGHT;
const int BACK_SOUR_X; //背景の転送元左座標
const int BACK_SOUR_Y; //背景の転送元上座標
const int BACK_DEST_X; //背景の転送先左座標
const int BACK_DEST_Y; //背景の転送先上座標
const int BACK_WIDTH; //背景の幅
const int BACK_HEIGHT; //背景の高さ
const int FIELD_X; //フィールドの転送開始X座標
const int FIELD_Y; //フィールドの転送開始Y座標
const int TREASURE_MAX;
const int REQUIRED; //クリアに必要な宝の数
enum {
UNCHECKED,
CHECKED,
TREASURE,
};
//フィールド構造体
struct Field {
int m_status;
bool m_bTreasure;
};
enum { ROW = 10, COL = 10, };
Field m_field[ROW][COL];
int m_clickCount;
int m_treasureCount;
};
|
「SceneGame.cpp」のコンストラクタ関数で初期値を入れます。
//============================================================================= // コンストラクタ // 引 数:Engine* エンジンクラスのアドレス //============================================================================= SceneGame::SceneGame(Engine *pEngine) : Scene(pEngine) , CHIP_X(0) , CHIP_Y(480) , CHIP_WIDTH(32) , CHIP_HEIGHT(32) , TREASURE_MAX(10) , REQUIRED(5) , BACK_SOUR_X(0) , BACK_SOUR_Y(544) , BACK_DEST_X(0) , BACK_DEST_Y(0) , BACK_WIDTH(640) , BACK_HEIGHT(480) , FIELD_X(160) , FIELD_Y(80) { } |
「Update関数」の範囲をチェックする箇所を変更します。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= void SceneGame::Update() { if (!m_bFinish) { if (m_pEngine->GetMouseButtonSync(DIK_LBUTTON)) { POINT point = m_pEngine->GetMousePosition(); if (point.x >= FIELD_X && point.x < FIELD_X + CHIP_WIDTH * COL && point.y >= FIELD_Y && point.y < FIELD_Y + CHIP_HEIGHT * ROW) { int x = (point.x - FIELD_X) / CHIP_WIDTH; int y = (point.y - FIELD_Y) / CHIP_HEIGHT; if (m_field[y][x].m_status != CHECKED) { if (m_field[y][x].m_bTreasure) { m_field[y][x].m_status = TREASURE; m_treasureCount++; } else { m_field[y][x].m_status = CHECKED; } m_clickCount++; } } } if (m_treasureCount >= REQUIRED) { m_bFinish = true; } } } |
「Draw関数」も変えます。
//============================================================================= // シーンの実行時に繰り返し呼び出される描画処理関数 //============================================================================= void SceneGame::Draw() { SetRect(&m_sour, BACK_SOUR_X, BACK_SOUR_Y, BACK_SOUR_X + BACK_WIDTH, BACK_SOUR_Y + BACK_HEIGHT); SetRect(&m_dest, BACK_DEST_X, BACK_DEST_Y, BACK_DEST_X + BACK_WIDTH, BACK_DEST_Y + BACK_HEIGHT); m_pEngine->Blt(&m_dest, TEXTURE_TREASURE, &m_sour); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { SetRect(&m_sour, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH, CHIP_Y, CHIP_X + m_field[i][j].m_status * CHIP_WIDTH + CHIP_WIDTH, CHIP_Y + CHIP_HEIGHT); SetRect(&m_dest, FIELD_X + j * CHIP_WIDTH, FIELD_Y + i * CHIP_HEIGHT, FIELD_X + j * CHIP_WIDTH + CHIP_WIDTH, FIELD_Y + i * CHIP_HEIGHT + CHIP_HEIGHT); m_pEngine->Blt(&m_dest, TEXTURE_TREASURE, &m_sour); } } m_pEngine->DrawPrintf(0, 400, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); m_pEngine->DrawPrintf(0, 420, FONT_GOTHIC, D3DCOLOR_XRGB(255, 255, 255), "発見した宝 %d", m_treasureCount); } |
実行してみましょう。
<実行結果 クライアント領域のみ>
出来ました!!
タイトルシーンを作って、超ミニゲームを作りました。
最初はこれくらいからで良いんです、ちょっとずつ大きなものを作れるよう頑張りましょう。