こんにちは、あんみんどうふです。
今回はミノの設置です。これだけだとすぐ終わっちゃうので、NEXT表示もやります。
前回の記事はこちら。
全編見たい方はタグからどうぞ。
4-0.訂正
・・・の前に訂正箇所がいくつかあります。壁と床を1マスにしていましたが、移動の際にとある方向でIミノを壁や床にくっつけると配列からはみ出してエラーが起きることが判明したので、先に直します。(いるかどうかわかりませんが)参考にしてた方、すみません・・・。
1 2 3 4 | //const int FIELD_WALL = 1; //const int FIELD_FLOOR = 1; const int FIELD_WALL = 2; // 壁の厚さ const int FIELD_FLOOR = 2; // 床の厚さ |
それとLoadイベント時に壁を生成する際、設定した定数に応じて正しく壁を増やすようにしました。以前まではいくら大きい数値にしても1マスの壁しか作らず、意味を成さないものになっていました・・・。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private void mainForm_Load(object sender, EventArgs e) { // 壁と床を作る for(int i = 0; i < field.GetLength(0); i++) { for (int j = 0; j < FIELD_WALL; j++) { field[i, j] = 8; // 左壁 field[i, field.GetLength(1) - 1 - j] = 8; // 右壁 } } for(int i = 0; i < field.GetLength(1); i++) { for (int j = 0; j < FIELD_FLOOR; j++) { field[field.GetLength(0) - 1 - j, i] = 8; // 床 } } |
バグ修正ってやつですね。ゲームでもよく見かけるので正直こういうの憧れてました^^;
4ー1.ミノ設置
その名の通りのことをします。地面にミノを設置すると次のミノが出てきます。これを作ります。
まずは設置処理を新たなメソッドminoDropに書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * テトリミノ設置 */ void minoDrop() { // フィールドに描画 minoDrawing(next[0], dir); // NEXTを進める nextToNext(); // 座標の初期化 x = INITIAL_X; y = INITIAL_Y; dir = 0; } |
たったこれだけ。次にミノ移動メソッドminoMovingの最後のif文に追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | if (minoMoveCheck(move, pwr)) { switch (move) { case 0: // 上 y += -pwr; break; case 1: // 右 x += pwr; break; case 2: // 下 y += pwr; break; case 3: // 左 x += -pwr; break; } } else if(move == 2) { // 下に何かある場合設置処理 minoDrop(); } |
これで一番下までミノを落とすと次のミノが現れます。以上。
(ゲームオーバー判定を作っていないので積み上がるとすごいことになってます・・・。まあ、それはそのうち。)
4-2.NEXT表示
次のミノが現れたのはいいですが、次のミノが全く分からない状態でプレイしているのでいわゆる“運ゲー”になっています。これを解消すべく、NEXTを表示させます。
デザイナーを開き、50×50のpictureboxを6つ作り、それっぽく並べます。nameは「next_1」~「next_6」にします。
このpictureboxにフィールドと同じ要領でNEXTのミノを描画します。
コードに戻り、まずはグローバル変数に新たな定数NEXT_DISPLAYを追加します。
1 | const int NEXT_DISPLAY = 6; // NEXT表示数 |
ここに入力した数の分、NEXTを表示します。
ぷよテトではNEXTが5つ、TETRIS99ではNEXTが6つといったように本家でも作品によって数が異なってたりします。
今回は前回に作ったNEXTがちゃんと機能しているか確かめたいので6つ表示させます。
※6月21日追記: 各作品のNEXTの数間違えてたので修正しました。恥ずかし。
そしてこれもメソッドの外に追記します。グローバル変数の所でもいいです。
1 | private System.Windows.Forms.PictureBox[] nextView; |
続けてNEXTの表示数を切り替える処理をLoadイベントに追記します。
1 2 3 4 5 6 7 8 9 10 11 12 | this.nextView = new System.Windows.Forms.PictureBox[] { next_1, next_2, next_3, next_4, next_5, next_6 }; for(int i = 0; i < nextView.Length; i++) { // 一旦全部非表示にする nextView[i].Visible = false; } for (int i = 1; i <= NEXT_DISPLAY; i++) { // NEXT表示数で設定した分だけ表示 nextView[i - 1].Visible = true; } |
nextViewという配列に先程作ったNEXTのpictureboxを格納しています。理由としてはfor文でまとめて処理できるようにするためです。いちいちnext_X.Visible = true;って書き並べるの面倒だし。
そして新しいメソッドnextDrawingを追加します。これはNEXTを先程作ったpictureboxに描画する処理です。
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | /** * NEXT描画 */ void nextDrowing() { const int SQUARE_NEXT = 10; // NEXTの1マスの大きさ int[,] nextField = new int[6, 6]; // 描画フィールド for (int n = 1; n <= NEXT_DISPLAY; n++) { for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { nextField[i + 1, j + 1] = mino[next[n], 0, i, j]; } } Bitmap canvas = new Bitmap(view_field.Width, view_field.Height); Graphics g = Graphics.FromImage(canvas); for (int i = 0; i < nextField.GetLength(0); i++) { for (int j = 0; j < nextField.GetLength(1); j++) { Color color = Color.White; switch (nextField[i, j]) { case 0: // 空白 color = Color.FromArgb(255, 255, 255); break; case 1: // Iミノ color = Color.FromArgb(0, 255, 255); break; case 2: // Oミノ color = Color.FromArgb(255, 255, 0); break; case 3: // Sミノ color = Color.FromArgb(0, 221, 0); break; case 4: // Zミノ color = Color.FromArgb(255, 0, 0); break; case 5: // Jミノ color = Color.FromArgb(30, 128, 255); break; case 6: // Lミノ color = Color.FromArgb(255, 140, 0); break; case 7: // Tミノ color = Color.FromArgb(255, 0, 255); break; case 8: // 壁 color = Color.FromArgb(0, 0, 0); break; } SolidBrush brush = new SolidBrush(color); // 四角形を描画 g.FillRectangle(brush, j * SQUARE_NEXT - 5, i * SQUARE_NEXT - 5, SQUARE_NEXT, SQUARE_NEXT); brush.Dispose(); } } g.Dispose(); nextView[n - 1].Image = canvas; } } |
フィールド描画のほぼコピペです。NEXT用のフィールド配列を作ってその通りに正方形を描画してるだけです。
後はminoDropにnextDrawingを実行させるように追記すれば完了です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * テトリミノ設置 */ void minoDrop() { // フィールドに描画 minoDrawing(next[0], dir); // NEXTを進める nextToNext(); // 座標・向きの初期化 x = INITIAL_X; y = INITIAL_Y; dir = 0; nextDrawing(); } |
次に出てくるミノがわかるようになり、一気にテトリスらしくなりました!一巡分のミノも7種すべて出てきているので前回作ったNEXTもうまく作れてましたね。よかった~
しかし、回転もできずライン消去もできないこのゲーム、流石にテトリスとは言えません。何をしても最終的に詰んでしまうので最早クソゲーでしかありません。
というわけで次回は回転とライン消去を作ります。(スーパーローテーションはまだやりません)
#5 回転・ライン消去編へ続く。