基于C#开发的俄罗斯方块
软设之后想着休息几天再继续其他课程的学习,于是花了点时间写了一个俄罗斯方块的小游戏(通过网上大神的版本)。俄罗斯方块的游戏主要有两个类组成。一个是方块类,用于创建不同形状的俄罗斯方块,并且提供在界面画方块的方法。还有一个就是游戏类,提供了键盘响应事件以及游戏的判定。
以下是代码:
1 方块类 2 public class Blocks 3 { 4 private const int blockWidth = 21; 5 private const int blockHeight = 21; 6 private int _width;//方块的宽,表示有多少个单元组成 7 private int _height;//方块的高 8 private int _left;//方块左边的位置 9 private int _top;//右边的位置 10 public int[,] shape;//用于存储方块,0表示无,1表示有 11 public int Top 12 { 13 get { return _top; } 14 set { _top = value; } 15 } 16 17 public int Left 18 { 19 get { return _left; } 20 set { _left = value; } 21 } 22 public int Height 23 { 24 get { return _height; } 25 set { _height = value; } 26 } 27 public int Width 28 { 29 get { return _width; } 30 set { _width = value; } 31 } 32 public Blocks() 33 { 34 getBlocks(); 35 } 36 /// <summary> 37 /// 产生一种图案的俄罗斯方块 38 /// </summary> 39 private void getBlocks() 40 { 41 Random r = new Random(); 42 int randomId= r.Next(1,9); 43 //int randomId = 1; 44 switch (randomId) 45 { 46 case 1://表示横条 47 Width = 4; 48 Height = 1; 49 Left = 3; 50 Top = 0; 51 shape = new int[Width, Height]; 52 shape[0, 0] = 1; 53 shape[1, 0] = 1; 54 shape[2, 0] = 1; 55 shape[3, 0] = 1; 56 break; 57 case 2://表示方块 58 Width = 2; 59 Height = 2; 60 Left = 4; 61 Top = 0; 62 shape = new int[Width, Height]; 63 shape[0, 0] = 1; 64 shape[0, 1] = 1; 65 shape[1, 0] = 1; 66 shape[1, 1] = 1; 67 break; 68 case 3://表示L 69 Width = 2; 70 Height = 3; 71 Left = 4; 72 Top = 0; 73 shape = new int[Width, Height]; 74 shape[0, 0] = 1; 75 shape[1, 2] = 1; 76 shape[0, 1] = 1; 77 shape[0, 2] = 1; 78 break; 79 case 4://表示L的反向 80 Width = 2; 81 Height = 3; 82 Left = 4; 83 Top = 0; 84 shape = new int[Width, Height]; 85 shape[0, 2] = 1; 86 shape[1, 0] = 1; 87 shape[1, 1] = 1; 88 shape[1, 2] = 1; 89 break; 90 case 5://表示z 91 Width = 2; 92 Height = 3; 93 Left = 4; 94 Top = 0; 95 shape = new int[Width, Height]; 96 shape[0, 1] = 1; 97 shape[1, 0] = 1; 98 shape[1, 1] = 1; 99 shape[0, 2] = 1; 100 break; 101 case 6://表示z的反向 102 Width = 2; 103 Height = 3; 104 Left = 4; 105 Top = 0; 106 shape = new int[Width, Height]; 107 shape[0, 0] = 1; 108 shape[0, 1] = 1; 109 shape[1, 1] = 1; 110 shape[1, 2] = 1; 111 break; 112 case 7://表示T 113 Width = 3; 114 Height = 2; 115 Left = 4; 116 Top = 0; 117 shape = new int[Width, Height]; 118 shape[0, 1] = 1; 119 shape[1, 0] = 1; 120 shape[2, 1] = 1; 121 shape[1, 1] = 1; 122 break; 123 case 8: 124 Width = 1; 125 Height = 1; 126 Left = 4; 127 Top = 0; 128 shape=new int[Width,Height]; 129 shape[0, 0] = 1; 130 break; 131 } 132 } 133 134 /// <summary> 135 /// 画单元方块 136 /// </summary> 137 /// <param name="g"></param> 138 public void DrawBlock(Graphics g) 139 { 140 Image backImg = Image.FromFile("image/block0.gif"); 141 for (int i = 0; i < Width; i++) 142 { 143 for (int j = 0; j < Height; j++) 144 { 145 if (shape[i, j] == 1) 146 { 147 Rectangle rectangle = new Rectangle((Left+i)*blockWidth,(Top+j)*blockHeight,blockWidth,blockHeight); 148 g.DrawImage(backImg,rectangle); 149 } 150 } 151 } 152 } 153 154 }
1 游戏类 2 public class Game 3 { 4 public const int gameWidth = 10; 5 public const int gameHeight = 20; 6 public const int blockWidth = 21; 7 public const int blockHeight = 21; 8 private Blocks currentBlock; 9 private Blocks nextBlock; 10 private int[,] gameMainPile=new int[gameWidth,gameHeight]; 11 public int score=0; 12 public bool over=false; 13 private AxWindowsMediaPlayer musicPlayer; 14 public Game(AxWindowsMediaPlayer musicPlayer) 15 { 16 ClearPile(); 17 CreateNewBlock(); 18 this.musicPlayer = musicPlayer; 19 //musicPlayer.settings.setMode("loop", true); 20 } 21 22 /// <summary> 23 /// 初始化游戏面板 24 /// </summary> 25 private void ClearPile() 26 { 27 for (int i = 0; i < gameWidth; i++) 28 { 29 for (int j = 0; j < gameHeight; j++) 30 { 31 gameMainPile[i, j] = 0; 32 } 33 } 34 } 35 36 /// <summary> 37 /// 创建一个俄罗斯方块 38 /// </summary> 39 private void CreateNewBlock() 40 { 41 if (nextBlock != null) 42 { 43 currentBlock = nextBlock; 44 } 45 else 46 { 47 currentBlock = new Blocks(); 48 } 49 nextBlock = new Blocks(); 50 } 51 52 /// <summary> 53 /// 画游戏主界面 54 /// </summary> 55 /// <param name="g"></param> 56 public void DrawPile(Graphics g) 57 { 58 Image backImg = Image.FromFile("image/block1.gif"); 59 for (int i = 0; i < gameWidth; i++) 60 { 61 for (int j = 0; j < gameHeight; j++) 62 { 63 if (gameMainPile[i, j] == 1) 64 { 65 Rectangle rectangle = new Rectangle(i*blockWidth,j*blockHeight,blockWidth,blockHeight); 66 g.DrawImage(backImg,rectangle); 67 } 68 } 69 } 70 } 71 72 /// <summary> 73 /// 画出当前方块所在位置 74 /// </summary> 75 /// <param name="g"></param> 76 public void DrawCurrentBlock(Graphics g) 77 { 78 if (currentBlock != null) 79 { 80 currentBlock.DrawBlock(g); 81 } 82 } 83 84 /// <summary> 85 /// 画出下一个俄罗斯方块 86 /// </summary> 87 /// <param name="g"></param> 88 public void DrawNextBlock(Graphics g) 89 { 90 if (nextBlock != null) 91 { 92 int tempLeft = nextBlock.Left; 93 int tempTop = nextBlock.Top; 94 nextBlock.Left = (6 - nextBlock.Width) / 2; 95 nextBlock.Top = (6 - nextBlock.Height) / 2; 96 nextBlock.DrawBlock(g); 97 nextBlock.Left = tempLeft; 98 nextBlock.Top = tempTop; 99 } 100 } 101 102 /// <summary> 103 /// 固定当前俄罗斯方块 104 /// </summary> 105 private void FixedCurrentBlock() 106 { 107 int fx, fy; 108 for (int i = 0; i < currentBlock.Width; i++) 109 { 110 for (int j = 0; j < currentBlock.Height; j++) 111 { 112 fx = currentBlock.Left + i; 113 fy = currentBlock.Top + j; 114 if (currentBlock.shape[i, j] == 1) 115 { 116 gameMainPile[fx, fy] = 1; 117 } 118 } 119 } 120 int n = CheckFullLines(); 121 if (n > 0) 122 { 123 musicPlayer.URL = "sounds/line.mp3"; 124 } 125 else 126 { 127 musicPlayer.URL = "sounds/hit.mp3"; 128 } 129 musicPlayer.Ctlcontrols.play(); 130 if (CheckOver()) 131 { 132 over = true; 133 } 134 } 135 136 /// <summary> 137 /// 判断俄罗斯方块是否到达底边 138 /// </summary> 139 /// <returns></returns> 140 public bool DownCheck() 141 { 142 bool hit = false; 143 currentBlock.Top++; 144 if ((currentBlock.Top + currentBlock.Height) > gameHeight) 145 { 146 //已经触碰到了底边 147 hit = true; 148 } 149 else 150 { 151 //检测是否触碰到已经存在的行 152 int fx, fy; 153 for (int i = 0; i < currentBlock.Width; i++) 154 { 155 for (int j = 0; j < currentBlock.Height; j++) 156 { 157 fx = currentBlock.Left + i; 158 fy = currentBlock.Top + j; 159 if ((currentBlock.shape[i, j] == 1) && (gameMainPile[fx, fy] == 1)) 160 { 161 hit = true; 162 } 163 } 164 } 165 } 166 167 if (hit) 168 { 169 currentBlock.Top--; 170 FixedCurrentBlock(); 171 CreateNewBlock(); 172 } 173 return hit; 174 } 175 176 /// <summary> 177 /// 键盘按键后响应移动俄罗斯方块 178 /// </summary> 179 /// <param name="direction"></param> 180 public void MoveBlocks(string direction) 181 { 182 bool canMove = true; 183 int fx, fy; 184 if (direction == "left") 185 { 186 //向左运动 187 if (currentBlock.Left > 0) 188 { 189 for (int i = 0; i < currentBlock.Width; i++) 190 { 191 for (int j = 0; j < currentBlock.Height; j++) 192 { 193 fx = currentBlock.Left + i; 194 fy = currentBlock.Top + j; 195 if ((currentBlock.shape[i, j] == 1) && (gameMainPile[(fx - 1), fy] == 1)) 196 { 197 canMove = false; 198 } 199 } 200 } 201 if (canMove) 202 { 203 currentBlock.Left--; 204 } 205 } 206 207 } 208 else if (direction == "right") 209 { 210 //向右运动 211 if ((currentBlock.Left + currentBlock.Width) < gameWidth) 212 { 213 for (int i = 0; i < currentBlock.Width; i++) 214 { 215 for (int j = 0; j < currentBlock.Height; j++) 216 { 217 fx = currentBlock.Left + i; 218 fy = currentBlock.Top + j; 219 if (currentBlock.shape[i, j] == 1 && gameMainPile[(fx + 1), fy] == 1) 220 { 221 canMove = false; 222 } 223 } 224 } 225 if (canMove) 226 { 227 currentBlock.Left++; 228 } 229 } 230 231 } 232 else if (direction == "up") 233 { 234 //旋转 235 RotateCurrentBlock(); 236 } 237 } 238 239 private void RotateCurrentBlock() //旋转方块 240 { 241 bool canRotate = true; 242 int newWidth = 0; 243 int newHeight = 0; 244 int[,] newShape; 245 newWidth = currentBlock.Height; 246 newHeight = currentBlock.Width; 247 newShape = new int[newWidth, newHeight]; 248 int x, y; 249 if (((currentBlock.Left + newWidth) <= gameWidth) 250 && ((currentBlock.Top + newHeight) < gameHeight)) 251 { 252 for (int i = 0; i < currentBlock.Width; i++) 253 { 254 for (int j = 0; j < currentBlock.Height; j++) 255 { 256 x = ((currentBlock.Height - 1) - j); 257 y = i; 258 newShape[x, y] = currentBlock.shape[i, j]; 259 if (newShape[x, y] == 1 && gameMainPile[x + currentBlock.Left, y + currentBlock.Top] == 1) 260 { 261 canRotate = false; 262 return; //不能旋转 263 } 264 } 265 } 266 if (canRotate) 267 { 268 currentBlock.Width = newWidth; 269 currentBlock.Height = newHeight; 270 currentBlock.shape = newShape; 271 } 272 } 273 } 274 275 /// <summary>e 276 /// 检查消除的行 277 /// </summary> 278 /// <returns></returns> 279 private int CheckFullLines() 280 { 281 int numLines = 0; 282 int[] fullLines=new int[gameHeight]; 283 for (int j = gameHeight-1; j > 0; j--) 284 { 285 bool fullLine = true; 286 for (int i = 0; i < gameWidth; i++) 287 { 288 if (gameMainPile[i, j] == 0) 289 { 290 fullLine = false; 291 break; 292 } 293 } 294 if (fullLine) 295 { 296 numLines++; 297 fullLines[numLines] = j; 298 } 299 } 300 if (numLines > 0) 301 { 302 for (int i = 1; i <= numLines; i++) 303 { 304 ClearLine(fullLines[i]+i-1); 305 } 306 score += 5 * (numLines * (numLines + 1)); 307 308 } 309 return numLines; 310 } 311 312 /// <summary> 313 /// 消除行 314 /// </summary> 315 /// <param name="lineNumber"></param> 316 private void ClearLine(int lineNumber) 317 { 318 for (int j = lineNumber; j > 0; j--) 319 { 320 for (int i = 0; i < gameWidth; i++) 321 { 322 gameMainPile[i, j] = gameMainPile[i, j - 1]; 323 } 324 } 325 for (int i = 0; i < gameWidth; i++) 326 { 327 gameMainPile[i, 0] = 0; 328 } 329 } 330 public bool CheckOver() 331 { 332 if (currentBlock.Top == 0) 333 { 334 return true; 335 } 336 else 337 { 338 return false; 339 } 340 } 341 342 343 344 345 }
1 public partial class frmMain : Form 2 { 3 4 Game game; 5 public frmMain() 6 { 7 InitializeComponent(); 8 comboBox1.SelectedIndex = 0; 9 } 10 11 private void btnStart_Click(object sender, EventArgs e) 12 { 13 game = new Game(musicPlayer); 14 pbMain.Width = Game.blockWidth * Game.gameWidth + 3; 15 pbMain.Height = Game.blockHeight * Game.gameHeight + 3; 16 pbMain.Invalidate(); 17 timer1.Enabled = true; 18 btnStart.Enabled = false; 19 } 20 21 private void pbMain_Paint(object sender, PaintEventArgs e) 22 { 23 if (game != null) 24 { 25 game.DrawPile(e.Graphics); 26 game.DrawCurrentBlock(e.Graphics); 27 } 28 } 29 30 private void pbNextBlock_Paint(object sender, PaintEventArgs e) 31 { 32 if (game != null) 33 { 34 game.DrawNextBlock(e.Graphics); 35 } 36 } 37 38 private void timer1_Tick(object sender, EventArgs e) 39 { 40 if (!game.DownCheck()) 41 { 42 pbMain.Invalidate(); 43 pbNextBlock.Invalidate(); 44 } 45 lblScore.Text = game.score.ToString(); 46 if (game.score >= 1000) 47 { 48 timer1.Enabled = false; 49 musicPlayer.URL = "sounds/level.mp3"; 50 musicPlayer.Ctlcontrols.play(); 51 MessageBox.Show("厉害厉害"); 52 btnStart.Enabled = true; 53 btnStop.Enabled = false; 54 } 55 if (game.over) 56 { 57 timer1.Enabled = false; 58 MessageBox.Show("游戏结束","提示"); 59 btnStart.Enabled = true; 60 } 61 } 62 63 private void frmMain_KeyDown(object sender, KeyEventArgs e) 64 { 65 //int key; 66 //string direction = "left"; 67 //key = e.KeyValue; 68 //if (key == 37) 69 //{ 70 // direction = "left"; 71 //} 72 //else if (key == 38) 73 //{ 74 // direction = "up"; 75 //} 76 //else if (key == 39) 77 //{ 78 // direction = "right"; 79 //} 80 //else if (key == 40) 81 //{ 82 // direction = "down"; 83 //} 84 //else 85 //{ 86 // direction = "space"; 87 //} 88 //game.MoveBlocks(direction); 89 //pbMain.Invalidate(); 90 //pbNextBlock.Invalidate(); 91 } 92 93 protected override bool ProcessCmdKey(ref Message msg, Keys e) 94 //重写ProcessCmdKey方法 95 { 96 if (btnStop.Text == "继续游戏") return true; //暂停时不响应键盘 97 if (e == Keys.Up || e == Keys.Down || e == Keys.Space || 98 e == Keys.Left || e == Keys.Right) 99 { 100 MyKeyPress(this, new KeyPressEventArgs((char)e)); 101 } 102 return true; 103 } 104 private void MyKeyPress(object sender, KeyPressEventArgs e) 105 { 106 switch (e.KeyChar) 107 { 108 case (char)Keys.Up: 109 game.MoveBlocks("up"); 110 break; 111 case (char)Keys.Down: 112 if (!game.DownCheck()) 113 pbMain.Invalidate(); //重画游戏面板区域 114 break; 115 case (char)Keys.Right: 116 game.MoveBlocks("right"); 117 break; 118 case (char)Keys.Left: 119 game.MoveBlocks("left"); 120 break; 121 case (char)Keys.Space: 122 break; 123 } 124 pbMain.Invalidate(); 125 pbNextBlock.Invalidate(); 126 } 127 128 private void btnStop_Click(object sender, EventArgs e) 129 { 130 if (btnStop.Text == "暂停游戏") 131 { 132 timer1.Enabled = false; 133 btnStop.Text="继续游戏"; 134 } 135 else if (btnStop.Text == "继续游戏") 136 { 137 timer1.Enabled = true; 138 btnStop.Text = "暂停游戏"; 139 } 140 } 141 142 private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) 143 { 144 timer1.Interval = 550 - Convert.ToInt32(comboBox1.SelectedItem)*50; 145 } 146 }
记得以前在贴吧看到过什么玩到10000分之后就会有情书弹出来。这个可以通过一个弹窗来实现。不过,对于一个分手1年多的人我就不写了。
提供可执行文件,可以自己加工后去表白: