スーパーローテーションシステムにおける回転のルールは
にあるとおりです。そこでこれに対応できるメソッドを作成します。
まずOミノは回転しても同じ形なので考える必要はありません。Iミノは特殊なので後回しにします。S、Z、J、L、Tの回転させるメソッドを作成します。
回転させたときに各ブロックがどの座標に移動するか考えます。そして移動先の座標が移動可能な場所なのかを判断します。フィールドの外だったり、すでにブロックが存在する場合は普通の回転はできません。その場合はスーパーローテーションシステムのルールで回転軸をズラして回転できないか判断させます。(実際には回転軸をズラして回転させるのではなく、回転させたものをズラしている)
以下は回転先の座標を管理するためのクラスです。
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 { public class BlockPosition { public BlockPosition(int colum, int row) { Colum = colum; Row = row; } public int Colum { get; private set; } public int Row { get; private set; } } } |
以下は回転させたときに各ブロックがどこへ移動するか取得するためのメソッドです。ミノを作成するときに blocks[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 35 36 37 |
public partial class Form1 : Form { List<BlockPosition> GetRightRotatedPositions(List<Block> blocks) { int centerX = blocks[0].Colum; int centerY = blocks[0].Row; List<BlockPosition> blockPositions = new List<BlockPosition>(); foreach(Block block in blocks) { if(blocks[0] == block) blockPositions.Add(new BlockPosition(block.Colum, block.Row)); else if(block.Colum < centerX && block.Row < centerY) blockPositions.Add(new BlockPosition(block.Colum+2, block.Row)); else if(block.Colum == centerX && block.Row < centerY) blockPositions.Add(new BlockPosition(block.Colum + 1, block.Row+1)); else if(block.Colum > centerX && block.Row < centerY) blockPositions.Add(new BlockPosition(block.Colum, block.Row+2)); else if(block.Colum < centerX && block.Row == centerY) blockPositions.Add(new BlockPosition(block.Colum+1, block.Row-1)); else if(block.Colum == centerX && block.Row == centerY) blockPositions.Add(new BlockPosition(block.Colum, block.Row)); else if(block.Colum > centerX && block.Row == centerY) blockPositions.Add(new BlockPosition(block.Colum-1, block.Row+1)); else if(block.Colum < centerX && block.Row > centerY) blockPositions.Add(new BlockPosition(block.Colum, block.Row-2)); else if(block.Colum == centerX && block.Row > centerY) blockPositions.Add(new BlockPosition(block.Colum-1, block.Row-1)); else if(block.Colum > centerX && block.Row > centerY) blockPositions.Add(new BlockPosition(block.Colum-2, block.Row)); } return blockPositions; } } |
以下は移動先が移動可能であるかどうか調べるためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { bool CanRotate(List<BlockPosition> blockPositions) { foreach(BlockPosition pos in blockPositions) { if(pos.Colum < 0 || pos.Colum >= FIELD_INNER_WIDTH) return false; if(pos.Row < 0 || pos.Row >= FIELD_INNER_HEIGHT) return false; if(FixedTetoro.Any(x => x.Colum == pos.Colum && x.Row == pos.Row)) return false; } return true; } } |
移動可能であることがわかったら対応するオブジェクトを取得する必要があります。以下はBlockPositionのリストからブロックのオブジェクトのリストを取得するメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { List<Block> GetBlocksFromBlockPositions(List<BlockPosition> positions) { List<Block> blocks = new List<Block>(); foreach(BlockPosition pos in positions) { blocks.Add(Field[pos.Colum, pos.Row]); } return blocks; } } |
あとは上記のメソッドを利用して回転処理をおこないます。
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 71 72 73 74 75 76 |
public partial class Form1 : Form { void RotateRightTetoro() { int[] xs; int[] ys; if(tetoroAngle == TetoroAngle.Angle0) { // 回転できないときにズラす量 xs = new int[] { 0, -1, -1, 0, -1, }; ys = new int[] { 0, 1, -1, 2, 2, }; } else if(tetoroAngle == TetoroAngle.Angle90) { xs = new int[] { 0, 1, 1, 0, 1, }; ys = new int[] { 0, 0, 1, -2, -2, }; } else if(tetoroAngle == TetoroAngle.Angle180) { xs = new int[] { 0, 1, 1, 0, 1, }; ys = new int[] { 0, 0, -1, 2, 2, }; } else// if(tetoroAngle == TetoroAngle.Angle270) { xs = new int[] { 0, -1, -1, 0, 1, }; ys = new int[] { 0, 0, 1, -2, -2, }; } // 通常回転をさせるとどこに移動するのか? List<BlockPosition> newBlockPositions = GetRightRotatedPositions(MovingTetoros); List<Block> newTetoro = new List<Block>(); for(int i = 0; i < 5; i++) { // スーパーローテーションシステムを適用した場合、どこに移動するのか? List<BlockPosition> newBlockPositions1 = new List<BlockPosition>(); foreach(BlockPosition pos in newBlockPositions) newBlockPositions1.Add(new BlockPosition(pos.Colum + xs[i], pos.Row + ys[i])); // 移動可能であれば・・・ if(CanRotate(newBlockPositions1)) { newTetoro = GetBlocksFromBlockPositions(newBlockPositions1); break; } // 移動可能でない場合は回転軸をズラしてやりなおす } // スーパーローテーションシステムを適用しても回転できないのであれば終了 if(newTetoro.Count == 0) return; // 回転できるのであれば新しいの回転角を記憶させる if(tetoroAngle == TetoroAngle.Angle0) tetoroAngle = TetoroAngle.Angle90; else if(tetoroAngle == TetoroAngle.Angle90) tetoroAngle = TetoroAngle.Angle180; else if(tetoroAngle == TetoroAngle.Angle180) tetoroAngle = TetoroAngle.Angle270; else if(tetoroAngle == TetoroAngle.Angle270) tetoroAngle = TetoroAngle.Angle0; // 古いデータはクリアして新しいデータでミノを表示させる ClearOldTetoro(); foreach(Block block in newTetoro) { block.BackColor = GetTetoroColor(tetoroTypes); } MovingTetoros = newTetoro; } } |
スペースキーを押したら回転させます。
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 |
public partial class Form1 : Form { private void Form1_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Left) MoveLeftTetoro(); if(e.KeyCode == Keys.Right) MoveRightTetoro(); if(e.KeyCode == Keys.Space) RotateTetoro(); if(e.KeyCode == Keys.Down) Drop(); } void RotateTetoro() { // Oミノは回転処理の必要なし if(tetoroTypes == TetoroTypes.O) return; // Iミノは特殊 if(tetoroTypes == TetoroTypes.I) { RotateRightTetoroI(); return; } // それ以外 RotateRightTetoro(); } } |
Iミノの処理は以下のとおりです。
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 { void RotateRightTetoroI() { int[] xs; int[] ys; if(tetoroAngle == TetoroAngle.Angle0) { xs = new int[] {0, -2,1,-2,1}; ys = new int[] { 0, 0, -1, 1, -2 }; } else if(tetoroAngle == TetoroAngle.Angle90) { xs = new int[] { 0, 1, 1, 0, 1 }; ys = new int[] { 0, 0, 1, -2, -2 }; } else if(tetoroAngle == TetoroAngle.Angle180) { xs = new int[] { 0, 1, 1, 0, 1 }; ys = new int[] { 0, 0, -1, 2, 2 }; } else // tetoroAngle == TetoroAngle.Angle270 { xs = new int[] { 0, -1, -1, 0, 1 }; ys = new int[] { 0, 0, 1, -2, -2 }; } List<BlockPosition> newBlockPositions = GetIRightRotatedPositions(MovingTetoros); List<Block> newTetoro = new List<Block>(); for(int i = 0; i < 5; i++) { // スーパーローテーションシステムを適用した場合、どこに移動するのか? List<BlockPosition> newBlockPositions1 = new List<BlockPosition>(); foreach(BlockPosition pos in newBlockPositions) newBlockPositions1.Add(new BlockPosition(pos.Colum + xs[i], pos.Row + ys[i])); // 移動可能であれば・・・ if(CanRotate(newBlockPositions1)) { newTetoro = GetBlocksFromBlockPositions(newBlockPositions1); break; } // 移動可能でない場合は回転軸をズラしてやりなおす } // スーパーローテーションシステムを適用しても回転できないのであれば終了 if(newTetoro.Count == 0) return; // 回転できるのであれば新しいの回転角を記憶させる if(tetoroAngle == TetoroAngle.Angle0) tetoroAngle = TetoroAngle.Angle90; else if(tetoroAngle == TetoroAngle.Angle90) tetoroAngle = TetoroAngle.Angle180; else if(tetoroAngle == TetoroAngle.Angle180) tetoroAngle = TetoroAngle.Angle270; else if(tetoroAngle == TetoroAngle.Angle270) tetoroAngle = TetoroAngle.Angle0; ClearOldTetoro(); foreach(Block block in newTetoro) { block.BackColor = GetTetoroColor(TetoroTypes.I); } MovingTetoros = newTetoro; } } |
Iミノの回転処理時におけるブロックの移動先を取得するメソッドです。
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 |
public partial class Form1 : Form { List<BlockPosition> GetIRightRotatedPositions(List<Block> blocks) { int minColum = blocks.Min(x => x.Colum); int minRow = blocks.Min(x => x.Row); List<BlockPosition> ret = new List<BlockPosition>(); if(tetoroAngle == TetoroAngle.Angle0) { int startX = minColum + 2; int startY = minRow - 1; ret.Add(new BlockPosition(startX, startY)); ret.Add(new BlockPosition(startX, startY + 1)); ret.Add(new BlockPosition(startX, startY + 2)); ret.Add(new BlockPosition(startX, startY + 3)); } else if(tetoroAngle == TetoroAngle.Angle90) { int startX = minColum - 2; int startY = minRow + 2; ret.Add(new BlockPosition(startX, startY)); ret.Add(new BlockPosition(startX + 1, startY)); ret.Add(new BlockPosition(startX + 2, startY)); ret.Add(new BlockPosition(startX + 3, startY)); } else if(tetoroAngle == TetoroAngle.Angle180) { int startX = minColum + 1; int startY = minRow - 2; ret.Add(new BlockPosition(startX, startY)); ret.Add(new BlockPosition(startX, startY + 1)); ret.Add(new BlockPosition(startX, startY + 2)); ret.Add(new BlockPosition(startX, startY + 3)); } else if(tetoroAngle == TetoroAngle.Angle270) { int startX = minColum - 1; int startY = minRow + 1; ret.Add(new BlockPosition(startX, startY)); ret.Add(new BlockPosition(startX + 1, startY)); ret.Add(new BlockPosition(startX + 2, startY)); ret.Add(new BlockPosition(startX + 3, startY)); } return ret; } } |