厚德载物

爱喝茶的家伙

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

   最近看了一本软件工程方面的书籍,由于书中缺乏完整的实例,所以想从一个小项目入手以期能对软件工程多一点实践认识 ,首先我看了Qt5.6.3自带的俄罗斯方块例子(在我电脑里面的路径是C:\Qt\Qt5.6.3\Examples\Qt-5.6.3\widgets\widgets\tetrix),还有一个俄罗斯方块的Java教学视频(地址:http://www.iqiyi.com/playlist420417802.html),打算将Qt版的Tetrix俄罗斯方块改写成Java版,下面是具体的过程。

 

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

 二. 需求分析(找对象)

 三.  概要设计

    3.1 数据模型

    3.2 类的设计

 四. 详细功能的设计

    4.1 数据初始化

    4.2 界面绘制

    4.3 左右移动功能设计

    4.4 下落功能设计

    4.5 旋转功能设计

    4.6 状态检测功能设计

 五. 总结

 

一.  明确业务需求

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

    Tetris 专用词  俄罗斯方块

    Tetromino 专用词 4格方块

    俄罗斯方块的基本规则:

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

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

   2)一组由4个小型正方形组成的规则图形,英文称为Tetromino,中文通称为方块共有7种,分别为ZShape, SShape, LineShape ,TShape, SquareShape , LShape , MirroredShape,空白则称为NoShape。

  LineShape: 一次最多消除四层

  MirroredShape: 最多消除三层,或消除两层

  LShape:最多消除三层,或消除两层

  SquareShape:消除一至二层

  SShape:最多两层,容易造成孔洞

  ZShape:最多两层,容易造成孔洞

  TShape:最多两层

3)玩家操作有:旋转方块,以格子为单位左右移动方块,让方块加速下落。

4)方块移动到区域最下方或是着陆到其他方块上无法移动时,就会固定在该处,而新的方块出现在区域上方开始落下。

5)当区域中某一列横向格子全部由方块填满,则该行会消失并成为玩家的得分。删除的行数以及落下的块数越多,得分指数上升。

6)当固定的方块堆到区域最上方以至于新方块无法移动时游戏结束。

7)一般来说,游戏还会提示下一个要落下的方块,熟练的玩家会计算下一个方块,评估要如何进行。由于游戏能不断进行下去对商业游戏不太理想,所以一般还会随着游戏的进行不断提高方块的下落速度。

8)预先设置的随机发生器不断地将不同种类的方块输出到区域顶部。

9)不同形状的方块对应不同的颜色以增加画面效果。

 

二. 业务分析

  根据流程图找出有哪些业务对象

    

 

   窗口

  |— TetrixBoard(俄罗斯方块)

       |— score 累计分数

       |— numLinesRemoved 移除的行数

       |— board(游戏区域22行X10列)

       |— TetrixPiece

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

            |— newPiece下一个准备下落的方块

  这里没有设计Cell类,以防止Tetris ,Tetromino, Cell 三个层次的类相互耦合,有利于明晰设计思路

 

