完成品はこんな感じになります。
ぷよを消すには?
以下はぷよを下に移動させるメソッドです。これ以上下には移動できない場合、ぷよを固定させることになりますが、テトリスとちがって下になにもない空間ができてはいけません。このようなとき、赤いぷよは切り離されて下に落ちます。
ではもう一度、PuyoMoveDownIfCanメソッドをみてみましょう。
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 |
public partial class Form1 : Form { void PuyoMoveDownIfCan() { int oldX = puyoPositionX; int oldY = puyoPositionY; Position subPosition = GetSubPuyoPosition(puyoPositionX, puyoPositionY, PuyoAngle); int oldSubX = subPosition.Colum; int oldSubY = subPosition.Row; // 移動できるのか? int newX = puyoPositionX; int newY = puyoPositionY + 1; int newSubX = oldSubX; int newSubY = subPosition.Row + 1; // 下げられないなら固定する if(!CanMoveDown(new Position(newX, newY)) || !CanMoveDown(new Position(newSubX, newSubY))) { FixPuyo(oldX, oldY); FixPuyo(oldSubX, oldSubY); OnFixed(); return; } SetPuyo(oldX, oldY, Puyo.None); SetPuyo(oldSubX, oldSubY, Puyo.None); puyoPositionY = newY; SetPuyo(puyoPositionX, puyoPositionY, DropingPuyo); SetPuyo(newSubX, newSubY, SubDropingPuyo); } } |
FixPuyoメソッドとOnFixedメソッド
これ以上、2つセットになった状態で下に移動できない場合はFixPuyoメソッドとOnFixedメソッドが呼び出されます。これは以下のような処理になっています。
FixPuyoメソッドは簡単です。セルのIsFixedプロパティにtrueをセットしているだけです。これで上から落ちてきた別のぷよが当たったときに当たり判定ができるようになります。
1 2 3 4 5 6 7 |
public partial class Form1 : Form { void FixPuyo(int colum, int row) { Cells[row, colum].IsFixed = true; } } |
OnFixedメソッドのなかでおこなわれる処理は以下のようなものです。
まず、ぷよが固定されたときにプヨの下に空洞があるか調べます。そして空洞がある場合はそれをうめるように上のぷよを下に下げます。
それから4つつながっているぷよがあったら消します。ぷよが消された結果、空洞ができるかもしれません。そこでさらに空洞をうめる処理をおこないます。するとまた連鎖がおきるかもしれないので、空洞がなくなるまで処理をくりかえします。
DownPuyoIfSpacesメソッドとDownPuyoIfSpaceメソッド
DownPuyoIfSpacesメソッドは空洞をうめるための処理をくりかえすためのものです。実際にぷよの直下に空洞があるかどうか調べて、あれば上にあるぷよを下に下げる処理をおこなうのはDownPuyoIfSpaceメソッドです。処理がおこなわれたときはtrueを返すので、falseを返すまでこれを繰り返します。
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 |
public partial class Form1 : Form { async Task<bool> DownPuyoIfSpaces() { bool ret = false; // ぷよの直下に空洞がある限り、上のぷよを下に下げる while(DownPuyoIfSpace()) { ret = true; // 一気に下げるのではなく1段ずつ0.1秒ごとに下げる await Task.Delay(100); } return ret; } bool DownPuyoIfSpace() { // 一度でも処理がおこなわれた場合はtrueを返す bool ret = false; for(int y = FIELD_HEIGHT - 3; y >= 0; y--) { for(int x = 0; x < FIELD_WIDTH; x++) { if(Cells[y + 1, x].Puyo == Puyo.None && Cells[y, x].Puyo != Puyo.None) { // 下に空間があるぷよは下に落とす SetPuyo(x, y + 1, Cells[y, x].Puyo); Cells[y + 1, x].IsFixed = Cells[y, x].IsFixed; SetPuyo(x, y, Puyo.None); Cells[y, x].IsFixed = false; ret = true; } } } if(ret) Field.Invalidate(); return ret; } } |
それでは実際にぷよが固定されたときに呼び出されるOnFixedメソッドを示します。
処理中はキー操作ができないようにして、4つ以上つながっているプヨがあったら消して空洞ができたら上のぷよを移動させます。移動する必要がないぷよだけになったら処理は終了です。上から新しいぷよを降らせます。
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 |
public partial class Form1 : Form { // 処理中はキー操作を無効にする bool isIgnoreKeyDown = false; private void Field_KeyDown(object sender, KeyEventArgs e) { if(isIgnoreKeyDown) return; // 落下しているぷよの操作 // 省略 } async void OnFixed() { // 処理中はキー操作ができないようにする isIgnoreKeyDown = true; // 設置されたプヨの下に空洞があれば上のプヨを落として空洞をうめる Task<bool> task = DownPuyoIfSpaces(); await task; // 4つつながっているプヨがあったら消す for(int i = 0; i < FIELD_HEIGHT; i++) { for(int j = 0; j < FIELD_WIDTH; j++) { Cell cell = Cells[i, j]; List<Cell> cells = GetConectedCell(cell); // 後述 ClearCheck(); if(cells.Count >= 4) { foreach(Cell cell0 in cells) cell0.Puyo = Puyo.None; // プヨが消えたら空洞ができているかもしれない Task<bool> task0 = DownPuyoIfSpaces(); bool ret = await task0; if(ret) { i = 0; j = 0; } } } } isIgnoreKeyDown = false; // 処理が終わったら新しいぷよを降らせる CreateNewPuyo(); } } |
4つ以上つながっているプヨを探すために自作メソッド GetConectedCellを使用しています。再帰呼び出しをしているのですが、同じぷよを複数回数えないようにチェックをつけながら調べています。GetConectedCellメソッドが終わったらClearCheckメソッドでチェックをはずします。
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 68 69 70 |
public partial class Form1 : Form { List<Cell> GetConectedCell(Cell cell) { int colum = cell.Colum; int row = cell.Row; List<Cell> cells = new List<Cell>(); if(0 < colum && colum < FIELD_WIDTH - 1 && 0 < row && row < FIELD_HEIGHT - 1) { Puyo puyo = Cells[row, colum].Puyo; if(puyo == Puyo.None || puyo == Puyo.Wall) return cells; if(!Cells[row + 1, colum].isChecked) { Cells[row + 1, colum].isChecked = true; if(Cells[row + 1, colum].Puyo == puyo) { cells.Add(Cells[row + 1, colum]); cells.AddRange(GetConectedCell(Cells[row + 1, colum])); } } if(!Cells[row - 1, colum].isChecked) { Cells[row - 1, colum].isChecked = true; if(Cells[row - 1, colum].Puyo == puyo) { cells.Add(Cells[row - 1, colum]); cells.AddRange(GetConectedCell(Cells[row - 1, colum])); } } if(!Cells[row, colum + 1].isChecked) { Cells[row, colum + 1].isChecked = true; if(Cells[row, colum + 1].Puyo == puyo) { cells.Add(Cells[row, colum + 1]); cells.AddRange(GetConectedCell(Cells[row, colum + 1])); } } if(!Cells[row, colum - 1].isChecked) { Cells[row, colum - 1].isChecked = true; if(Cells[row, colum - 1].Puyo == puyo) { cells.Add(Cells[row, colum - 1]); cells.AddRange(GetConectedCell(Cells[row, colum - 1])); } } } return cells; } void ClearCheck() { for(int i = 0; i < FIELD_HEIGHT; i++) { for(int j = 0; j < FIELD_WIDTH; j++) { Cell cell = Cells[i, j]; cell.isChecked = false; } } } } |
エラーほとんどなくなったんですが、
すすめると2つエラーでてきました
すみませんが 下記の2つのメソッド教えてもらえませんか?
GetConectedCell(cell);
ClearCheck();
記事を修正、GetConectedCellメソッドとClearCheckメソッドを追加しました。