JAVA版俄罗斯方块学习

JAVA版俄罗斯方块学习

首页休闲益智单机俄罗斯方块中文版更新时间:2024-05-11

软件的开发过程

1) 需求(软件功能的文字描述)

2) 需求分析(找对象)

3) 概要设计

3.1) 数学模型

3.2) 类的设计

4) 详细功能的设计

4.1) 数据初始化

4.2) 界面绘制

4.3) 左右移动功能设计

4.4) 下落功能设计

1 明确业务需求

用自然语言,将业务功能描述清楚

Tetris 专用词 俄罗斯方块

Tetromino 专用词 4格方块

俄罗斯方块的基本规则:

1、一个用于摆放小型正方形的平面虚拟场地,其标准大小:

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

2、一组由4个小型正方形组成的规则图形,英文称为Tetromino,

中文通称为方块共有7种,分别以S、Z、L、J、I、O、T这7个

字母的形状来命名。

I:一次最多消除四层

J(左右):最多消除三层,或消除二层

L:最多消除三层,或消除二层

O:消除一至二层

S(左右):最多二层,容易造成孔洞

Z (左右):最多二层,容易造成孔洞

T:最多二层

(1)玩家操作有:旋转方块,以格子为单位左右移动方块,

让方块加速落下。

(2)方块移到区域最下方或是着地到其他方块上无法移动时,

就会固定在该处,而新的方块出现在区域上方开始落下。

(3)当区域中某一列横向格子全部由方块填满,则该行会消失

并成为玩家的得分。同时删除的行数越多,得分指数上升。

(4)当固定的方块堆到区域最上方而无法消除层数时,

则游戏结束。

(6)一般来说,游戏还会提示下一个要落下的方块,

熟练的玩家会计算到下一个方块,评估要如何进行。

由于游戏能不断进行下去对商业用游戏不太理想,

所以一般还会随着游戏的进行而加速提高难度。

(7)预先设置的随机发生器不断地输出单个方块到场地顶部

2 业务分析

找到有哪些业务对象根据图片的分析

窗口

|-- tetris(俄罗斯方块) 矩形区域

|-- score 累计分数

|-- lines 销毁的行数

|-- wall(墙 20行X10列)

| |-- 20row(行)

| |-- 10 col cell(列)

|-- tetromino 正在下落的(4格方块,有7种形态)

| |-- 4 cell

|-- nextOne 下一个准备下落的方块

|-- 4 cell

3 数据模型, 一切业务对象转换为数字表示

场地按照行列划分为 20×10格子

格子有属性row, col, color

4 类 设计

Cell

|-- int row

|-- int col

|-- image 贴图

Tetromino

|--Cell[] cells

|-- Cell * 4

Tetris 俄罗斯方块

|-- Cell[][] wall = 20*10

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

|-- Tetromino nextOne 下一个方块

|-- int lines

|-- int score

填写初始化代码(构造器)

功能:

toString()

绘制界面: 将对象的"数据"绘制到界面, 界面是数据的表现

界面不是业务逻辑,

利用API实现界面的绘制工作!

5 算法设计,就是如何利用数据的计算实现软件的功能

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

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

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

就是将下落业务功能,转换为数字计算实现

左右移动

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

1 合理的文字流程描述

2 分析文字描述中的功能(动作)为方法

3 用流程控制语句连接方法实现功能!

4 严格测试结果! TestCase

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

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

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

4) "检查游戏结束"了吗?

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

下落流程:也是一个功能,要封装为一个方法

A 返回值:是无返回值的方法,有输出,数据输出

结果就是tetromino 和 wall

B 方法名:softDropAction 软下落动作

C 参数:无参数,实际的输入数据tetromino和wall

D 过程:

详细设计:

A "能够下落" 设计为一个方法

返回值(输出): boolean 返回true 表示能够下落

方法名: canDrop 能够下落吗?

参数(输入):是墙和正在下落的方块