三. 概要设计

    1) 数据模型

         设计方块类TetrixPiece,一切业务对象转换为数字表示,类的属性有自身的相对坐标coords[][],形状变量pieceShape,颜色变量color,在游戏区域的网格坐标gridX、gridY以及在窗口的位置坐标x、y等,方法有判断是否可以移动的tryMove(),方块移动函数drop()、moveLeft()、moveRight()、rotate(),检测当前方块状态函数changeStatus()等。

    2)类的设计

       TetrixPiece

           属性

             |—tb  对主窗口类TetrixBoard对象的引用,因为要用到主类的一些方法

             |—coordsTable[][]  各种形状的方块对应的内部坐标表

             |—stoped 方块是否停止的布尔变量

             |—speedup 方块是否加速下落的布尔变量

             |—x 方块在窗口的位置坐标,从左到右增大

             |—y 方块在窗口的位置坐标,从上到下增大

             |—gridX 方块在游戏区域的网格坐标,从左到右增大

             |—gridY 方块在游戏区域的网格坐标,从下到上增大

             |—color 方块的颜色

             |—colorArr[] 各种方块对应的颜色表

             |—pieceShape 方块的形状

             |—coords[][] 方块的内部小格子坐标

       方法

     |—TetrixPiece(TetrixBoard tb) 构造函数

            |—setRandomShape() 初始化时随机设定方块类的形状

            |—setShape(int shape) 设定方块的形状

            |—x(int index) 读取指定的小方格的内部坐标

            |—y(int index) 读取指定的小方格的内部坐标

            |—minX() 方块的最小内部坐标

            |—minY() 方块的最小内部坐标

            |—maxX() 方块的最大内部坐标

            |—maxY() 方块的最大内部坐标

            |—drawNewPiece(Graphics g) 在预览区域画出下一个方块

            |—draw(Graphics g) 画出当前方块

            |—drop() 当前方块下落

            |—rotate() 当前方块旋转90度

            |—changeStatus() 检测当前方块状态

            |—pieceDropped() 检测是否可以消行,统计成绩和升级

            |—moveLeft() 当前方块左移

            |—moveRight () 当前方块右移

            |—tryMove(int newX, int newY) 判断当前方块可否向指定方向移动

            |—keyPressed(KeyEvent e) 键盘按下事件响应

            |—keyReleased(KeyEvent e) 键盘松开事件响应

 

  TetrixBoard

       属性

            |— x 窗口位置

            |— y 窗口位置

            |— board[] 纪录游戏区域方块的位置

            |— dropHeight 方块下落次数

            |— numPiecesDropped 下落的方块个数

            |— numLinesRemoved 移除的行数

            |— isStarted  游戏是否开始

            |— isPaused 游戏是否暂停

            |— score 游戏成绩

            |— level 当前等级

            |— offScreenImage 双缓冲刷新屏幕用到的变量

            |— curPiece 当前方块对象

            |— newPiece 下一个方块对象

            |— mf 文本字体对象

            |— launcher() 主类初始化函数

            |— update(Graphics g) 双缓冲刷新屏幕函数

            |— drawSquare(Graphics g, int x, int y, int Shape) 画出一个指定颜色和位置的小方格,用于显示游戏区域累计的方块

            |— paint(Graphics g) 系统自动调用的重绘函数

     内部类

            |— paintThread implements Runnable 绘制多线程内部类,用于控制新方块的生成和时间点

            |— keyMonitor extends KeyAdapter 按键事件内部类

     方法

        |— launcher() 初始化函数

            |— clearBoard() 初始化时清空纪录方块位置的数组

            |— removeFullLines() 通过更新方块位置纪录数组实现消行

            |— main(String[] args) 程序主函数

 

四. 详细功能设计

   1)数据初始化

        设定主窗口的位置、大小、标题、背景、可见性、窗口监听器和键盘事件监听器等,初始化两个方块对象,指定它们的颜色和形状,清空纪录方块位置的数组。

 

   2)界面绘制

        在指定位置绘制一个200x440大小的矩形作为方块活动区域,在窗口右上角绘制下一个方块的预览图,在窗口右下角显示成绩、等级、按键提示信息。

 

   3)方块左右移动功能设计

       方法名:moveRight()

        输入:curPiece 正在下落的方块

        输出:curPiece 正在下落的方块

        过程:如果正在下落的方块能够向右移动一下就移动,否则原地不动。如果没有超出边界或者没有压住另外一个方块,就可以移动。

                  如果移动成功,方块的x坐标要加上一个SIZE,gridX坐标则加1。

        算法:

               1)将gridX的坐标先尝试加1;

               2)检测方块的各个小方格坐标是否超出边界或是碰上了已有的方块;

               3)如果没有就更新方块坐标,否则方块坐标保持不变。

 

      4)下落功能设计

        方法名:drop()

   输入:curPiece 正在下落的方块

        输出:curPiece 正在下落的方块

        过程:如果方块能够向下移动一下就移动,否则原地不动。如果没有超出边界或者没有压住另外一个方块,就可以移动。

                  如果移动成功,方块的y坐标要加上一个SIZE,gridY坐标则减1。

        算法:

               1)将gridY的坐标先尝试减1;

               2)检测方块的各个小方格坐标是否超出边界或是碰上了已有的方块;

               3)如果没有就更新方块坐标,否则方块坐标保持不变。

 

       5)旋转功能设计

        方法名:rotate()

   输入:curPiece 正在下落的方块

        输出:curPiece 正在下落的方块

        过程:如果方块能够顺时针旋转90度就旋转,否则原地不动。如果没有超出边界或者没有压住另外一个方块,就可以旋转。

                  如果旋转成功,方块的各小方格内部x坐标变成原来的-y坐标,内部y坐标变成原来的x坐标。

        算法:

               1)将方块的各小方格坐标预先做变换;

               2)检测方块的各个小方格坐标是否超出边界或是碰上了已有的方块;

               3)如果没有就更新方块各小方格坐标,否则保持不变。

 

