业务需求->业务对象模型(对象关系)->数据建模->类的设计->概要编码->详细功能设计

基本规则:

1)俄罗斯方块都是由一个个Cell构成的:

行宽:10,列高:20,以每个小正方形为单位

2)其次,所有的俄罗斯方块都是一组由4个小型正方形组成的规则图形Tetromino

分别为:S、Z、L、J、I、O、T这几种

数据结构设计:

Cell     格子

|--     int row 行

|--     int col 列

|--     Image image 贴图

Tetromino     四格方块,有7个子类

|--     Cell[] cells     包含4个格子

Tetris     俄罗斯方块

|--     int score     分数

|--     int lines      行数

|--     Cell[][] wall = new Cell[20][10]     20*10的墙

|--     Tetromino tetromino     正在下落的方块

|--     Trtromino nextOne        下一个下落方块

其次是功能:

下落移动功能

旋转流程

定时自动下落

暂停

继续

结束游戏

算法设计:

4格方块的初始形态:I S Z J L T O

就在初始数据的数值状态设计

四格方块的下落计算: 就是将每个格子的row+1

四格子方块的左右移动计算:就是将每个格子的col+1或col-1

下落流程控制:控制方块下落与墙之间的控制关系

1) 如果"能够下落", 就下落一步

2) 否则就"着陆到墙里面"

3) 着落以后, "销毁充满的行", 并且记分

4) 检查游戏是否结束

5) 如果没有结束,还能玩,就生成下一个方块

分数计算

界面的绘制

键盘事件控制

旋转流程控制

加速下降流程控制

记分

开始流程控制(Timer)

主刷新(Timer)频率: 1/100 秒

0.5秒执行一次下落(是主刷新的50倍)

利用定时器定时的调用 下落流程

如果暂停时候, 就不执行下落流程来

实现过程:

1) 在Tetris类中添加属性 Timer, 用于启动主刷新频率

2) 在Tetris类中添加属性 level 是下落的间隔次数

如: 50 表示50次刷新以后,执行一次 下落, 如果减少,

加快下落

3)  在Tetris类中添加属性 stepIndex 是下落计数

每当 stepIndex % level == 0 时候 执行一次 下落

4) 在Tetris类中添加属性  pause 暂停执行状态控制

5) 在action() 方法添加主刷新Timer的启动

在主刷新中 添加代码 控制下落

绘制背景图片

1) 在Tetris类中声明静态变量 background

2) 使用静态代码块 加载磁盘文件到内存对象

将使用到 图片读取API: ImageIO

3) 在paint 方法中绘制背景图片

绘制 正在下落的方块

1) 先在action方法中生产 正在下落的方块和下一个方块

2) 在paint方法中调用 paintTetromino()方法

3) 在Tetris类中 增加paintTetromino()方法

将正在下落的4格方块的每个格子逐一绘制出来

使方块移动

1) 处理键盘事件(API), 获得用户何时按下 -> 

2) 当按下 -> 按键时候, 执行当前4格方块 向右移动 方法

3) 向右移动 方法 会改变当前4格方块的每个格子的列坐标

4) 调用继承于JPanel类的 repaint(), 这个方法会尽快的

调用 paint()

5) paint() 会根据当前数据(已经被右移动改变的数据)

绘制全部面板效果

以下是源码:

Cell.java(格子类)

1 packagecom.timmy.tetris;2 importjava.awt.Image;3 public classCell {4 /**

5 *一个格子6 */

7 private introw;8 private intcol;9 privateImage image;10 public Cell(int
row,intcol,Image image){11 this.row =row;12 this.col =col;13 this.image
=image;14 }15

16 //toString打印行列,方便调试

17 publicString toString(){18 return "["+row+","+col+"]";19 }20

21 public voiddrop(){22 row++;23 }24

25 public voidmoveLeft(){26 col--;27 }28

29 public voidmoveRight(){30 col++;31 }32

33

34 public void setRow(introw){35 this.row =row;36 }37

38 public intgetRow(){39 returnrow;40 }41 public intgetCol() {42 returncol;43
}44 public void setCol(intcol) {45 this.col =col;46 }47 publicImage getImage()
{48 returnimage;49 }50 public voidsetImage(Image image) {51 this.image
=image;52 }53 }

Tetromino.java(四格方块类)

1 packagecom.timmy.tetris;2 importjava.util.Random;3 //抽象类

