テトリスのガイドラインではホールドに関する記述があります。これによると
テトリミノを1個保持できる。
使うと現在のミノがホールドに入り、ホールドにあったミノが降ってくる
(最初だけはネクストが降る)。
1回使うと設置するまで使えない。
とあります。さっそくプログラムに組み込んでみましょう。
まず、デザイナでホールドされたテトリミノが表示される部分を作成します。
またキーボードによる操作もガイドラインでは決められています。
↓がソフトドロップなのはわかるとしてなぜか右回転は↑キーです。ちょっとやりにくい。またスペースキーにはこれまで回転を割り当てていましたが、ハードドロップを割り当てるべきと書かれています。ホールドはCキーまたは左右のShiftキーになっています。
← 左に移動
→ 右に移動
↑ 右回転
↓ ソフトドロップ
スペースキー ハードドロップ
Shiftキー ホールド
Ctrlキー 左回転
Zキー 左回転
Xキー 右回転
Cキー ホールド
ESCキー Pouse
F1キー Pouse
それではそのように変更しましょう。
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 |
public partial class Form1 : Form { private void Form1_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Left) MoveLeftTetoro(); else if(e.KeyCode == Keys.Right) MoveRightTetoro(); else if(e.KeyCode == Keys.Up) RotateTetoro(); else if(e.KeyCode == Keys.Down) SoftDrop(); else if(e.KeyCode == Keys.Space) HardDrop(); else if(e.KeyCode == Keys.ControlKey) RotateTetoro2(); else if(e.KeyCode == Keys.ShiftKey) Hold(); else if(e.KeyCode == Keys.Z) RotateTetoro2(); else if(e.KeyCode == Keys.X) RotateTetoro(); else if(e.KeyCode == Keys.C) Hold(); else if(e.KeyCode == Keys.Escape) Pouse(); else if(e.KeyCode == Keys.F1) Pouse(); } void Hold() { // あとで考える } void Pouse() { // あとで考える } } |
ホールドするためにはホールドされているミノを格納する変数が必要です。
1 |
TetoroTypes holdTetoro = TetoroTypes.None; |
最初はホールドされているミノは存在しないので列挙体にNoneを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public partial class Form1 : Form { enum TetoroTypes { // I - テトリミノ(水色) // O - テトリミノ(黄色) // S - テトリミノ(緑) // Z - テトリミノ(赤) // J - テトリミノ(青) // L - テトリミノ(オレンジ) // T - テトリミノ(紫) I = 0, O = 1, S = 2, Z = 3, J = 4, L = 5, T = 6, None = 7, // 追加 } } |
ピクチャーボックスにホールドされているミノのイメージを表示させる必要があります。TetoroTypesからイメージを取得するメソッドとしてGetImageFromTetoroTypeを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Form1 : Form { Image GetImageFromTetoroType(TetoroTypes types) { if(types == TetoroTypes.I) return Properties.Resources.i; if(types == TetoroTypes.J) return Properties.Resources.j; if(types == TetoroTypes.L) return Properties.Resources.l; if(types == TetoroTypes.O) return Properties.Resources.o; if(types == TetoroTypes.S) return Properties.Resources.s; if(types == TetoroTypes.T) return Properties.Resources.t; if(types == TetoroTypes.Z) return Properties.Resources.z; return null; } } |
ホールドが実行されたら、現在落下中のミノをホールドします。
そしてこれまでホールドされていたものが存在しない場合は新しいミノを降らせ、存在する場合はこれまでホールドされていたミノを降らせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public partial class Form1 : Form { void Hold() { if(holdTetoro == TetoroTypes.None) { holdTetoro = tetoroTypes; ClearOldTetoro(); ShowNewTetoro(); } else { TetoroTypes oldTetoro = holdTetoro; holdTetoro = tetoroTypes; ClearOldTetoro(); ShowNewTetoro(oldTetoro); } pictureBoxHold.Image = GetImageFromTetoroType(holdTetoro); } } |
これは新しいミノを降らせるためのメソッドです。
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 |
public partial class Form1 : Form { void ShowNewTetoro(TetoroTypes tetoro) { if(tetoro == TetoroTypes.I) CreateTetoroI(); if(tetoro == TetoroTypes.O) CreateTetoroO(); if(tetoro == TetoroTypes.S) CreateTetoroS(); if(tetoro == TetoroTypes.Z) CreateTetoroZ(); if(tetoro == TetoroTypes.J) CreateTetoroJ(); if(tetoro == TetoroTypes.L) CreateTetoroL(); if(tetoro == TetoroTypes.T) CreateTetoroT(); if(FixedTetoro.Intersect(MovingTetoros).Count() != 0) { OnGameOver(); } ShowGohst(); } } |
これでよさそうなのですが、
ホールドは1回使うと設置するまで使えない
というルールがあります。そこで
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Form1 : Form { bool isAllowHold = true; void Hold() { if(!isAllowHold) return; isAllowHold = false; // 以下、変更なし } void ShowNewTetoro() { isAllowHold = true; // 以下、変更なし } } |
これでホールドを使用すると設置されるまで使用することができなくなります。
またゲーム開始時に設定を初期化する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { void GameStart() { isAllowHold = true; holdTetoro = TetoroTypes.None; pictureBoxHold.Image = null; pictureBoxHold.BackColor = ClearColor; // 以下、変更なし } } |