可以不作为输入参数定义,因为是Tetris的实例变量

如果将方法 canDrop 定义在 Tetris类中,就可以

直接利用this获得实例变量,进而获得输入数据

过程:

如果4格方块的某个格子 的行坐标到达19就不能

下落了

如果4格方块的某个格子的下方墙上有方块,就不能

下落了。

左右移动流程控制

是一个方法, 是一个功能

方法名:moveRightAction 向右移动动作

输入:tetromino 正在下落的方块

输出:tetromino 正在下落的方块

过程:如果正在下落的方块能够向右移动就移动一下

否则就原地不动。如果没有超过边界或者没有压住

另外一个方块,就可以移动。

也就是:如果能够移动,输出的数据一定所有列 1

算法:

1) 先向右移动一次。

2) 检查移动结果是否出界或重回(压住)

3) 如果出界了或重回了就退回去(向左移动)

分数计算

界面的绘制

键盘事件控制

旋转流程控制

加速下降流程控制

记分

开始流程控制(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的启动

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

暂停流程控制

设置暂停状态 true

继续流程控制

结束流程控制

修改键盘事件

修改paintScore方法

如何绘制背景图片

1) 将图片素材文件复制到 com.tarena.tetris 包中

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

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

将使用到 图片读取API: ImageIO

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

可能出现的错误:

1) 文件名/包搞错了!

如何绘制 正在下落的方块

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

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

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

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

如何使方块移动

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

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

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

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

调用 paint()

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

绘制全部面板效果

6) 用户的感受就是, 方块动了.

Cell.Java


  1. package Tetris;
  2. import java.awt.image.BufferedImage;
  3. /**
  4. * 格子
  5. */
  6. public class Cell {
  7. private int row;
  8. private int col;
  9. private BufferedImage image;
  10. public Cell(int row, int col, BufferedImage image) {
  11. super();
  12. this.row = row;
  13. this.col = col;
  14. this.image = image;
  15. }
  16. public int getRow() {
  17. return row;
  18. }
  19. public void setRow(int row) {
  20. this.row = row;
  21. }
  22. public int getCol() {
  23. return col;
  24. }
  25. public void setCol(int col) {
  26. this.col = col;
  27. }
  28. public BufferedImage getImage() {
  29. return image;
  30. }
  31. public void setImage(BufferedImage image) {
  32. this.image = image;
  33. }
  34. public void drop(){
  35. row ;
  36. }
  37. public void moveLeft(){
  38. col--;
  39. }
  40. public void moveRight(){
  41. col ;
  42. }
  43. }

Tetromino.java