4 public abstract classTetromino {5 /**

6 * 四格方块类7 */

8 //是留给子类的,所以用保护

9 protected Cell[] cells = new Cell[4];10 protected State[] states;//旋转状态

11

12 /**私有构造器,不会有子类*/

13 privateTetromino(){14 }15

16 /**内部类、旋转*/

17 protected classState{18 introw0,col0,row1,col1,row2,col2,row3,col3;19
public State(int row0, int col0, int row1, int col1, introw2,20 int col2, int
row3, intcol3) {21 super();22 this.row0 =row0;23 this.col0 =col0;24 this.row1
=row1;25 this.col1 =col1;26 this.row2 =row2;27 this.col2 =col2;28 this.row3
=row3;29 this.col3 =col3;30 }31 }32

33 /**旋转下标*/

34 private int index = 10000;35

36 /**向右转*/

37 public voidrotateRight(){38 index++; //10001

39 State s = states[index%states.length];//取余是[1]40 //s = s1

41 Cell o = cells[0];//找到0号格子作为旋转轴

42 int row =o.getRow();43 int col =o.getCol();44
cells[1].setRow(row+s.row1);45 cells[1].setCol(col+s.col1);46
cells[2].setRow(row+s.row2);47 cells[2].setCol(col+s.col2);48
cells[3].setRow(row+s.row3);49 cells[3].setCol(col+s.col3);50 }51

52 /**向左转*/

53 public voidrotateLeft(){54 index--;55 State s =
states[index%states.length];56 Cell o = cells[0];57 int row =o.getRow();58 int
col =o.getCol();59 cells[1].setRow(row+s.row1);60
cells[1].setCol(col+s.col1);61 cells[2].setRow(row+s.row2);62
cells[2].setCol(col+s.col2);63 cells[3].setRow(row+s.row3);64
cells[3].setCol(col+s.col3);65 }66

67 /**下落一步*/

68 public voidsoftDrop(){69 for(int i=0;i

86 }87

88 //简单工厂方法模式:

89 public staticTetromino randomOne(){90 Random r = newRandom();91 int type =
r.nextInt(7);92 switch(type){93 case 0: return newT();94 case 1: return
newI();95 case 2: return newS();96 case 3: return newZ();97 case 4: return
newL();98 case 5: return newJ();99 case 6: return newO();100 }101 return
null;102 }103

104 //利用私有内部类,封装了子类实现的细节,永远只有7种子类105 //静态会造成用类名直接访问,外部不知道,别人不能new

106 private static class T extendsTetromino{107 publicT(){108 cells[0] = new
Cell(0,4,Tetris.T);109 cells[1] = new Cell(0,3,Tetris.T);110 cells[2] = new
Cell(0,5,Tetris.T);111 cells[3] = new Cell(1,4,Tetris.T);112 states = new
State[4];113 states[0] = new State(0,0,0,-1,0,1,1,0);114 states[1] = new
State(0,0,-1,0,1,0,0,-1);115 states[2] = new State(0,0,0,1,0,-1,-1,0);116
states[3] = new State(0,0,1,0,-1,0,0,1);117 }118 }119 private static class I
extendsTetromino{120 publicI(){121 cells[0] = new Cell(0,4,Tetris.I);122
cells[1] = new Cell(0,3,Tetris.I);123 cells[2] = new Cell(0,5,Tetris.I);124
cells[3] = new Cell(0,6,Tetris.I);125 states = new State[2];126 states[0] = new
State(0,0,0,-1,0,1,0,2);127 states[1] = new State(0,0,-1,0,1,0,2,0);128 }129

130 }131 private static class S extendsTetromino{132 publicS(){133 cells[0] =
new Cell(0,4,Tetris.S);134 cells[1] = new Cell(0,5,Tetris.S);135 cells[2] = new
Cell(1,3,Tetris.S);136 cells[3] = new Cell(1,4,Tetris.S);137 states = new
State[2];138 states[0] = new State(0,0,1,0,-1,-1,0,-1);139 states[1] = new
State(0,0,0,1,1,-1,1,0);140

141 }142

143 }144 private static class Z extendsTetromino{145 publicZ(){146 cells[0] =
new Cell(1,4,Tetris.Z);147 cells[1] = new Cell(0,3,Tetris.Z);148 cells[2] = new
Cell(0,4,Tetris.Z);149 cells[3] = new Cell(1,5,Tetris.Z);150 states = new
State[2];151 states[0] = new State(0,0,-1,1,0,1,1,0);152 states[1] = new
State(0,0,-1,-1,-1,0,0,1);153 }154

155 }156 private static class L extendsTetromino{157 publicL(){158 cells[0] =
new Cell(0,4,Tetris.L);159 cells[1] = new Cell(0,3,Tetris.L);160 cells[2] = new
Cell(0,5,Tetris.L);161 cells[3] = new Cell(1,3,Tetris.L);162 states = new
State[4];163 states[0] = new State(0,0,-1,0,1,0,-1,-1);164 states[1] = new
State(0,0,0,1,0,-1,-1,1);165 states[2] = new State(0,0,1,0,-1,0,1,1);166
states[3] = new State(0,0,0,-1,0,1,1,-1);167 }168

169 }170 private static class J extendsTetromino{171 publicJ(){172 cells[0] =
new Cell(0,4,Tetris.J);173 cells[1] = new Cell(0,3,Tetris.J);174 cells[2] = new
Cell(0,5,Tetris.J);175 cells[3] = new Cell(1,5,Tetris.J);176 states = new
State[4];177 states[0] = new State(0,0,-1,0,1,0,1,-1);178 states[1] = new
State(0,0,0,1,0,-1,-1,-1);179 states[2] = new State(0,0,1,0,-1,0,-1,1);180
states[3] = new State(0,0,0,-1,0,1,1,1);181 }182

183 }184 private static class O extendsTetromino{185 publicO(){186 cells[0] =
new Cell(0,4,Tetris.O);187 cells[1] = new Cell(0,5,Tetris.O);188 cells[2] = new
Cell(1,4,Tetris.O);189 cells[3] = new Cell(1,5,Tetris.O);190 states = new
State[1];191 states[0] = new State(0,0,0,1,1,0,1,1);192 }193

194 }195 }

Tetris.java(俄罗斯方块类【主类】)

1 packagecom.timmy.tetris;2 importjava.awt.Color;3 importjava.awt.Font;4
importjava.awt.Graphics;5 importjava.awt.Image;6
importjava.awt.event.KeyAdapter;7 importjava.awt.event.KeyEvent;8
importjava.awt.event.KeyListener;9 importjava.util.Arrays;10
importjava.util.Timer;11 importjava.util.TimerTask;12
importjavax.imageio.ImageIO;13 importjavax.swing.JPanel;14
importjavax.swing.JFrame;15 //JPanel 图形界面上能够显示的空白面板(空白矩形区域)16 //扩展了面板为
俄罗斯方块,扩展出 分数 和 正在下落的17 //方块,以及下一个下落的方块

18 public class Tetris extendsJPanel{19 /**

20 * 俄罗斯方块类,继承于JPanel21 */

22 public static final int ROWS = 20;23 public static final int COLS = 10;24
//格子的绘制大小

25 public static final int CELL_SIZE = 26;26 //行数

27 private intlines;28 //分数

29 private intscore;30 //字体颜色

31 public static final int FONT_COLOR =0x667799;32 public static final int
FONT_SIZE = 30;33

34 private booleanpause;35 private booleangameOver;36 privateTimer timer;37
//时间间隔

38 private int inteval = 500;39 //墙

40 private Cell[][] wall = new Cell[20][10];41 //正在下落的方块

42 privateTetromino tetromino;43 //下一个方块

44 privateTetromino nextOne;45 //分数表,用于针对一次性消除不同行数,给不同分数

46 private int[] scoreTable= {0,1,5,10,20};47 //利用静态代码块静态加载图片资源48
//将磁盘上的图片文件,加载到内存中的图片对象

49 public staticImage background;50 public staticImage gameOverImg;51 public
staticImage I;52 public staticImage T;53 public staticImage S;54 public
staticImage Z;55 public staticImage L;56 public staticImage J;57 public
staticImage O;58

59 static {//静态代码块,只执行一次60 //Class类提供了方法getResource()可以定位61 //package中的文件位置62
//图片文件到内存中的对象63 //tetris.png 文件与Tetris.class 在同一个包中

64 try{65 Class cls = Tetris.class;66 background =
ImageIO.read(cls.getResource("tetris.png"));67 gameOverImg =
ImageIO.read(cls.getResource("game-over.png"));68 I =
ImageIO.read(cls.getResource("I.png"));69 L =
ImageIO.read(cls.getResource("L.png"));70 J =
ImageIO.read(cls.getResource("J.png"));71 O =
ImageIO.read(cls.getResource("O.png"));72 S =
ImageIO.read(cls.getResource("S.png"));73 T =
ImageIO.read(cls.getResource("T.png"));74 Z =
ImageIO.read(cls.getResource("Z.png"));75 }catch(Exception e){76
e.printStackTrace();77 }78 }79

80 /**画界面*/

81 //重写父类JPanel 类的 paint方法(绘图方法)82 //重写之后修改了父类的paint方法,目的是实现自定义绘制83 //Graphics
理解为一个绑定到当前面板的画笔

84 public voidpaint(Graphics g){85 g.drawImage(background, 0, 0, null);86
//坐标系平移

87 g.translate(15,15);88 //画墙

89 paintWall(g);90 //画下落方块

91 paintTetromino(g);92 //画下一个下落的方块

93 paintnextOne(g);94 //画分数

95 paintScore(g);96 if(gameOver){97 g.translate(-5, -5);98
g.drawImage(gameOverImg,0,0,null);99 }100 }101

102 /**绘制分数*/

103 private voidpaintScore(Graphics g) {104

105 int x = 289;106 int y = 165;107 g.setColor(newColor(FONT_COLOR));108 Font
font = getFont();//获得系统字体

109 font = newFont(font.getFontName(),font.BOLD,FONT_SIZE);110
g.setFont(font);111 String str = "SCORE:" +score;112 g.drawString(str, x,
y);113 y+= 54;114 str = "LINES:" +lines;115 g.drawString(str, x, y);116 y+=
54;117 str = "[P]Pause";118 if(pause){119 str = "[C]CONTINUE";120 }121
if(gameOver){122 str = "[S]RESTART";123 }124 g.drawString(str, x, y);125 }126

127 /**绘制墙,就是将Wall数组的内容绘制到界面*/

128 private voidpaintWall(Graphics g){129 for(int row=0;row

131 Cell[] line =wall[row];132 for(int col=0;col

134 Cell cell =line[col];135 int x = col*CELL_SIZE;136 int y =
row*CELL_SIZE;137 if(cell==null){138 g.setColor(new Color(0));//黑色139 //画方块

140 g.drawRect(x, y,CELL_SIZE, CELL_SIZE);141 }else{142
g.drawImage(cell.getImage(), x-1, y-1, null);143 }144 }145 }146 }147

148 /**启动软件*/

149 public voidaction(){150 startAction();151 repaint();//JPanel
中的重绘方法,会尽快调用paint152 //键盘按键监听器,KeyListener是KeyAdapter的父类153 //利用匿名内部类

154 KeyListener l = newKeyAdapter() {155 //如果有按键按下,就会执行

156 public voidkeyPressed(KeyEvent e){157 int key =e.getKeyCode();158 if(key
==KeyEvent.VK_Q){159 System.exit(0);//结束程序

160 }161 if(gameOver){162 if(key ==KeyEvent.VK_S){163 startAction();164
repaint();165 }166 return;167 }168 if(pause){169 if(key ==KeyEvent.VK_C){170
continueAction();171 }172 return; //提前结束方法,不再处理后续事件

173 }174 switch(key){175 caseKeyEvent.VK_DOWN:softDropAction();176 break;177
caseKeyEvent.VK_RIGHT:moveRightAction();178 break;179
caseKeyEvent.VK_LEFT:moveLeftAction();180 break;181
caseKeyEvent.VK_UP:rotateRightAction();182 break;183
caseKeyEvent.VK_SPACE:hardDropAction();184 break;185
caseKeyEvent.VK_P:pauseAction();186 break;187 }188 repaint();//重绘

189 }190 };191 //将键盘监听器对象,添加到面板上

192 this.addKeyListener(l);//this 代表当前俄罗斯方块面板

193 this.requestFocus();//获得焦点

194 }195

196 /**方块旋转*/

197 private voidrotateRightAction() {198 tetromino.rotateRight();199
if(outOfBounds() ||coincide()){200 tetromino.rotateLeft();201 }202 }203

204 /**画正在下落块*/

205 public voidpaintTetromino(Graphics g){206 //如果没有正在下落的方块,就不绘制

207 if(tetromino==null){208 return;209 }210 Cell[] cells =tetromino.cells;211
for(int i=0;i

219 /**画下一个方块*/

220 public voidpaintnextOne(Graphics g){221 //如果没有正在下落的方块,就不绘制

222 if(tetromino==null){223 return;224 }225 Cell[] cells =nextOne.cells;226
for(int i=0;i

234 /**下落方法*/

235 private voidsoftDropAction(){236 if(canDrop()){237
tetromino.softDrop();238 }else{239 landToWall();240 destroyLines();241
checkGameOver();242 tetromino =nextOne;243 nextOne =Tetromino.randomOne();244
}245 }246

247 /**检查当前方块是否能下落*/

248 private booleancanDrop(){249 Cell[] cells =tetromino.cells;250
//检查当前方块是否到达底部

251 for(Cell cell: cells){252 int row =cell.getRow();253 if(row==ROWS-1){254
return false;255 }256 }257 //检查是否到墙

258 for(Cell cell:cells){259 int row =cell.getRow();260 int col
=cell.getCol();261 if(wall[row+1][col]!=null){262 return false;263 }264 }265
return true;266 }267 /**着陆到墙*/

268 private voidlandToWall(){269 Cell[] cells =tetromino.cells;270 for(Cell
cell:cells){271 int row =cell.getRow();272 int col =cell.getCol();273
wall[row][col] =cell;274 }275 }276

277 /**硬下落*/

278 public voidhardDropAction(){279 while(canDrop()){280
tetromino.softDrop();281 }282 landToWall();283 destroyLines();284
checkGameOver();285 tetromino =nextOne;286 nextOne =Tetromino.randomOne();287
}288

289 /**消除行*/

290 private voiddestroyLines(){291 int lines = 0;292 for(int row=0;row

302 /**检查是否这行是否满*/

303 private boolean fullCells(introw){304 Cell[] line =wall[row];305 for(Cell
cell:line){306 if(cell==null){307 return false;308 }309 }310 return true;311
}312

313 /**删除行*/

314 private void deleteLine(introw){315 for(int i=row;i>=1;i--){316
//wall[i-1]->wall[i]

317 System.arraycopy(wall[i-1], 0, wall[i], 0, COLS);318 }319
Arrays.fill(wall[0], null);//第零行归零

320 }321

322 /**检查是否游戏结束*/

323 private voidcheckGameOver(){324 if(wall[0][4] != null){325 gameOver =
true;326 timer.cancel();327 repaint();328 }329 }330

331 /**向左移动*/

332 private voidmoveLeftAction(){333 tetromino.moveLeft();334 if(outOfBounds()
||coincide()){335 tetromino.moveRight();336 }337 repaint();338 }339

340 /**向右移动*/

341 private voidmoveRightAction(){342 tetromino.moveRight();343
//检查顺序一定是先检查是否出界,再检查是否重合

344 if(outOfBounds() ||coincide()){345 tetromino.moveLeft();346 }347
repaint();348 }349

350 /**检查出界*/

351 private booleanoutOfBounds(){352 Cell[] cells =tetromino.cells;353
for(Cell cell : cells){354 int col =cell.getCol();355 if(col<0 ||
col>=COLS){356 return true;357 }358 }359 return false;360 }361

362 /**检查格子是否会重合*/

363 private booleancoincide(){364 Cell[] cells =tetromino.cells;365 for(Cell
cell : cells){366 int row =cell.getRow();367 int col =cell.getCol();368
if(row>=0 && row=0 && col

375 /**开始*/

376 public voidstartAction(){377 pause = false;378 gameOver = false;379 score
= 0;380 lines = 0;381 for(Cell[] line : wall){382 Arrays.fill(line, null);383
}384 tetromino =Tetromino.randomOne();385 nextOne =Tetromino.randomOne();386
TimerTask task = newTimerTask() {387 public voidrun(){388 softDropAction();389
repaint();390 }391 };392 timer = newTimer();393 timer.schedule(task, inteval,
inteval);394 }395

396 /**暂停*/

397 public voidpauseAction(){398 timer.cancel();399 pause = true;400 }401

402 /**继续*/

403 public voidcontinueAction(){404 pause = false;405 timer = newTimer();406
timer.schedule(newTimerTask(){407 public voidrun(){408 softDropAction();409
repaint();410 }411 },inteval,inteval);412 pause = false;413 }414

415 /**main 方法*/

416

417 public static voidmain(String[] args) {418 JFrame frame = new
JFrame("俄罗斯方块");//窗口框

419 Tetris tetris = new Tetris();//Tetris 继承了JPanel420 //Tetris
也是面板,面板可以放到frame中显示

421

422 frame.add(tetris);423 //去处窗口装饰

424 frame.setUndecorated(true);425 frame.setSize(530,580);426
//设置窗口的默认关闭操作是退出程序

427 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);428
//设置窗口可见,frame在显示的时候会尽快的调用 paint方法

429 frame.setVisible(true);430 //设置窗口居中

431 frame.setLocationRelativeTo(null);432 //开始动作

433 tetris.action();434 }435 }

技术
©2019-2020 Toolsou All rights reserved,
大一上c语言学生管理系统(下)年底了,不要跳槽。字节跳动测试工程师凉经分享教你用Python画一棵圣诞树用C实现圣诞树python 使用turtle 画樱花(python3验证ok)win10系统的计算机C盘在哪,c盘users在哪(win10c盘找不到users)计算机发展史上最著名的两位鼻祖HDFS主要组件(数据块、NameNode、DataNode、secondaryNameNode)python 指定时间运行代码