こんちは、あんみんどうふです。
今回は回転とライン消去です。学生の頃に作ろうとしたテトリスではライン消去がうまくいかず、ミノが宙に浮いていました。リベンジを果たします。
前回の記事はこちら。
全編見たい方はタグからどうぞ。
5-1.回転
回転処理を新たにminoTurnメソッドに書きます。仕様として、Zキーを押したら左回転、Xキーを押したら右回転させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /** * ミノの回転 * ------------------------------ * turn 回転方向(0…左回転, 1…右回転) */ void minoTurn(int turn) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { // 現在位置に描画しているミノを一旦削除 int target = field[i + y + FIELD_SPACE - 1, j + x + FIELD_WALL]; if (target == mino[next[0], dir, i, j]) { field[i + y + FIELD_SPACE - 1, j + x + FIELD_WALL] = 0; } } } switch (turn) { case 0: // 左回転 dir--; break; case 1: // 右回転 dir++; break; } if (dir < 0) dir = 3; if (dir > 3) dir = 0; // 描画 minoDrawing(next[0], dir); } |
左回転で現在方向(dir)の値を1減らし、右回転で1増やすことで回転します。下のif文は下限上限を超えないようにする処理です。
そしてkeydownイベントに追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private void mainForm_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.Up: // 後でハードドロップの処理を入れる break; case Keys.Left: minoMoving(3, 1); break; case Keys.Right: minoMoving(1, 1); break; case Keys.Down: minoMoving(2, 1); break; case Keys.Z: minoTurn(0); break; case Keys.X: minoTurn(1); break; case Keys.C: // 後でホールドの処理を入れる break; } } |
Z、Xを押したらそれぞれminoTurnを呼び出すようにしました。これで回転が可能になりました。
ちなみに公式ガイドラインによるとキーボード操作の場合上キーが右回転、Spaceキーがハードドロップということになっているらしいです。普段私はSwitchでテトリスをプレイしていますが、パッド操作は上ボタンがハードドロップなんですね。私はこれで慣れちゃっているのでガイドライン通りの操作はちょっと難しく感じますね・・・。
今回はガイドラインに“なるべく近づける”というコンセプトで作っているので、このコードのまま作ります。テトリスさんごめんね!
5-2.ライン消去
横1列揃えたら消えて上の段が落ちてくるようにします。これは新規メソッドminoDeleteに書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /** * ライン消去 */ void minoDelete() { int line = 0; // 消去ライン数 int score = 0; // 獲得スコア数 // フィールド全体を確認する for(int i = 0; i < field.GetLength(0) - FIELD_FLOOR - FIELD_SPACE; i++) { // 各列チェック bool flag = false; for (int j = 0; j < FIELD_WIDTH; j++) { if (field[i + FIELD_SPACE, j + FIELD_WALL] == 0) break; if (j == FIELD_WIDTH - 1) flag = true; } if(flag) { // 1段下げる for(int j = i + FIELD_SPACE; j > 0; j--) { for(int k = 0; k < FIELD_WIDTH; k++) { // 消した列に上の列をコピー field[j, k + FIELD_WALL] = field[j - 1, k + FIELD_WALL]; // 上の列を空白にする field[j - 1, k + FIELD_WALL] = 0; } } line++; } } } |
上から横1列ずつチェックし、何かしらあれば1列すべてにミノがあるかチェックします。1列埋まっているならそこから上のミノをすべて1段分上書きすることで、ライン消去を表現しています。
わかりやすく画像にまとめてみました↓
一応、消去したラインのカウントもしています。今は何にも使ってませんが、後々スコア実装したりするかもしれないし、REN数表示とかやるかもしれないし。
後はminoDropに挟み込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * テトリミノ設置 */ void minoDrop() { // フィールドに描画 minoDrawing(next[0], dir); // NEXTを進める nextToNext(); // ライン消去 minoDelete(); // 座標・向きの初期化 x = INITIAL_X; y = INITIAL_Y; dir = 0; nextDrawing(); } |
ここまで書いたら適当に操作して列を埋めてみます。
ちゃんと回転もするし列も消えてますね。普通のテトリスとしてはほぼほぼ完成です!
さて、ここから現代版テトリスの仕様となります。これからスーパーローテーション、ホールド、ハードドロップを実装していきます!
次回はスーパーローテーションの実装です。今回のテトリス制作で最も難しい部分かもしれません。
#6 スーパーローテーション編へ続く。