6)方块状态检测功能设计

        方法名:changeStatus()

   输入:curPiece 正在下落的方块

        输出:curPiece 正在下落的方块

        过程:如果方块能够向下移动就返回,否则将方块停止状态变量设置为真,如果游戏没有结束就统计成绩,然后更新方块位置纪录数组,最后检测是否可以消行,如果能消行就再次更新方块位置纪录数组实现消行。

        算法:

               1)使用tryMove()函数检测是否能下落,如果不能将stoped状态变量设置为true,否则返回;

               2)在stoped为true时,如果isStarted状态变量为真就进入pieceDroped()函数;

               3)在pieceDroped()函数中先更新方块位置纪录数组board[]数组,将刚刚停止的方块“登记在册”,然后进入主类中的removeFullLines()函数;

               4)在removeFullLines()函数中通过board[]数组先检查是否有满行的情况,有则再次更新board[]数组实现消行;

               5)更新成绩和等级以及相关变量的值。

 

五. 总结

      本次设计有以下几个地方值得一提:

  1) 设计思路为自顶向下,框架就是TetrixBoard类和TetrixPiece两个类,一个类相当于一个模块,所以需要提高模块的内聚性,减少模块的耦合性,特别要尽量避免一个模块同多个模块之间的耦合,因此就本例来说,设计的类少一些更适合。

  2)实现思路为迭代设计,TetrixBoard类和TetrixPiece两个类的属性和方法可以逐步添加。

  3)为了避免屏幕闪烁,这里使用了java的双缓冲绘图技术(update()函数),其原理是先在内存中分配一个和我们动画窗口一样大的空间(缓冲区),然后利用getGraphics()方法去获得双缓冲画笔,接着利用双缓冲画笔在缓冲区中绘制我们想要的东西,最后将缓冲区一次性的绘制到窗体中显示出来,这样在我门的动画窗口上面显示出来的图像就非常流畅了。

  4)在方块的移动,旋转,下落,以及消行中用到了一个非常重要的函数tryMove(),原理是利用方块的内部坐标计算出在假想位置的方块的各小方格的网格坐标,然后判断是否越界或是已被其他方块占据,这也是为什么使用三套坐标的原因,窗口坐标用于绘图,网格坐标和内部坐标用于逻辑判断。

  5)方块形状数组的设计是一个三维数组,第一维是方块形状,第二维是方块内部的四个小方格的序号,第三维是小方格的横坐标和纵坐标,每个方块的内部原点坐标是(0,0),这样旋转时便于坐标变换。另外方块的形状和颜色是一一对应的,便于在重绘已经落下的方块时同时获取形状和颜色。

 

 

附录:源代码

     TetrixPiece.java

package tetris;
import java.util.Random;
import java.lang.Math;
import java.awt.event.*;
import java.awt.*;