</pre><pre name="code" class="java">Tetromino


  1. package Tetris;
  2. import java.util.Arrays;
  3. import java.util.Random;
  4. /**
  5. * 4格方块类
  6. *
  7. */
  8. public abstract class Tetromino {
  9. /** 4个格子,留给子类使用的属性 protected*/
  10. protected Cell[] cells = new Cell[4];
  11. /** 随机参数7种方块之一 */
  12. public static Tetromino randomOne(){
  13. Random random = new Random();
  14. int type = random.nextInt(7);
  15. switch (type) {
  16. case 0: return new T();
  17. case 1: return new S();
  18. case 2: return new Z();
  19. case 3: return new I();
  20. case 4: return new L();
  21. case 5: return new J();
  22. case 6: return new O();
  23. }
  24. return null;
  25. }
  26. public void softDrop(){
  27. for (int i = 0; i < cells.length; i ) {
  28. Cell cell = cells[i];
  29. cell.drop();
  30. }
  31. }
  32. public void moveLeft(){
  33. for (int i = 0; i < cells.length; i ) {
  34. Cell cell = cells[i];
  35. cell.moveLeft();
  36. }
  37. }
  38. public void moveRight(){
  39. for (int i = 0; i < cells.length; i ) {
  40. Cell cell = cells[i];
  41. cell.moveRight();
  42. }
  43. }
  44. @Override
  45. public String toString() {
  46. return Arrays.toString(cells);
  47. }
  48. /** 存储旋转状态的类,在Tetromino类中添加 */
  49. protected class State{
  50. int row0,col0,row1,col1,
  51. row2,col2,row3,col3;
  52. public State(int row0, int col0, int row1, int col1, int row2,
  53. int col2, int row3, int col3) {
  54. this.row0=row0;this.col0=col0;
  55. this.row1 = row1;this.col1 = col1;
  56. this.row2 = row2;this.col2 = col2;
  57. this.row3 = row3;this.col3 = col3;
  58. }
  59. }
  60. //在Tetromino 类上添加向右转的方法
  61. private int index = 10000;
  62. //s0={row0,col0,row1,col1,row2,col2,row3,col3}
  63. protected State[] states;//在子类构造器中初始化 //{s0,s1,s2,s3};
  64. public void rotateRight() {
  65. //System.out.println(this);
  66. //输入1:cells 当前方块的数据
  67. //输入2:sN : s1 s2 s3 s0 s1 s2 s3 ...
  68. //输出 cells 旋转以后的方块数据
  69. //算法:cells[0] sN -> cells
  70. //如何得到序列:1 2 3 0 1 2 3 0 1 2 3 0
  71. index ;//10005
  72. //index%4 = ?;//1 2 3 0 1 2 3 0
  73. //states[index%4]=?//s1 s2 s3 s0 s1 s2 s3...
  74. State s = states[index%states.length];
  75. //s = s1
  76. Cell o = cells[0];//找到轴 t0[0]
  77. int row = o.getRow();
  78. int col = o.getCol();
  79. cells[1].setRow(row s.row1);//轴的row s1[row1]=t1.row
  80. cells[1].setCol(col s.col1);
  81. cells[2].setRow(row s.row2);
  82. cells[2].setCol(col s.col2);
  83. cells[3].setRow(row s.row3);
  84. cells[3].setCol(col s.col3);
  85. //System.out.println(this);
  86. }
  87. public void rotateLeft() {
  88. index --;//10005
  89. State s = states[index%states.length];
  90. Cell o = cells[0];//找到轴 t0[0]
  91. int row = o.getRow();
  92. int col = o.getCol();
  93. cells[1].setRow(row s.row1);//轴的row s1[row1]=t1.row
  94. cells[1].setCol(col s.col1);
  95. cells[2].setRow(row s.row2);
  96. cells[2].setCol(col s.col2);
  97. cells[3].setRow(row s.row3);
  98. cells[3].setCol(col s.col3);
  99. }
  100. }
  101. /** T 型方块,包内类 */
  102. class T extends Tetromino{
  103. public T() {
  104. cells[0] = new Cell(0,4,Tetris.T);
  105. cells[1] = new Cell(0,3,Tetris.T);
  106. cells[2] = new Cell(0,5,Tetris.T);
  107. cells[3] = new Cell(1,4,Tetris.T);
  108. //在子类中初始化旋转状态数据
  109. states = new State[]{
  110. new State(0,0, 0,-1, 0,1, 1,0), //s0
  111. new State(0,0, -1,0, 1,0, 0,-1),//s1
  112. new State(0,0, 0,1, 0,-1, -1,0),//s2
  113. new State(0,0, 1,0, -1,0, 0,1)//s3
  114. };
  115. }
  116. }
  117. class S extends Tetromino{
  118. public S() {
  119. cells[0] = new Cell(0,4,Tetris.S);
  120. cells[1] = new Cell(0,5,Tetris.S);
  121. cells[2] = new Cell(1,3,Tetris.S);
  122. cells[3] = new Cell(1,4,Tetris.S);
  123. //=====
  124. states = new State[] {
  125. new State(0, 0, 0, 1, 1, -1, 1, 0),
  126. new State(0, 0, -1, 0, 1, 1, 0, 1)};
  127. }
  128. }
  129. class L extends Tetromino{
  130. public L() {
  131. cells[0] = new Cell(0,4,Tetris.L);
  132. cells[1] = new Cell(0,3,Tetris.L);
  133. cells[2] = new Cell(0,5,Tetris.L);
  134. cells[3] = new Cell(1,3,Tetris.L);
  135. //====
  136. states = new State[] {
  137. new State(0, 0, 0, 1, 0, -1, -1, 1),
  138. new State(0, 0, 1, 0, -1, 0, 1, 1),
  139. new State(0, 0, 0, -1, 0, 1, 1, -1),
  140. new State(0, 0, -1, 0, 1, 0, -1, -1)};
  141. }
  142. }
  143. class J extends Tetromino{
  144. public J() {
  145. cells[0] = new Cell(0,4,Tetris.J);
  146. cells[1] = new Cell(0,3,Tetris.J);
  147. cells[2] = new Cell(0,5,Tetris.J);
  148. cells[3] = new Cell(1,5,Tetris.J);
  149. //===
  150. states = new State[] {
  151. new State(0, 0, 0, 1, 0, -1, -1, -1),
  152. new State(0, 0, 1, 0, -1, 0, -1, 1),
  153. new State(0, 0, 0, -1, 0, 1, 1, 1),
  154. new State(0, 0, -1, 0, 1, 0, 1, -1)};
  155. }
  156. }
  157. class Z extends Tetromino{
  158. public Z() {
  159. cells[0] = new Cell(1,4,Tetris.Z);
  160. cells[1] = new Cell(1,5,Tetris.Z);
  161. cells[2] = new Cell(0,3,Tetris.Z);
  162. cells[3] = new Cell(0,4,Tetris.Z);
  163. //====
  164. states = new State[] {
  165. new State(0, 0, -1, -1, -1, 0, 0, 1),
  166. new State(0, 0, -1, 1, 0, 1, 1, 0)};
  167. }
  168. }
  169. class O extends Tetromino{
  170. public O() {
  171. cells[0] = new Cell(0,4,Tetris.O);
  172. cells[1] = new Cell(0,5,Tetris.O);
  173. cells[2] = new Cell(1,4,Tetris.O);
  174. cells[3] = new Cell(1,5,Tetris.O);
  175. //===
  176. states = new State[] { new State(0, 0, 0, 1, 1, 0, 1, 1),
  177. new State(0, 0, 0, 1, 1, 0, 1, 1) };
  178. }
  179. }
  180. class I extends Tetromino{
  181. public I() {
  182. cells[0] = new Cell(0,4,Tetris.I);
  183. cells[1] = new Cell(0,3,Tetris.I);
  184. cells[2] = new Cell(0,5,Tetris.I);
  185. cells[3] = new Cell(0,6,Tetris.I);
  186. //===
  187. states = new State[] {
  188. new State(0, 0, 0, -1, 0, 1, 0, 2),
  189. new State(0, 0, -1, 0, 1, 0, 2, 0)};
  190. }
  191. }
  192. package Tetris;
  193. import java.awt.Color;
  194. import java.awt.Font;
  195. import java.awt.Graphics;
  196. import java.awt.event.KeyAdapter;
  197. import java.awt.event.KeyEvent;
  198. import java.awt.event.KeyListener;
  199. import java.awt.image.BufferedImage;
  200. import java.util.Arrays;
  201. import javax.imageio.ImageIO;
  202. import javax.swing.JFrame;
  203. import javax.swing.JPanel;
  204. /**
  205. * 俄罗斯方块
  206. *
  207. */
  208. public class Tetris extends JPanel {
  209. /** 游戏的状态 */
  210. private int state;
  211. /** 游戏正在玩状态 */
  212. public static final int PLAYING = 0;
  213. /** 游戏暂停状态 */
  214. public static final int PAUSE = 1;
  215. /** 游戏结束状态 */
  216. public static final int GAME_OVER = 2;
  217. /** 游戏状态提示信息 */
  218. private static final String[] STATE=
  219. {"[P]Pause", "[C]Continue", "[S]Restart"};
  220. /** 下落速度控制 */
  221. int index = 0;
  222. /** speed 的值越小下落速度越快 */
  223. int speed = 8;
  224. /** 分数 */
  225. private int score;
  226. /** 行数, 销毁的总行数 */
  227. private int lines;
  228. public static final int ROWS = 20;
  229. public static final int COLS = 10;
  230. /** 方块墙 */
  231. private Cell[][] wall=new Cell[ROWS][COLS];
  232. /** 正在下落的方块 */
  233. private Tetromino tetromino;
  234. /** 下一个方块 */
  235. private Tetromino nextOne;
  236. /** 在Tetris 中添加背景图属性 */
  237. private static BufferedImage background;
  238. public static BufferedImage gameOverImage;
  239. public static BufferedImage T;
  240. public static BufferedImage S;
  241. public static BufferedImage Z;
  242. public static BufferedImage J;
  243. public static BufferedImage L;
  244. public static BufferedImage I;
  245. public static BufferedImage O;
  246. /** 读取图片文件到内存对象 */
  247. //将图片复制到 com.tarena.tetris包中
  248. static {
  249. try{
  250. background=ImageIO.read(
  251. Tetris.class.getResource(
  252. "tetris.png"));
  253. gameOverImage=ImageIO.read(
  254. Tetris.class.getResource(
  255. "game-over.png"));
  256. T=ImageIO.read(Tetris.class
  257. .getResource("T.png"));
  258. S=ImageIO.read(Tetris.class
  259. .getResource("S.png"));
  260. Z=ImageIO.read(Tetris.class
  261. .getResource("Z.png"));
  262. J=ImageIO.read(Tetris.class
  263. .getResource("J.png"));
  264. L=ImageIO.read(Tetris.class
  265. .getResource("L.png"));
  266. O=ImageIO.read(Tetris.class
  267. .getResource("O.png"));
  268. I=ImageIO.read(Tetris.class
  269. .getResource("I.png"));
  270. }catch(Exception e){
  271. e.printStackTrace();
  272. }
  273. }
  274. /** 利用重写方法修改父类JPanel */
  275. //paint:涂绘, Graphics:图,画笔
  276. public void paint(Graphics g){
  277. //draw: 绘
  278. g.drawImage(background, 0, 0, null);
  279. //g.drawString("Hello", 50, 50);
  280. g.translate(15, 15);
  281. paintWall(g);
  282. paintTetromino(g);
  283. paintNextOne(g);
  284. paintScore(g);//绘制分数
  285. g.translate(-15, -15);
  286. paintState(g);//绘制游戏状态
  287. }
  288. //绘制状态
  289. private void paintState(Graphics g) {
  290. //如果state是 0 显示 Pause
  291. //如果state是 1 显示 Continue
  292. //如果state是 2 显示 Restart
  293. g.drawString(STATE[state], 309, 287);
  294. if(state == GAME_OVER){
  295. g.drawImage(gameOverImage,0,0,null);
  296. }
  297. }
  298. //绘制分数
  299. private void paintScore(Graphics g){
  300. int x = 293;
  301. int y = 162;
  302. Font font = new Font(
  303. Font.SANS_SERIF, Font.BOLD, 30);
  304. g.setFont(font);
  305. g.setColor(new Color(0x667799));
  306. g.drawString("SCORE:" score, x, y);
  307. y =56;
  308. g.drawString("LINES:" lines, x, y);
  309. }
  310. public void paintNextOne(Graphics g){
  311. Cell[] cells = nextOne.cells;
  312. for(int i=0;i<cells.length; i ){
  313. Cell cell = cells[i];
  314. int x = CELL_SIZE*(cell.getCol() 10);
  315. int y = CELL_SIZE*(cell.getRow() 1);
  316. g.drawImage(cell.getImage(), x, y,
  317. null);
  318. }
  319. }
  320. /** 在Tetris类中填方法,绘制正在下落的方块 */
  321. public void paintTetromino(Graphics g){
  322. Cell[] cells = tetromino.cells;
  323. for(int i=0;i<cells.length; i ){
  324. Cell cell = cells[i];
  325. int x = CELL_SIZE*cell.getCol();
  326. int y = CELL_SIZE*cell.getRow();
  327. g.drawImage(cell.getImage(), x, y,
  328. null);
  329. }
  330. }
  331. public static final int CELL_SIZE=26;
  332. /** 在Tetris 添加画墙的方法 */
  333. private void paintWall(Graphics g){
  334. for(int row=0; row<ROWS; row ){
  335. for(int col=0; col<COLS; col ){
  336. Cell cell = wall[row][col];
  337. int x=CELL_SIZE * col;
  338. int y=CELL_SIZE * row;
  339. if(cell==null){
  340. //g.drawRect(x, y,
  341. // CELL_SIZE, CELL_SIZE);
  342. }else{
  343. g.drawImage(cell.getImage(),
  344. x,y,null);
  345. }
  346. }
  347. }
  348. }
  349. /** 在Tetris 类中添加方法 */
  350. public void action(){
  351. state = PLAYING;
  352. //wall[19][2]=new Cell(19,2,T);
  353. //尽快的调用paint()重新绘制面板
  354. tetromino = Tetromino.randomOne();
  355. nextOne = Tetromino.randomOne();
  356. repaint();
  357. //创建键盘事件监听器对象
  358. KeyListener l=new KeyAdapter(){
  359. @Override
  360. public void keyPressed(KeyEvent e) {
  361. int key = e.getKeyCode();
  362. //当state是值是PAUSE时候,只处理c按键
  363. //其它的按键的代码被忽略不再执行
  364. if(key==KeyEvent.VK_Q){
  365. System.exit(0);//结束Java进程
  366. }
  367. switch(state){
  368. case GAME_OVER:
  369. if(key==KeyEvent.VK_S){
  370. restartAction();
  371. }
  372. return;
  373. case PAUSE:
  374. if(key==KeyEvent.VK_C){
  375. state=PLAYING;
  376. }
  377. //retuer以后的代码不再执行了
  378. return;
  379. }
  380. switch(key){
  381. case KeyEvent.VK_DOWN:
  382. softDropAction();break;
  383. case KeyEvent.VK_RIGHT:
  384. moveRightAction();break;
  385. case KeyEvent.VK_LEFT:
  386. moveLeftAction(); break;
  387. case KeyEvent.VK_UP:
  388. rotateRightAction(); break;
  389. case KeyEvent.VK_Z:
  390. rotateLeftAction(); break;
  391. case KeyEvent.VK_SPACE:
  392. hardDropAction(); break;
  393. case KeyEvent.VK_P:
  394. state = PAUSE; break;
  395. }
  396. repaint();
  397. }
  398. };
  399. //添加监听器到当前面板(挂载)
  400. this.addKeyListener(l);
  401. //为当前面板申请输入焦点,有焦点才能接收键盘事件
  402. this.requestFocus();
  403. //在action方法中添加,主控制循环
  404. for(;;){
  405. if(state==PLAYING){
  406. index ;
  407. if(index % speed==0){
  408. softDropAction();
  409. }
  410. }
  411. repaint();
  412. try{
  413. Thread.sleep(1000/10);
  414. }catch(Exception e){
  415. }
  416. }
  417. }
  418. /** 重新开始游戏 */
  419. protected void restartAction() {
  420. score = 0;
  421. lines = 0;
  422. //将墙清空
  423. wall = new Cell[ROWS][COLS];
  424. tetromino = Tetromino.randomOne();
  425. nextOne = Tetromino.randomOne();
  426. speed = 8;
  427. index = 0;
  428. state = PLAYING;
  429. }
  430. /** 在Tetris类中添加加速下来功能
  431. * 就是下落到不能下落为止
  432. **/
  433. private void hardDropAction(){
  434. //当能够下落就下落一步,到不能下落为止
  435. while(canDrop()){
  436. tetromino.softDrop();
  437. }
  438. landIntoWall();
  439. destroyLines();
  440. if(!isGameOver()){
  441. tetromino = nextOne;
  442. nextOne = Tetromino.randomOne();
  443. }else{ //游戏结束状态
  444. state = GAME_OVER;
  445. }
  446. }
  447. /** 在Tetris 类中填写方法 softDropAction */
  448. private void softDropAction(){
  449. boolean drop = canDrop();
  450. //System.out.println("t:" tetromino);
  451. //System.out.println("canDrop:" drop);
  452. if(drop){
  453. tetromino.softDrop();
  454. }else{
  455. // 入墙,land着陆 into进去 Wall 墙
  456. landIntoWall();//封装 方块入墙 的算法
  457. // 销毁行 destroyLines,计分
  458. destroyLines();//封装销毁行的算法
  459. // 检查是否结束
  460. // 如果游戏没有结束,产生下一个方块
  461. if(!isGameOver()){
  462. tetromino=nextOne;
  463. nextOne=Tetromino.randomOne();
  464. }else{
  465. state = GAME_OVER;
  466. }
  467. }
  468. //System.out.println(tetromino);
  469. }
  470. /** 检查游戏是否结束
  471. * 如果下一个将要出场的方块的墙上位置被占用
  472. * 了就结束了!
  473. * */
  474. private boolean isGameOver() {
  475. Cell[] cells = nextOne.cells;
  476. for(int i=0; i<cells.length; i ){
  477. Cell cell = cells[i];
  478. int row=cell.getRow();
  479. int col=cell.getCol();
  480. if(wall[row][col]!=null){
  481. return true;
  482. }
  483. }
  484. return false;
  485. }
  486. /** 销毁墙上已经满的行, 并且计分 */
  487. private int[] scoreTable = {0,1,5,20,100};
  488. // lines 0 1 2 3 4
  489. private void destroyLines() {
  490. int lines = 0;//当前销毁的行数
  491. for(int row=0; row<ROWS; row ){
  492. if(fullCells(row)){
  493. deleteRow(row);
  494. lines ;
  495. }
  496. }
  497. this.score = scoreTable[lines];
  498. //速度控制,每增加1000分时候,速度
  499. //的值会变小,速度加快
  500. //速度的最小值是 1,不能比1更小了
  501. speed = Math.max(8-score/1000, 1);
  502. this.lines = lines;
  503. }
  504. /** 检查墙上row行是否是"满格子",true:满了 */
  505. private boolean fullCells(int row) {
  506. Cell[] line = wall[row];
  507. for(int i=0; i<line.length; i ){
  508. Cell cell = line[i];
  509. if(cell==null){
  510. return false;
  511. }
  512. }
  513. return true;
  514. }
  515. /** 删除墙上 row对应的行 */
  516. private void deleteRow(int row) {
  517. for(int i=row; i>=1; i--){
  518. System.arraycopy(wall[i-1], 0,
  519. wall[i], 0, COLS);
  520. }
  521. Arrays.fill(wall[0], null);
  522. }
  523. /** 将方块着陆到墙上 */
  524. private void landIntoWall() {
  525. Cell[] cells = tetromino.cells;
  526. for(int i=0; i<cells.length; i ){
  527. Cell cell = cells[i];
  528. int row = cell.getRow();
  529. int col = cell.getCol();
  530. wall[row][col]=cell;
  531. }
  532. }
  533. /** 在Tetris类中添加方法 canDrop() */
  534. private boolean canDrop(){
  535. //输入是 wall tetromino
  536. //先检查tetromino是否到达底部
  537. Cell[] cells = tetromino.cells;
  538. for(int i=0; i<cells.length; i ){
  539. //i = 0 1 2 3
  540. //cell“引用”了4格方块的每个格式
  541. Cell cell = cells[i];
  542. //如果某个格子的行是19,就不能下落了
  543. if(cell.getRow() == ROWS-1){
  544. //System.out.println("到达底部");
  545. return false;
  546. }
  547. }
  548. //检查tetromino的下方墙上是否有方块
  549. for(int i=0; i<cells.length; i ){
  550. Cell cell = cells[i];
  551. int row = cell.getRow();
  552. int col = cell.getCol();
  553. if(wall[row 1][col]!=null){
  554. //System.out.println(cell "的下方有方块");
  555. return false;
  556. }
  557. }
  558. return true;
  559. }
  560. /** Tetris 类中添加向右移动流程控制方法 */
  561. private void moveRightAction(){
  562. tetromino.moveRight();
  563. //outOfBounds出界 concide:重合
  564. if(outOfBounds() || concide()){
  565. tetromino.moveLeft();
  566. }
  567. }
  568. private void moveLeftAction(){
  569. tetromino.moveLeft();
  570. //outOfBounds出界 concide:重合
  571. if(outOfBounds() || concide()){
  572. tetromino.moveRight();
  573. }
  574. }
  575. //检查当前下落的方块,是否出界,true:出界了
  576. private boolean outOfBounds(){
  577. Cell[] cells = tetromino.cells;
  578. for(int i=0; i<cells.length; i ){
  579. Cell cell = cells[i];
  580. int row = cell.getRow();
  581. int col = cell.getCol();
  582. if((row<0||row>=ROWS) ||
  583. (col<0||col>=COLS)){
  584. return true;
  585. }
  586. }
  587. return false;
  588. }
  589. //检查当前下落的方块,是否与墙砖重合,true重合
  590. private boolean concide(){
  591. Cell[] cells = tetromino.cells;
  592. //for (int i = 0; i < cells.length; i ) {
  593. // Cell cell = cells[i];
  594. for(Cell cell: cells){
  595. int row = cell.getRow();
  596. int col = cell.getCol();
  597. if(wall[row][col]!=null){
  598. return true;
  599. }
  600. }
  601. return false;
  602. }
  603. /** 在tetris 类中增加旋转流程控制方法 */
  604. public void rotateRightAction(){
  605. //rotate:原地转
  606. tetromino.rotateRight();
  607. if(outOfBounds() || concide()){
  608. tetromino.rotateLeft();
  609. }
  610. }
  611. public void rotateLeftAction(){
  612. //rotate:原地转
  613. tetromino.rotateLeft();
  614. if(outOfBounds() || concide()){
  615. tetromino.rotateRight();
  616. }
  617. }
  618. public static void main(String[] args) {
  619. //Frame 框,相框,代表窗口框
  620. JFrame frame = new JFrame();
  621. //panel 代表面板
  622. Tetris panel = new Tetris();
  623. //Background 背景
  624. panel.setBackground(Color.YELLOW);
  625. //窗口中添加面板
  626. frame.add(panel);
  627. frame.setUndecorated(true);//去掉窗口边框
  628. frame.setSize(535, 580);
  629. //居中
  630. frame.setLocationRelativeTo(null);
  631. //点击X时候同时关闭程序
  632. frame.setDefaultCloseOperation(
  633. JFrame.EXIT_ON_CLOSE);
  634. //显示窗口框
  635. frame.setVisible(true);
  636. //尽快的调用 paint()方法绘制显示界面
  637. //显示窗口以后,执行 启动方法action
  638. panel.action();
  639. }
  640. }

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved