消したブロックの上に残っているブロックは下へ落とす必要があります。
イメージは「ぷよぷよ」と同じですが、途中のアニメーションはありません。
まずは「Samegame.h」を開き、privateメンバ関数を追加します。
//選択したブロック数を取得する int GetSelectBlockNum() const; //選択したブロックを削除する void DeleteSelectBlock(); //ブロックを落とす void FallBlock(); }; |
「DeleteBlock関数」から「FallBlock関数」を呼び出します。
//ブロックを消す void Samegame::DeleteBlock() { if (m_selectBlockNum <= 1) { return; } DeleteSelectBlock(); FallBlock(); } |
「DeleteSelectBlock関数」の下に「FallBlock関数」の本体を追加します。
//ブロックを落とす
void Samegame::FallBlock()
{
}
|
まだ枠組みだけです。
考え方を説明しながらプログラムを書いていきます。
まず、フィールドの左から1列ずつ、最下段から最上段までブロックを調べます。
これをプログラムで書くと↓のようになります。
//ブロックを落とす void Samegame::FallBlock() { for (int j = 0; j < COL; j++) { for (int i = ROW - 1; i >= 0; i--) { } } } |
次に、最初に出てくる「空のブロック」の箇所を探し、添え字を保存しておきます。
プログラムに追加します。
//ブロックを落とす void Samegame::FallBlock() { int spaceIndex; bool bFirstSpace; for (int j = 0; j < COL; j++) { bFirstSpace = false; for (int i = ROW - 1; i >= 0; i--) { if (!bFirstSpace) { if (m_field[i][j].m_color == NO_BLOCK) { spaceIndex = i; bFirstSpace = true; } } } } } |
添え字を保存するため「spaceIndex」を用意しました。
また「最初の空のブロック」を見つけた後は別のプログラムを動かすため、フラグ「bFirstSpace」を用意しました。
1列ずつ同じ事を繰り返すため、「bFirstSpace」は最初のループ内でfalseを代入します。
フラグがfalseの間「空のブロック」を探し、見つけたら「spaceIndex」に添え字を格納、フラグをtrueにします。
引き続き最上段までのループを続けますが、今度は「ブロック」を探します。
ブロックを見つけたら、保存しておいた添え字を使ってブロックを入れ替えます。
入れ替えた後は、保存しておいた添え字を−1します。
では、プログラムを追加します。
//ブロックを落とす void Samegame::FallBlock() { int spaceIndex; bool bFirstSpace; Block work; for (int j = 0; j < COL; j++) { bFirstSpace = false; for (int i = ROW - 1; i >= 0; i--) { if (!bFirstSpace) { if (m_field[i][j].m_color == NO_BLOCK) { spaceIndex = i; bFirstSpace = true; } } else { if (m_field[i][j].m_color != NO_BLOCK) { work = m_field[i][j]; m_field[i][j] = m_field[spaceIndex][j]; m_field[spaceIndex][j] = work; spaceIndex--; } } } } } |
これで完成なのですが、コンパイルすると警告が出ます。
warning C4701: 初期化されていない可能性のあるローカル変数 'spaceIndex' が使用されます
プログラムをトレースしていけば、初期値が入らない時に使われる事が無いと分かりますが、警告は潰しておくべきです。
意味はありませんが、最初の宣言時に初期値を入れておきましょう。
int spaceIndex = 0; //警告対策
|
では、実行してみましょう。
<実行結果 クライアント領域のみ>
上に残ったブロックが落ちてくればOKです。