Java项目--俄罗斯方块
百度盘链接
链接:http://pan.baidu.com/s/1mhQ9SYc 密码:9ujo
一、心得
二、游戏实例
游戏截图
目录结构
三、代码
1、主界面 Tetris.java
1 package com.hsj.tetris; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.Image; 7 import java.awt.event.KeyAdapter; 8 import java.awt.event.KeyEvent; 9 import java.util.Arrays; 10 import java.util.Timer; 11 import java.util.TimerTask; 12 13 import javax.imageio.ImageIO; 14 import javax.swing.JFrame; 15 import javax.swing.JPanel; 16 /** 17 * 俄罗斯方块游戏面板 18 * 19 */ 20 public class Tetris extends JPanel { 21 /** 正在下落方块 */ 22 private Tetromino tetromino; 23 /** 下一个下落方块 */ 24 private Tetromino nextOne; 25 /** 行数 */ 26 public static final int ROWS = 20; 27 /** 列数 */ 28 public static final int COLS = 10; 29 /** 墙 */ 30 private Cell[][] wall = new Cell[ROWS][COLS]; 31 /** 消掉的行数 */ 32 private int lines; 33 /** 分数 */ 34 private int score; 35 36 public static final int CELL_SIZE = 26; 37 38 private static Image background;//背景图片 39 public static Image I; 40 public static Image J; 41 public static Image L; 42 public static Image S; 43 public static Image Z; 44 public static Image O; 45 public static Image T; 46 static{//加载静态资源的,加载图片 47 //建议将图片放到 Tetris.java 同包中! 48 //从包中加载图片对象,使用Swing API实现 49 // Toolkit toolkit = Toolkit.getDefaultToolkit(); 50 // background = toolkit.getImage( 51 // Tetris.class.getResource("tetris.png")); 52 // T = toolkit.getImage(Tetris.class.getResource("T.png")); 53 // S = toolkit.getImage(Tetris.class.getResource("S.png")); 54 // Z = toolkit.getImage(Tetris.class.getResource("Z.png")); 55 // L = toolkit.getImage(Tetris.class.getResource("L.png")); 56 // J = toolkit.getImage(Tetris.class.getResource("J.png")); 57 // I = toolkit.getImage(Tetris.class.getResource("I.png")); 58 // O = toolkit.getImage(Tetris.class.getResource("O.png")); 59 //import javax.imageio.ImageIO; 60 try{ 61 background = ImageIO.read( 62 Tetris.class.getResource("tetris.png")); 63 T=ImageIO.read(Tetris.class.getResource("T.png")); 64 I=ImageIO.read(Tetris.class.getResource("I.png")); 65 S=ImageIO.read(Tetris.class.getResource("S.png")); 66 Z=ImageIO.read(Tetris.class.getResource("Z.png")); 67 L=ImageIO.read(Tetris.class.getResource("L.png")); 68 J=ImageIO.read(Tetris.class.getResource("J.png")); 69 O=ImageIO.read(Tetris.class.getResource("O.png")); 70 }catch(Exception e){ 71 e.printStackTrace(); 72 } 73 } 74 75 public void action(){ 76 //tetromino = Tetromino.randomTetromino(); 77 //nextOne = Tetromino.randomTetromino(); 78 //wall[19][2] = new Cell(19,2,Tetris.T); 79 startAction(); 80 repaint(); 81 KeyAdapter l = new KeyAdapter() { 82 public void keyPressed(KeyEvent e) { 83 int key = e.getKeyCode(); 84 if(key == KeyEvent.VK_Q){ 85 System.exit(0);//退出当前的Java进程 86 } 87 if(gameOver){ 88 if(key==KeyEvent.VK_S){ 89 startAction(); 90 } 91 return; 92 } 93 //如果暂停并且按键是[C]就继续动作 94 if(pause){//pause = false 95 if(key==KeyEvent.VK_C){ continueAction(); } 96 return; 97 } 98 //否则处理其它按键 99 switch(key){ 100 case KeyEvent.VK_RIGHT: moveRightAction(); break; 101 case KeyEvent.VK_LEFT: moveLeftAction(); break; 102 case KeyEvent.VK_DOWN: softDropAction() ; break; 103 case KeyEvent.VK_UP: rotateRightAction() ; break; 104 case KeyEvent.VK_Z: rotateLeftAction() ; break; 105 case KeyEvent.VK_SPACE: hardDropAction() ; break; 106 case KeyEvent.VK_P: pauseAction() ; break; 107 } 108 repaint(); 109 } 110 }; 111 this.requestFocus(); 112 this.addKeyListener(l); 113 } 114 115 public void paint(Graphics g){ 116 g.drawImage(background, 0, 0, null);//使用this 作为观察者 117 g.translate(15, 15);//平移绘图坐标系 118 paintTetromino(g);//绘制正在下落的方块 119 paintWall(g);//画墙 120 paintNextOne(g); 121 paintScore(g); 122 } 123 public static final int FONT_COLOR = 0x667799; 124 public static final int FONT_SIZE = 0x20; 125 private void paintScore(Graphics g) { 126 Font f = getFont();//获取当前的 面板默认字体 127 Font font = new Font( 128 f.getName(), Font.BOLD, FONT_SIZE); 129 int x = 290; 130 int y = 162; 131 g.setColor(new Color(FONT_COLOR)); 132 g.setFont(font); 133 String str = "SCORE:"+this.score; 134 g.drawString(str, x, y); 135 y+=56; 136 str = "LINES:"+this.lines; 137 g.drawString(str, x, y); 138 y+=56; 139 str = "[P]Pause"; 140 if(pause){str = "[C]Continue";} 141 if(gameOver){ str = "[S]Start!";} 142 g.drawString(str, x, y); 143 } 144 145 private void paintNextOne(Graphics g) { 146 Cell[] cells = nextOne.getCells(); 147 for(int i=0; i<cells.length; i++){ 148 Cell c = cells[i]; 149 int x = (c.getCol()+10) * CELL_SIZE-1; 150 int y = (c.getRow()+1) * CELL_SIZE-1; 151 g.drawImage(c.getImage(), x, y, null); 152 } 153 } 154 155 private void paintTetromino(Graphics g) { 156 Cell[] cells = tetromino.getCells(); 157 for(int i=0; i<cells.length; i++){ 158 Cell c = cells[i]; 159 int x = c.getCol() * CELL_SIZE-1; 160 int y = c.getRow() * CELL_SIZE-1; 161 //g.setColor(new Color(c.getColor())); 162 //g.fillRect(x, y, CELL_SIZE, CELL_SIZE); 163 g.drawImage(c.getImage(), x, y, null); 164 } 165 } 166 167 //在 Tetris 类 中添加 方法 paintWall 168 private void paintWall(Graphics g){ 169 for(int row=0; row<wall.length; row++){ 170 //迭代每一行, i = 0 1 2 ... 19 171 Cell[] line = wall[row]; 172 //line.length = 10 173 for(int col=0; col<line.length; col++){ 174 Cell cell = line[col]; 175 int x = col*CELL_SIZE; 176 int y = row*CELL_SIZE; 177 if(cell==null){ 178 //g.setColor(new Color(0)); 179 //画方形 180 //g.drawRect(x, y, CELL_SIZE, CELL_SIZE); 181 }else{ 182 g.drawImage(cell.getImage(), x-1, y-1, null); 183 } 184 } 185 } 186 } 187 /** 188 * 在 Tetris(俄罗斯方块) 类中增加方法 189 * 这个方法的功能是:软下落的动作 控制流程 190 * 完成功能:如果能够下落就下落,否则就着陆到墙上, 191 * 而新的方块出现并开始落下。 192 */ 193 public void softDropAction(){ 194 if(tetrominoCanDrop()){ 195 tetromino.softDrop(); 196 }else{ 197 tetrominoLandToWall(); 198 destroyLines();//破坏满的行 199 checkGameOver(); 200 tetromino = nextOne; 201 nextOne = Tetromino.randomTetromino(); 202 } 203 } 204 /** 销毁已经满的行,并且计分 205 * 1)迭代每一行 206 * 2)如果(检查)某行满是格子了 就销毁这行 207 **/ 208 public void destroyLines(){ 209 int lines = 0; 210 for(int row = 0; row<wall.length; row++){ 211 if(fullCells(row)){ 212 deleteRow(row); 213 lines++; 214 } 215 } 216 // lines = ? 217 this.lines += lines;//0 1 2 3 4 218 this.score += SCORE_TABLE[lines]; 219 } 220 private static final int[] SCORE_TABLE={0,1,10,30,200}; 221 // 0 1 2 3 4 222 223 public boolean fullCells(int row){ 224 Cell[] line = wall[row]; 225 for(int i=0; i<line.length; i++){ 226 if(line[i]==null){//如果有空格式就不是满行 227 return false; 228 } 229 } 230 return true; 231 } 232 public void deleteRow(int row){ 233 for(int i=row; i>=1; i--){ 234 //复制 [i-1] -> [i] 235 System.arraycopy(wall[i-1], 0, wall[i], 0, COLS); 236 } 237 Arrays.fill(wall[0], null); 238 } 239 240 /** 检查当前的4格方块能否继续下落 */ 241 public boolean tetrominoCanDrop(){ 242 Cell[] cells = tetromino.getCells(); 243 for(int i = 0; i<cells.length; i++){ 244 Cell cell = cells[i]; 245 int row = cell.getRow(); int col = cell.getCol(); 246 if(row == ROWS-1){return false;}//到底就不能下降了 247 } 248 for(int i = 0; i<cells.length; i++){ 249 Cell cell = cells[i]; 250 int row = cell.getRow(); int col = cell.getCol(); 251 if(wall[row+1][col] != null){ 252 return false;//下方墙上有方块就不能下降了 253 } 254 } 255 return true; 256 } 257 /** 4格方块着陆到墙上 */ 258 public void tetrominoLandToWall(){ 259 Cell[] cells = tetromino.getCells(); 260 for(int i=0; i<cells.length; i++){ 261 Cell cell = cells[i]; 262 int row = cell.getRow(); 263 int col = cell.getCol(); 264 wall[row][col] = cell; 265 } 266 } 267 268 public void moveRightAction(){ 269 tetromino.moveRight(); 270 if(outOfBound() || coincide()){ 271 tetromino.moveLeft(); 272 } 273 } 274 public void moveLeftAction(){ 275 tetromino.moveLeft(); 276 if(outOfBound() || coincide()){ 277 tetromino.moveRight(); 278 } 279 } 280 /** ... */ 281 private boolean outOfBound(){ 282 Cell[] cells = tetromino.getCells(); 283 for(int i=0; i<cells.length; i++){ 284 Cell cell = cells[i]; 285 int col = cell.getCol(); 286 if(col<0 || col>=COLS){ 287 return true;//出界了 288 } 289 } 290 return false; 291 } 292 private boolean coincide(){ 293 Cell[] cells = tetromino.getCells(); 294 //for each 循环、迭代,简化了"数组迭代书写" 295 for(Cell cell: cells){//Java 5 以后提供增强版for循环 296 int row = cell.getRow(); 297 int col = cell.getCol(); 298 if(row<0 || row>=ROWS || col<0 || col>=COLS || 299 wall[row][col]!=null){ 300 return true; //墙上有格子对象,发生重合 301 } 302 } 303 return false; 304 } 305 /** 向右旋转动作 */ 306 public void rotateRightAction(){ 307 //旋转之前 308 //System.out.println(tetromino); 309 tetromino.rotateRight(); 310 //System.out.println(tetromino); 311 //旋转之后 312 if(outOfBound() || coincide()){ 313 tetromino.rotateLeft(); 314 } 315 } 316 317 /** Tetris 类中添加的方法 */ 318 public void rotateLeftAction(){ 319 tetromino.rotateLeft(); 320 if(outOfBound() || coincide()){ 321 tetromino.rotateRight(); 322 } 323 } 324 public void hardDropAction(){ 325 while(tetrominoCanDrop()){ 326 tetromino.softDrop(); 327 } 328 tetrominoLandToWall(); 329 destroyLines(); 330 checkGameOver(); 331 tetromino = nextOne; 332 nextOne = Tetromino.randomTetromino(); 333 } 334 335 private boolean pause; 336 private boolean gameOver; 337 private Timer timer; 338 /** Tetris 类中添加的方法, 用于启动游戏 */ 339 public void startAction(){ 340 clearWall(); 341 tetromino = Tetromino.randomTetromino(); 342 nextOne = Tetromino.randomTetromino(); 343 lines = 0; score = 0; pause=false; gameOver=false; 344 timer = new Timer(); 345 timer.schedule(new TimerTask(){ 346 public void run() { 347 softDropAction(); 348 repaint(); 349 } 350 }, 700, 700); 351 } 352 353 private void clearWall(){ 354 //将墙的每一行的每个格子清理为null 355 for(int row=0; row<ROWS; row++){ 356 Arrays.fill(wall[row], null); 357 } 358 } 359 360 /** 在Tetris 类中添加方法 */ 361 public void pauseAction(){ 362 timer.cancel(); //停止定时器 363 pause = true; 364 repaint(); 365 } 366 public void continueAction(){ 367 timer = new Timer(); 368 timer.schedule(new TimerTask() { 369 public void run() { 370 softDropAction(); 371 repaint(); 372 } 373 }, 700, 700); 374 pause = false; 375 repaint(); 376 } 377 /** 在 Tetris 类中添加 方法 */ 378 public void checkGameOver(){ 379 if(wall[0][4]==null){ 380 return; 381 } 382 gameOver = true; 383 timer.cancel(); 384 repaint(); 385 } 386 387 public static void main(String[] args) { 388 JFrame frame = new JFrame(); 389 Tetris tetris = new Tetris(); 390 frame.add(tetris); 391 frame.setSize(525, 550); 392 frame.setUndecorated(false);//true去掉窗口框! 393 frame.setTitle("俄罗斯方块"); 394 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 395 //Location 位置 RelativeTo相对于 396 frame.setLocationRelativeTo(null);//使当前窗口居中 397 frame.setVisible(true); 398 tetris.action(); 399 } 400 }
二、Cell.java
1 package com.fry.tetris; 2 3 import java.awt.Image; 4 5 /** 6 * 格子 7 * 每一个小格子,就有所在的行 列 和图片 8 */ 9 public class Cell { 10 private int row; 11 private int col; 12 //private int color; 13 private Image image;//格子的贴图 14 15 public Cell() { 16 } 17 18 public Cell(int row, int col, Image image) { 19 super(); 20 this.row = row; 21 this.col = col; 22 this.image = image; 23 } 24 25 public int getRow() { 26 return row; 27 } 28 29 public void setRow(int row) { 30 this.row = row; 31 } 32 33 public int getCol() { 34 return col; 35 } 36 37 public void setCol(int col) { 38 this.col = col; 39 } 40 41 42 public Image getImage() { 43 return image; 44 } 45 46 public void setImage(Image image) { 47 this.image = image; 48 } 49 50 public void moveRight(){ 51 col++; 52 //System.out.println("Cell moveRight()" + col); 53 } 54 55 public void moveLeft(){ 56 col--; 57 } 58 59 public void moveDown(){ 60 row++; 61 } 62 63 @Override 64 public String toString() { 65 return "["+row+","+col+"]"; 66 } 67 }
三、功能实现 Tetromino.java
package com.fry.tetris; import java.util.Arrays; import java.util.Random; /** * 4格方块 */ public class Tetromino { protected Cell[] cells = new Cell[4]; /** 保存旋转的相对于轴位置状态 */ protected State[] states; /** 随机生成 4格方块, 使用简单工厂方法模式! * randomTetromino 随机生成一个四格方块 * 这个方面的返回值是多态的! * */ public static Tetromino randomTetromino(){ Random r = new Random(); int type = r.nextInt(7); switch(type){ case 0: return new T(); case 1: return new I(); case 2: return new J(); case 3: return new L(); case 4: return new O(); case 5: return new S(); case 6: return new Z(); } return null; } public Cell[] getCells() { return cells; } /** 下落 */ public void softDrop(){ for(int i=0; i<cells.length; i++){ cells[i].moveDown(); } } public void moveRight(){ //System.out.println("moveRight()"); for(int i=0; i<cells.length; i++){ this.cells[i].moveRight(); } } public void moveLeft(){ for(int i=0; i<cells.length; i++){ cells[i].moveLeft(); } } private int index = 100000; /** 在 Tetromino 上添加方法 */ public void rotateRight() { index++;//index = 10001 // index % states.length = 10001 % 4 = 1 State s = states[index%states.length];//s1 // [0] + s1 = [1] Cell o = cells[0];//获取当前的轴 //轴与相对位置的和作为旋转以后的格子位置 cells[1].setRow(o.getRow()+s.row1); cells[1].setCol(o.getCol()+s.col1); cells[2].setRow(o.getRow()+s.row2); cells[2].setCol(o.getCol()+s.col2); cells[3].setRow(o.getRow()+s.row3); cells[3].setCol(o.getCol()+s.col3); } /** 在 Tetromino 上添加方法 */ public void rotateLeft() { index--;//index = 10001 // index % states.length = 10001 % 4 = 1 State s = states[index%states.length];//s1 // [0] + s1 = [1] Cell o = cells[0];//获取当前的轴 cells[1].setRow(o.getRow()+s.row1); cells[1].setCol(o.getCol()+s.col1); cells[2].setRow(o.getRow()+s.row2); cells[2].setCol(o.getCol()+s.col2); cells[3].setRow(o.getRow()+s.row3); cells[3].setCol(o.getCol()+s.col3); } @Override public String toString() { return Arrays.toString(cells); } /** Tetromino 类中添加的 内部类 用于记录旋转状态 */ protected class State{ int row0,col0,row1,col1,row2,col2,row3,col3; public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) { this.row0 = row0; this.col0 = col0; this.row1 = row1; this.col1 = col1; this.row2 = row2; this.col2 = col2; this.row3 = row3; this.col3 = col3; } } }//Tetromino 类的结束 class T extends Tetromino{ public T() { cells[0] = new Cell(0, 4, Tetris.T); cells[1] = new Cell(0, 3, Tetris.T); cells[2] = new Cell(0, 5, Tetris.T); cells[3] = new Cell(1, 4, Tetris.T); states = new State[]{ new State(0,0, 0,-1, 0,1, 1, 0), new State(0,0, -1,0, 1,0, 0,-1), new State(0,0, 0,1, 0,-1, -1,0), new State(0,0, 1,0, -1,0, 0,1)}; } } class I extends Tetromino{ public I() { cells[0] = new Cell(0, 4, Tetris.I); cells[1] = new Cell(0, 3, Tetris.I); cells[2] = new Cell(0, 5, Tetris.I); cells[3] = new Cell(0, 6, Tetris.I); states = new State[]{ new State(0,0, 0,1, 0,-1, 0,-2), new State(0,0, -1,0, 1,0,2,0)}; } } class L extends Tetromino { public L() { cells[0] = new Cell(0, 4, Tetris.L); cells[1] = new Cell(0, 3, Tetris.L); cells[2] = new Cell(0, 5, Tetris.L); cells[3] = new Cell(1, 3, Tetris.L); states = new State[]{ new State(0,0, 0,-1, 0,1, 1,-1 ), new State(0,0, -1,0, 1,0, -1,-1), new State(0,0, 0,1, 0,-1, -1,1), new State(0,0, 1,0, -1,0, 1,1)}; } } class J extends Tetromino { public J() { cells[0] = new Cell(0, 4, Tetris.J); cells[1] = new Cell(0, 3, Tetris.J); cells[2] = new Cell(0, 5, Tetris.J); cells[3] = new Cell(1, 5, Tetris.J); states = new State[]{ new State(0,0, 0,-1, 0,1, 1,1), new State(0,0, -1,0, 1,0, 1,-1), new State(0,0, 0,1, 0,-1, -1,-1), new State(0,0, 1,0, -1,0, -1,1 )}; } } class S extends Tetromino { public S() { cells[0] = new Cell(0, 4, Tetris.S); cells[1] = new Cell(0, 5, Tetris.S); cells[2] = new Cell(1, 3, Tetris.S); cells[3] = new Cell(1, 4, Tetris.S); states = new State[]{ new State(0,0, 0,1, 1,-1, 1,0 ), new State(0,0, -1,0, 1,1, 0,1 )}; } } class Z extends Tetromino { public Z() { cells[0] = new Cell(1, 4, Tetris.Z); cells[1] = new Cell(0, 3, Tetris.Z); cells[2] = new Cell(0, 4, Tetris.Z); cells[3] = new Cell(1, 5, Tetris.Z); states = new State[]{ new State(0,0, -1,-1, -1,0, 0,1 ), new State(0,0, -1,1, 0,1, 1,0 )}; } } class O extends Tetromino { public O() { cells[0] = new Cell(0, 4, Tetris.O); cells[1] = new Cell(0, 5, Tetris.O); cells[2] = new Cell(1, 4, Tetris.O); cells[3] = new Cell(1, 5, Tetris.O); states = new State[]{ new State(0,0, 0,1, 1,0, 1,1 ), new State(0,0, 0,1, 1,0, 1,1 )}; } }