public class TetrixPiece { //TetrisClient的引用 TetrixBoard tb; // 定义落下的方块的形状,包含NoShape public static int NoShape = 0, ZShape = 1, SShape = 2, LineShape =3, TShape = 4, SquareShape = 5, LShape = 6, MirroredShape = 7; public static int[][][] coordsTable = { { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, { { 0, -1 }, { 0, 0 }, { -1, 0 }, { -1, 1 } }, { { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } }, { { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } }, { { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } }, { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }, { { -1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } }, { { 1, -1 }, { 0, -1 }, { 0, 0 }, { 0, 1 } } }; // 大小 public static final int SIZE = 20; // 下落的补偿 public static final int SPEED = 20; // 是否停止 public boolean stoped = false; // 是否按下向下键 public boolean speedup = false; // 出现的位置,包括绝对位置和网格坐标 public int x, y; public int gridX, gridY; private Color color = null; // 颜色数组 public static Color[] colorArr = { new Color(255,20,147), new Color(0,0,139), new Color(139,0,0), new Color(128,128,0), new Color(56,94,15), new Color(0,128,128), new Color(139,101,8), new Color(255,99,71) }; // 声明形状变量 private int pieceShape; // 声明方块类的坐标变量,右四个小方块的相对坐标组成 private int coords[][] = new int[4][2]; // 构造函数 public TetrixPiece(TetrixBoard tb) { this.tb = tb; setRandomShape(); } // 随机设定方块类的形状 public void setRandomShape() { Random r = new Random(); int shapeIndex = r.nextInt(7) + 1; setShape(shapeIndex); } // 设定方块类的指定形状 public void setShape(int shape) { // 设定方块对象的各小方块的坐标 for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; ++j) coords[i][j] = coordsTable[shape][i][j]; } // 设定方块对象的形状 pieceShape = shape; this.color = colorArr[shape]; gridX = TetrixBoard.GRID_WIDTH / 2 + 1; gridY = TetrixBoard.GRID_HEIGHT - 1 + minY(); x = TetrixBoard.CORRECT_X + gridX * SIZE; y = TetrixBoard.CORRECT_Y + (TetrixBoard.GRID_HEIGHT - 1 - gridY) * SIZE; } // 读取指定的小方块的x坐标 public int x(int index) { return coords[index][0]; } // 读取指定的小方块的y坐标 public int y(int index) { return coords[index][1]; } // 方块类的最小x坐标 public int minX() { int min = coords[0][0]; for (int i = 1; i < 4; ++i) min = Math.min(min, coords[i][0]); return min; } // 方块类的最大x坐标 public int maxX() { int max = coords[0][0]; for (int i = 1; i < 4; ++i) max = Math.max(max, coords[i][0]); return max; } // 方块类的最小y坐标 public int minY() { int min = coords[0][1]; for (int i = 1; i < 4; ++i) min = Math.min(min, coords[i][1]); return min; } // 方块类的最大y坐标 public int maxY() { int max = coords[0][1]; for (int i = 1; i < 4; ++i) max = Math.max(max, coords[i][1]); return max; } // 画出下一个方块 public void drawNewPiece(Graphics g) { g.setColor(color); for(int i=0; i<4; i++) { Graphics2D g2 = (Graphics2D)g; g2.setStroke(new BasicStroke(3.0f)); g2.drawRect(300 + x(i) * SIZE, 100 + y(i) * SIZE, SIZE-5, SIZE-5); g.fillRect(300 + x(i) * SIZE + 4, 100 + y(i) * SIZE + 4, SIZE - 12, SIZE - 12); } } // 画出当前方块 public void draw(Graphics g) { g.setColor(color); for(int i=0; i<4; i++) { Graphics2D g2 = (Graphics2D)g; g2.setStroke(new BasicStroke(3.0f)); g2.drawRect(x + x(i) * SIZE, y + y(i) * SIZE, SIZE-5, SIZE-5); g.fillRect(x + x(i) * SIZE + 4, y + y(i) * SIZE + 4, SIZE - 12, SIZE - 12); } } // 下落方法 public void drop() { if(tryMove(gridX , gridY - 1) && !stoped) { y += SPEED; gridY -= 1; tb.dropHeight++; } } // 检测当前状态 public void changeStatus() { if (!tryMove(gridX, gridY -1)) { stoped = true; if(tb.isStarted) pieceDropped(); } } // 累积掉落块的次数并累计成绩 public void pieceDropped() { //纪录已停止方块的位置信息 for (int i = 0; i < 4; ++i) { int x = gridX + coords[i][0]; int y = gridY - coords[i][1]; tb.board[x + y * TetrixBoard.GRID_WIDTH] = pieceShape; } // 检测是否可以消行 tb.removeFullLines(); ++tb.numPiecesDropped; if (tb.numPiecesDropped % 25 == 0) { ++tb.level; } tb.score = tb.numPiecesDropped * 2 + tb.dropHeight; } // 方块类向左旋转90度 public void rotate() { // 方块为田字形则直接返回TetrixPiece对象 if (pieceShape == SquareShape || stoped) return ; // 假定可以选择并修改坐标 for (int i = 0; i < 4; ++i) { int temp = coords[i][0]; coords[i][0] = -coords[i][1]; coords[i][1] = temp; } // 如果旋转测试失败则改回原来的坐标 if(!tryMove(gridX, gridY)) { for (int i = 0; i < 4; ++i) { int temp = coords[i][0]; coords[i][0] = coords[i][1]; coords[i][1] = -temp; } } } // 向左移动 public void moveLeft() { if(tryMove(gridX - 1, gridY) && !stoped) { x -= SIZE; gridX -= 1; } } // 向右移动 public void moveRight() { if(tryMove(gridX + 1, gridY) && !stoped) { x += SIZE; gridX += 1; } } public boolean tryMove(int newX, int newY) { for (int i = 0; i < 4; ++i) { int x = newX + x(i); int y = newY - y(i); if (x < 0|| x >= TetrixBoard.GRID_WIDTH || y < 0 || y >= TetrixBoard.GRID_HEIGHT ) return false; if (tb.board[x + y * 10] != NoShape) return false; } return true; } // 按键事件 public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if(key == KeyEvent.VK_Q){ //退出当前的Java进程 System.exit(0); } //如果暂停并且按键是[C]就继续动作 if(tb.isPaused){ if(key==KeyEvent.VK_C) tb.isPaused = false; return; } switch(key) { case KeyEvent.VK_LEFT: moveLeft(); tb.repaint(); break; case KeyEvent.VK_RIGHT: moveRight(); tb.repaint(); break; case KeyEvent.VK_SPACE: rotate(); tb.repaint(); break; case KeyEvent.VK_DOWN: speedup = true; tb.repaint(); break; case KeyEvent.VK_P: tb.isPaused = true; } } // 按键事件 public void keyReleased(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_DOWN) { speedup = false; } } }

 

