テトリミノを移動させます。左右の矢印キーをおすと左右に移動するようになります。
移動するときは本当に移動できるのかを調べる必要があります。移動したらフィールドの外にはみ出してしまう場合や他のテトリミノの存在する場所に移動することはできません。
落下中のテトリミノを構成するブロックがどの位置にあるかはフィールド変数のMovingTetorosに保存されています。そこでLINQのSelectメソッドをつかって移動後の位置を取得して、これとFixedTetoroとの積集合を調べてそのような要素があるかを調べることにします。
まず左に移動する場合。MovingTetorosのX座標の最小値をしらべて0があれば、これ以上左に移動させることはできないことがわかります。
移動後にMovingTetorosに格納されるデータはLINQのSelectメソッドを使えば取得できます。これをいったんnewPosという変数に格納します。newPosとFixedTetoroの積集合の要素数が0でない場合はそこには移動できません。
問題なく移動できるのであれば移動させます。まずMovingTetorosに格納されていたデータをもとに現在表示されているテトリミノをいったん消去します。この処理をするのが自作メソッド ClearOldTetoroです。
落下中のテトリミノを消去したら、newPosの情報をもとに新しい位置にテトリミノを描画します。そしてMovingTetorosの内容をnewPosの内容にいれかえます。
移動できない場合はなにもしないで returnします。
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 |
public partial class Form1 : Form { void MoveLeftTetoro() { if(MovingTetoros.Min(x => x.Colum) <= 0) return; var newPos = MovingTetoros.Select(x => Field[x.Colum-1, x.Row]).ToList(); if(newPos.Intersect(FixedTetoro).Count() != 0) return; MovingTetoroPos = new Point(MovingTetoroPos.X - 1, MovingTetoroPos.Y); Color tetoroColor = MovingTetoros[0].BackColor; ClearOldTetoro(); MovingTetoros = newPos; foreach(Block block in newPos) block.BackColor = tetoroColor; } void ClearOldTetoro() { foreach(Block block in MovingTetoros) block.BackColor = Color.White; MovingTetoros.Clear(); } } |
同様にして右に移動させるメソッドと下に移動させるメソッドを作成します。
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 MoveRightTetoro() { if(MovingTetoros.Max(x => x.Colum) >= FIELD_INNER_WIDTH - 1) return; var newPos = MovingTetoros.Select(x => Field[x.Colum + 1, x.Row]).ToList(); if(newPos.Intersect(FixedTetoro).Count() != 0) return; MovingTetoroPos = new Point(MovingTetoroPos.X+1, MovingTetoroPos.Y); Color tetoroColor = MovingTetoros[0].BackColor; ClearOldTetoro(); MovingTetoros = newPos; foreach(Block block in newPos) block.BackColor = tetoroColor; } } |
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 |
public partial class Form1 : Form { void MoveDownTetoro() { if(MovingTetoros.Max(x => x.Row) >= FIELD_INNER_HEIGHT - 1) { // テトリミノが着地した場合、 // 次のテトリミノを出現させる // 同じ段がすべてブロックで埋め尽くされているか確認する必要がある // これに関する処理をするTetoroDownedメソッドにいては後述 TetoroDowned(); return; } var newPos = MovingTetoros.Select(x => Field[x.Colum, x.Row + 1]).ToList(); if(newPos.Intersect(FixedTetoro).Count() != 0) { TetoroDowned(); return; } MovingTetoroPos = new Point(MovingTetoroPos.X, MovingTetoroPos.Y+1); Color tetoroColor = MovingTetoros[0].BackColor; ClearOldTetoro(); MovingTetoros = newPos; foreach(Block block in newPos) block.BackColor = tetoroColor; } } |
テトリミノを回転させる
スペースキーがおされたらテトリミノを時計方向に回転させます。回転させるためには
ブロックの元の座標と新しい座標の関係は以下のようになります。
1 2 |
newX = TETORO_SIZE-1- oldY newY = oldX |
しかしこれはテトリミノの左上の座標が(0,0)だった場合の話です。実際にはテトリミノは左右や下に移動しているので、この公式をそのまま使うことはできません。
いったんテトリミノの左上の座標を(0,0)に移動させたことにして、そこで上記公式で回転の処理をして、最後にもとの位置に戻しています。
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 RotateTetoro() { int oldX = MovingTetoroPos.X; int oldY = MovingTetoroPos.Y; var newPos = MovingTetoros .Select(x => Field[x.Colum - oldX, x.Row - oldY]) .Select(x => Field[TETORO_SIZE - 1 - x.Row, x.Colum]) .Select(x => { if(x.Colum + oldX < 0 || x.Colum + oldX >= FIELD_INNER_WIDTH) return null; if(x.Row + oldY < 0 || x.Row + oldY >= FIELD_INNER_HEIGHT) return null; return Field[x.Colum + oldX, x.Row + oldY]; }).ToList(); if(newPos.Any(x => x == null)) return; if(newPos.Intersect(FixedTetoro).Count() != 0) return; Color tetoroColor = MovingTetoros[0].BackColor; ClearOldTetoro(); foreach(Block block in newPos) { block.BackColor = tetoroColor; } MovingTetoros = newPos; } } |