今回は時間の計測や表示を行ってみます。
まずは残り時間用の定数と変数を追加します。
「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; //転送元左座標 const int TIME_SPAN; //基準となる時間間隔 int m_panelWidth; //パネル1枚の幅 int m_panelHeight; //パネル1枚の高さ int *m_pField; //フィールド unsigned int m_timeRemain; //残り時間 }; |
「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) , TIME_SPAN(60) , m_pField(NULL) { } |
「60」秒を1単位として残り時間を設定します。
「Srart関数」に計算式を追加します。
//============================================================================= // シーンの実行時に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; } m_timeRemain = (m_gameData.m_split - 2) * TIME_SPAN; } |
「難易度」によって残り時間を変えたいので上のような式にしました。
分割単位が「3」であれば「60秒」、「4」であれば「120秒」になります。
残り時間を表示するのに、今回は「DrawNumber関数」を使おうと思います。
リンク先の説明文にも書いてありますが、フォントを使った文字や数値の表示はPCの環境によって変わる可能性があります。
特に数値は変化しますので、特別に関数を用意しました。
使う画像は「information.png」にある↓の部分です。
大きさに制限はありませんが、同じ高さ、同じ幅で「0〜9」と「空欄」が1つ分必要です。
今回は、幅「30ピクセル」高さ「40ピクセル」で作りました。
「DrawNumber関数」の引数は、
転送を開始するX座標。 転送を開始するY座標。 描画したい数値(正数)。 描画したい桁数。 前ゼロ制御(true 前ゼロあり、false なし)。 転送元のX座標(画像の'0'の左上座標) 転送元のY座標(画像の'0'の左上座標) 数字画像1つ分の幅 数字画像1つ分の高さ 転送元となる画像ファイルのパス付ファイル名。 GameBase.hにて定数として宣言する。 |
です。
「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; //転送元左座標 const int NUMBER_DEST_X; //転送先左座標 const int NUMBER_DEST_Y; //転送先上座標 const int NUM_OF_DIGIT; //桁数 const int NUMBER_SOUR_X; //転送元左座標 const int NUMBER_SOUR_Y; //転送元上座標 const int NUMBER_WIDTH; //数字1つ分の幅 const int NUMBER_HEIGHT; //数字1つ分の高さ const int TIME_SPAN; //基準となる時間間隔 int m_panelWidth; //パネル1枚の幅 int m_panelHeight; //パネル1枚の高さ int *m_pField; //フィールド unsigned int m_timeRemain; //残り時間 }; |
「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) , NUMBER_DEST_X(490) , NUMBER_DEST_Y(360) , NUM_OF_DIGIT(3) , NUMBER_SOUR_X(160) , NUMBER_SOUR_Y(0) , NUMBER_WIDTH(30) , NUMBER_HEIGHT(40) , TIME_SPAN(60) , m_pField(NULL) { } |
「Draw関数」で「DrawNumber関数」を呼び出します。
//============================================================================= // シーンの実行時に繰り返し呼び出される描画処理関数 //============================================================================= 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); m_pEngine->DrawNumber( NUMBER_DEST_X, NUMBER_DEST_Y, m_timeRemain, NUM_OF_DIGIT, false, NUMBER_SOUR_X, NUMBER_SOUR_Y, NUMBER_WIDTH, NUMBER_HEIGHT, TEXTURE_INFO); } |
実行してみましょう。
<実行結果 クライアント領域のみ>
前ゼロなし、最大3桁で残り時間が表示されました。
「4×4の16分割」の方も見てみます。
<実行結果 クライアント領域のみ>
上手くいってますね。
次は実際に残り時間を減らしていきます。
実際に1秒に1ずつ減らす必要がありますので、時間の計測を行います。
時間の計測には「IntervalManageクラス」を用意しました。
扱う時間の単位は「ミリ秒(1000分の1秒)」です。
1秒計測したければ「1000」と設定し、1分計測したければ「60000」と設定します。
「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; //転送元左座標 const int NUMBER_DEST_X; //転送先左座標 const int NUMBER_DEST_Y; //転送先上座標 const int NUM_OF_DIGIT; //桁数 const int NUMBER_SOUR_X; //転送元左座標 const int NUMBER_SOUR_Y; //転送元上座標 const int NUMBER_WIDTH; //数字1つ分の幅 const int NUMBER_HEIGHT; //数字1つ分の高さ const int TIME_SPAN; //基準となる時間間隔 int m_panelWidth; //パネル1枚の幅 int m_panelHeight; //パネル1枚の高さ int *m_pField; //フィールド unsigned int m_timeRemain; //残り時間 IntervalManage m_imSpan; //時間計測用 }; |
「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; } m_timeRemain = (m_gameData.m_split - 2) * TIME_SPAN; m_imSpan.SetInterval(1000); } |
計測間隔の設定には「SetInterval関数」を使います。
今回は、1秒間隔で時間計測を行いますので「1000」をセットしました。
次に「Update関数」で1秒経過したかどうかを判断し、経過したら残り時間を減らします。
//============================================================================= // シーンの実行時に繰り返し呼び出される更新処理関数 //============================================================================= 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; } } } } if (m_timeRemain > 0) { if (m_imSpan.GetTiming()) { m_timeRemain--; } } } |
設定した時間が経過したかどうかは「GetTiming関数」で調べます。
残り時間が0より大きい間、1ずつ減少させていきます。
実行してみましょう。
<実行結果 クライアント領域のみ>
次回はゲームのクリアとタイムオーバーシーンを追加します。