1 packagecom.ftl.tetris;2
3 importjava.awt.Color;4 importjava.awt.Font;5 importjava.awt.Graphics;6 importjava.awt.event.KeyAdapter;7 importjava.awt.event.KeyEvent;8 importjava.awt.image.BufferedImage;9 importjava.io.IOException;10 importjava.util.Arrays;11 importjava.util.Timer;12 importjava.util.TimerTask;13
14 importjavax.imageio.ImageIO;15 importjavax.swing.JFrame;16 importjavax.swing.JPanel;17
18 /**
19 * 俄罗斯方块20 *21 *@authorFTL101222 *23 */
24 public class Tetris extendsJPanel {25 private int score; //分数
26 private int lines; //行数
27 private Cell[][] walls; //定义背景
28 private Tetromino tetromino; //正在下降的格子
29 private Tetromino nextOne; //下一个下降的格子
30
31 public static final int ROWS = 20; //背景墙的行数
32 public static final int COLS = 10; //背景墙的列数
33 private static final int CELL_SIZE = 26; //间距
34 private static final int FONT_COLOR= 0x667799; //字体颜色
35 private static final int FONT_SIZE = 30;36
37 private Timer timer; //定时调度
38 private intspeed;39 private intlevel;40 private intindex;41
42 //游戏运行状态
43 private intstate;44 private static final int RUNNING = 0;45 private static final int PAUSE = 1;46 private static final int GAME_OVER = 2;47
48
49
50 /**
51 * 背景图片52 *53 *@paramargs54 */
55 private staticBufferedImage background;56 public staticBufferedImage T;57 public staticBufferedImage S;58 public staticBufferedImage I;59 public staticBufferedImage L;60 public staticBufferedImage J;61 public staticBufferedImage O;62 public staticBufferedImage Z;63 public staticBufferedImage gameOver;64 public staticBufferedImage pause;65
66
67 /**
68 * 静态代码块加载图片69 */
70 static{71 try{72 background = ImageIO.read(Tetris.class.getResource("tetris.png"));73 gameOver = ImageIO.read(Tetris.class.getResource("gameover.png"));74 pause = ImageIO.read(Tetris.class.getResource("pause.png"));75 T = ImageIO.read(Tetris.class.getResource("T.png"));76 I = ImageIO.read(Tetris.class.getResource("I.png"));77 L = ImageIO.read(Tetris.class.getResource("L.png"));78 O = ImageIO.read(Tetris.class.getResource("O.png"));79 S = ImageIO.read(Tetris.class.getResource("S.png"));80 J = ImageIO.read(Tetris.class.getResource("J.png"));81 Z = ImageIO.read(Tetris.class.getResource("Z.png"));82 } catch(IOException e) {83 //TODO 自动生成的 catch 块
84 e.printStackTrace();85 }86 }87
88
89
90 /**
91 * 画背景,画墙,画正在下落的方块,画下一个方块92 */
93 @Override94 public voidpaint(Graphics g) {95 //TODO 自动生成的方法存根
96 g.drawImage(background, 0, 0, null);97 g.translate(15, 15); //坐标系平移15个像素98
99 //打印背景
100 paintWall(g);101 //打印下落的方块
102 paintTetromino(g);103 //打印即将下落的方块
104 paintNextmino(g);105 //绘制分数
106 paintScore(g);107 //绘制游戏状态
108 paintState(g);109 }110
111 /**
112 * 绘制游戏状态113 */
114 private voidpaintState(Graphics g) {115 switch(state) {116 casePAUSE:117 g.drawImage(pause, -15, -15, null);118 break;119 caseGAME_OVER:120 g.drawImage(gameOver, -15, -15, null);121 break;122 }123 }124
125
126 /**
127 * 绘制分数128 *@paramg129 */
130 private voidpaintScore(Graphics g) {131 int x = 290;132 int y = 160;133 g.setColor(newColor(FONT_COLOR));134 Font font =g.getFont();135 font = newFont(font.getName(),font.getStyle(),FONT_SIZE);136 g.setFont(font);137 String str = null;138 str = "SCORE:" +score;139 g.drawString(str, x, y);140 y += 56;141 str = "LINES:" +lines;142 g.drawString(str, x, y);143 y += 56;144 str = "LEVEL:" +level;145 g.drawString(str, x, y);146 }147
148
149 /**
150 * 启动Action方法,初始化数组Walls,151 *@paramargs152 */
153 public voidaction()154 {155 walls = newCell[ROWS][COLS];156 walls[2][2] = new Cell(2,2,T); //将强的第二行第二列设置为T方块的一个格子(2,2)
157 tetromino = Tetromino.getOne(); //正在下落的方块
158 nextOne = Tetromino.getOne(); //下一个即将下落的方块
159
160 this.state =RUNNING;161 //增加键盘监听控制
162 KeyAdapter l = newKeyAdapter() {163
164 @Override165 public voidkeyPressed(KeyEvent e) {166 //TODO 自动生成的方法存根167 //int key = e.getKeyCode();168 //switch (key) {169 //case KeyEvent.VK_DOWN:170 //softDorpAction();171 //break;172 //case KeyEvent.VK_RIGHT:173 //moveRightAction();174 //break;175 //case KeyEvent.VK_LEFT:176 //moveLeftAction();177 //break;178 //case KeyEvent.VK_SPACE:179 //hardDropAction();180 //break;181 //case KeyEvent.VK_UP:182 //rotateRightAction();183 //break;184 //}
185 int key =e.getKeyCode();186 switch(state) {187 caseGAME_OVER:188 processGameOverKey(key);189 break;190 casePAUSE:191 processPauseKey(key);192 break;193 caseRUNNING:194 processRunningKey(key);195 break;196 }197 repaint();198 }199 };200 //点击按钮的时候,按钮获得焦点,对应处理一些逻辑
201 this.requestFocus();202 this.addKeyListener(l);203
204 //定时方法
205 this.timer = newTimer();206 this.timer.schedule(newTimerTask() {207 public voidrun() {208 speed = 40 - (lines / 2);209 speed = speed < 1 ? 1: speed;210 level = 41 -speed;211 if(state == RUNNING && index % speed == 0){212 softDorpAction();213 }214 index++;215 repaint();216 }217 }, 10, 13);218 }219
220 /**
221 * 运行按钮222 *@paramkey223 */
224 private void processRunningKey(intkey) {225 switch(key) {226 caseKeyEvent.VK_Q:227 System.exit(0);228 break;229 caseKeyEvent.VK_DOWN:230 softDorpAction();231 break;232 caseKeyEvent.VK_RIGHT:233 moveRightAction();234 break;235 caseKeyEvent.VK_LEFT:236 moveLeftAction();237 break;238 caseKeyEvent.VK_SPACE:239 hardDropAction();240 break;241 caseKeyEvent.VK_UP:242 rotateRightAction();243 break;244 caseKeyEvent.VK_P:245 this.state =PAUSE;246 break;247 }248
249 }250
251 /**
252 * 停止按钮253 *@paramkey254 */
255 private void processPauseKey(intkey) {256 switch(key) {257 caseKeyEvent.VK_Q:258 System.exit(0);259 break;260 caseKeyEvent.VK_C:261 index = 0;262 this.state =RUNNING;263 break;264 }265
266 }267
268 /**
269 * 游戏结束,重新开始270 *@paramkey271 */
272 private void processGameOverKey(intkey) {273 switch(key) {274 caseKeyEvent.VK_Q:275 System.exit(0); //退出游戏
276 break;277 caseKeyEvent.VK_S:278 this.lines = 0;279 this.score = 0;280 this.walls = newCell[ROWS][COLS];281 this.tetromino =Tetromino.getOne();282 this.nextOne =Tetromino.getOne();283 this.state =RUNNING;284 //this.index = 0;
285 break;286 }287 }288
289
290 /**
291 * 绘制正在下落的方块292 *@paramargs293 */
294 public voidpaintTetromino(Graphics g)295 {296 if(tetromino == null)297 {298 return; //结束方法
299 }300 //将每个格子的row 和 col转换为x,y,然后贴图
301 Cell[] cells =tetromino.cells;302 for(int i = 0; i < cells.length; i++)303 {304 //cell 为每一个盒子
305 Cell cell =cells[i];306 int x = cell.getCol() *CELL_SIZE;307 int y = cell.getRow() *CELL_SIZE;308 g.drawImage(cell.getImage(), x-1, y-1, null);309 }310 }311
312 /**
313 * 画下一个即将下落的方块314 */
315 public voidpaintNextmino(Graphics g)316 {317 if(nextOne == null)318 {319 return; //结束方法
320 }321 //将每个格子的row 和 col转换为x,y,然后贴图
322 Cell[] cells =nextOne.cells;323 for(int i = 0; i < cells.length; i++)324 {325 //cell 为每一个盒子
326 Cell cell =cells[i];327 int x = (cell.getCol() + 10)*CELL_SIZE;328 int y = (cell.getRow() + 1) *CELL_SIZE;329 g.drawImage(cell.getImage(), x-1, y-1, null);330 }331 }332
333
334 /**
335 * 画墙336 *337 *@paramargs338 */
339 private voidpaintWall(Graphics g) {340 //TODO 自动生成的方法存根
341 for (int row = 0; row < walls.length; row++) {342 //line表示墙上的每一行
343 Cell[] line =walls[row];344 for (int col = 0; col < line.length; col++) {345 //cell表示墙上的每一个格子
346 Cell cell =line[col];347 int x = col *CELL_SIZE;348 int y = row *CELL_SIZE;349 //如果cell为空,则表示没有格子
350 if(cell == null){351 g.drawRect(x, y, CELL_SIZE, CELL_SIZE);352 }353 //如果不为空,表示有格子,显示各自,x-1,y-1为了不让重叠,为了美观
354 else
355 {356 g.drawImage(cell.getImage(), x-1, y-1, null);357 }358 //g.drawString(row+"," + col,x,y+CELL_SIZE);
359 }360
361 }362 }363
364 /**
365 * 判断是否出界366 */
367 private booleanoutOfBounds(){368 Cell[] cells =tetromino.cells;369 for(int i = 0; i < cells.length; i++)370 {371 Cell cell =cells[i];372 int col =cell.getCol();373 if(col < 0 || col >=COLS )374 {375 return true;376 }377 }378 return false;379 }380
381 /**
382 * 判断是否重合383 */
384 private booleancoinclude() {385 Cell[] cells =tetromino.cells;386 for (int i = 0; i < cells.length; i++) {387 Cell cell =cells[i];388 int row =cell.getRow();389 int col =cell.getCol();390 if (row >= 0 && row < ROWS && col >= 0 && col <=COLS391 && walls[row][col] != null) {392 return true; //重合
393 }394 }395 return false;396 }397
398 /**
399 * 判断右边是否出界400 *@paramargs401 */
402 public voidmoveRightAction(){403 tetromino.moveRight();404 if(this.outOfBounds() || this.coinclude())405 {406 tetromino.moveLeft();407 }408 }409
410 /**
411 * 判断左边是否出界412 *@paramargs413 */
414 public voidmoveLeftAction(){415 tetromino.moveLeft();416 if(this.outOfBounds() || this.coinclude())417 {418 tetromino.moveRight();419 }420 }421
422 /**
423 * 判断游戏是否结束:424 *425 */
426
427 private booleanisGameOver(){428 //如果下一个放开没有出场位置,游戏结束429 //就是: 下一个出场方块每个ge子都有对于的墙上如果有格子
430 Cell[] cells =nextOne.cells;431 for(Cell cell:cells){432 int row =cell.getRow();433 int col =cell.getCol();434 if(walls[row][col] != null){435 return true;436 }437 }438 return false;439 }440
441 /**
442 * 选择控制--右边443 */
444 private voidrotateRightAction() {445 tetromino.roateRight();446 if(this.outOfBounds() || this.coinclude()){447 tetromino.roateLeft();448 }449
450 }451
452
453 private static int[] scoreTable = {0,1,10,50,100};454
455 /**
456 *销毁行457 */
458 public voiddestoryLines()459 {460 int lines = 0;461 //循环墙上的每一行,如果每一行都有格子,表示行满
462 for(int row = 0; row < walls.length; row++){463 if(this.fullCells(row)){464 deleteRow(row);465 lines++;466 }467 }468 this.score +=scoreTable[lines];469 this.lines +=lines;470 }471
472 /**
473 * 删除某行474 *475 */
476 public void deleteRow(introw) {477 for(int i = row; i >=1; i--)478 {479 System.arraycopy(walls[i-1], 0, walls[i], 0, COLS);480 }481 Arrays.fill(walls[0], null);482 }483
484
485 /**
486 * 判断行是否满了487 */
488 public boolean fullCells(introw){489 Cell[] line = walls[row];//获取每一个格子的行
490 for(Cell cell:line)491 {492 if(cell == null)493 {494 return false; //未满
495 }496 }497 return true;498 }499
500
501 /**
502 * 格子落地503 */
504 public voidlandIntoWall(){505 //获取正在下落的四个格子
506 Cell[] cells =tetromino.cells;507 for(int i = 0; i< cells.length; i++)508 {509 Cell cell =cells[i];510 int row =cell.getRow();511 int col =cell.getCol();512 //格子放在相应的位置
513 walls[row][col] =cell;514 }515 }516
517
518 /**
519 * 判断是否可以继续下落520 *@paramargs521 */
522
523 private booleancanDrop(){524 Cell[] cells =tetromino.cells;525 //到达最后一行
526 for (int i = 0; i < cells.length; i++) {527 Cell cell =cells[i];528 int row =cell.getRow();529 if( row == ROWS - 1)530 {531 return false; //不能下落
532 }533 }534 //下一行有格子
535 for(Cell cell:cells )536 {537 int row = cell.getRow() + 1;538 int col =cell.getCol();539 if( row >= 0 && row < ROWS && col >=0 && col <=COLS540 && walls[row][col] != null)541 {542 return false;543 }544 }545 return true;546 }547
548 /**
549 *下落流控制550 */
551 public voidsoftDorpAction() {552 if(this.canDrop()){553 tetromino.softDorp();554 }else{555 this.landIntoWall();556 this.destoryLines();557 this.tetromino = this.nextOne;558 this.nextOne =Tetromino.getOne();559 }560 }561
562 public voidhardDropAction()563 {564 while(this.canDrop()){565 this.softDorpAction();566 }567 landIntoWall();568 destoryLines();569 tetromino =nextOne;570 nextOne =Tetromino.getOne();571 }572
573 public static voidmain(String[] args) {574 JFrame jf = newJFrame();575 Tetris tetris = newTetris();576 tetris.setBackground(new Color(0x0000ff));577 jf.add(tetris);578 jf.setSize(530, 580);579 jf.setLocationRelativeTo(null);580 jf.setTitle("Go Fighting——FTL");581 jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);582 jf.setVisible(true);583
584 tetris.action();585 }586
587 }