 TetrixBoard.java

  

package tetris;
import java.awt.*;
import java.awt.event.*;
import java.awt.Font; public class TetrixBoard extends Frame { // 声明变量,窗口位置 int x = 100; int y = 100; // 方块运动窗口为15x20格,以数组纪录其被窗口填充状况 public int board[] = new int [220]; // 下落次数 public int dropHeight = 0; public int numPiecesDropped = 0; // 移除的行数 public int numLinesRemoved = 0; // 开始游戏 public boolean isStarted = true; // 暂停 public boolean isPaused = false; // 总成绩 public int score = 0; // 当前等级 public int level = 0; // 程序窗口大小 public static final int WIDTH = 400; public static final int HEIGHT = 500; // 游戏区域起始坐标 public static final int CORRECT_X = 20; public static final int CORRECT_Y = 30; //游戏区域大小 public static final int RECT_WIDTH = 200; public static final int RECT_HEIGHT = 440; //游戏区域网格大小 public static final int GRID_WIDTH = 10; public static final int GRID_HEIGHT = 22; //双缓冲刷新用到的变量 Image offScreenImage = null; // 声明一个TetrixPiece对象 TetrixPiece newPiece = null; TetrixPiece curPiece = null; // 设定文本字体 Font mf = new Font("TimesRoman", Font.ITALIC, 18); public void launcher() { // 出现位置 this.setLocation(x,y); // 大小 this.setSize(WIDTH, HEIGHT); // 启动线程前先生成一个TetrixPiece实例 curPiece = new TetrixPiece(this); newPiece = new TetrixPiece(this); //启动刷新线程 new Thread(new paintThread()).start(); // 可见性 this.setVisible(true); // 窗口标题 this.setTitle("Tetris Game"); // 不可调整 this.setResizable(false); // 布局管理 this.setLayout(null); // 背景颜色 this.setBackground(new Color(240,255,240)); // 添加窗口监听器 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); // 清空窗格 this.clearBoard(); // 添加按键事件监控 this.addKeyListener(new keyMonitor()); } // 屏幕双缓冲避免屏闪 public void update(Graphics g) { // 在内存中开辟一个与当前窗口大小一致的空间 if(offScreenImage == null) { offScreenImage = this.createImage(WIDTH, HEIGHT); } //建立Graphics对象,把要绘制的对象存放在分配好的内存空间 Graphics gOffScreen = offScreenImage.getGraphics(); Color c = gOffScreen.getColor(); //设定内存对象背景颜色 gOffScreen.setColor(new Color(240,255,240)); gOffScreen.fillRect(0, 0, WIDTH, HEIGHT); gOffScreen.setColor(c); //绘制窗口到内存对象中 paint(gOffScreen); //将内存对象一次性绘制到当前窗口,消除屏闪 g.drawImage(offScreenImage, 0, 0, null); } // 画出一个指定颜色和位置的小方块 public void drawSquare(Graphics g, int x, int y, int Shape) { g.setColor(TetrixPiece.colorArr[Shape]); Graphics2D g2 = (Graphics2D)g; g2.setStroke(new BasicStroke(3.0f)); g2.drawRect(x, y , TetrixPiece.SIZE-5, TetrixPiece.SIZE-5); g.fillRect(x + 4, y + 4, TetrixPiece.SIZE - 12, TetrixPiece.SIZE - 12); } @Override public void paint(Graphics g) { Color c = g.getColor(); // 设定红色画笔画框 g.setColor(Color.MAGENTA); g.drawRect(CORRECT_X - 2 , CORRECT_Y, RECT_WIDTH, RECT_HEIGHT); // 设定文本颜色 g.setColor(new Color(70,130,180)); g.setFont(mf); g.drawString("Score : "+score, 260,200); g.drawString("Level : "+level, 260,240); g.drawString("Pause : 'p'", 260, 280); g.drawString("Continue : 'c'", 260, 320); g.drawString("Quit : 'q'", 260, 360); // 重新设回原来的颜色 g.setColor(c); curPiece.draw(g); //curPiece.changeStatus(); newPiece.drawNewPiece(g); // 因定时器产生的重绘向下走一格,若只是旋转不应下降故此处移除 //if(!curPiece.stoped) // curPiece.drop(); // 重画已下落的方块 for (int i = 0; i < GRID_HEIGHT; ++i) { for (int j = 0; j < GRID_WIDTH; ++j) { int shape = board[j + (GRID_HEIGHT - i - 1) * GRID_WIDTH]; if (shape != TetrixPiece.NoShape) drawSquare(g, CORRECT_X + j * TetrixPiece.SIZE,CORRECT_Y + i * TetrixPiece.SIZE, shape); } } // 为防止消行时最后下落块没有及时重绘,此句放到最后 curPiece.changeStatus(); } // 刷新类 private class paintThread implements Runnable { @Override public void run() { while(true) { repaint(); if(!curPiece.stoped && !isPaused) curPiece.drop(); //触底后再生成一个Shape实例 if(curPiece.stoped && isStarted && !isPaused) { curPiece = newPiece; // 如果当前Shape实例不能移动则停止游戏 if(!curPiece.tryMove(curPiece.gridX, curPiece.gridY)) isStarted = false; newPiece = new TetrixPiece(TetrixBoard.this); } try{ //向下键是否被按下 if(!curPiece.speedup) { Thread.sleep(1000/(level + 1)); } else Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } // 按键事件内部类 private class keyMonitor extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { curPiece.keyPressed(e); } @Override public void keyReleased(KeyEvent e) { curPiece.keyReleased(e); } } // 窗格清空 public void clearBoard() { for (int i = 0; i < 220; ++i) board[i] = TetrixPiece.NoShape; } // 检测是否可以消行 public void removeFullLines() { int numFullLines = 0;      // 是否可以消行 for (int i = GRID_HEIGHT - 1; i >= 0; --i) { boolean lineIsFull = true; for (int j = 0; j < GRID_WIDTH; ++j) { if (board[j + i * GRID_WIDTH] == TetrixPiece.NoShape) { lineIsFull = false; break; } }        // 可以消行则更新方块位置纪录数组 if (lineIsFull) { ++numFullLines; for (int k = i; k < GRID_HEIGHT - 1; ++k) { for (int j = 0; j < GRID_WIDTH; ++j) board[j + k * GRID_WIDTH] = board[j + (k + 1) * GRID_WIDTH]; } for (int j = 0; j < GRID_WIDTH; ++j) board[j + (GRID_HEIGHT - 1) * GRID_WIDTH] = TetrixPiece.NoShape; } } // 消行后更新成绩 if (numFullLines > 0) { numLinesRemoved += numFullLines; score += 10 * numFullLines; //isWaitingAfterLine = true; curPiece.setShape(TetrixPiece.NoShape); } } public static void main(String[] args) { new TetrixBoard().launcher(); } }

 

posted on 2018-12-15 14:08  剑胆琴心2015  阅读(5483)  评论(0编辑  收藏  举报