4 系统的概要设计
4.1 系统的功能设计
4.1.1 手动处理业务的基本流程
本游戏的设计以娱乐为初衷,以益智为目的,在综合研究以往俄罗斯方块经典游戏功能的基础上推陈出新,加之新的功能,赋以新的生机和活力。以下具体阐述游戏的基本流程。
运行说明:
1>运行程序,点击右侧控制面板内的“开始”或“控制”菜单内的“开始”按钮开始游戏。
2>使用上、下、左、右键和空格键,P键,C键控制方块的变形、下落、向左和向右移动和一键迅速下落,暂停,继续。
3>方块满行消除,分数自动增加,等级自动增加一级。
4>等级增加、方块下落速度增加,按右侧控制面板或“游戏”菜单内的“初级”“中级”,“高级”按钮来手动改变游戏难易程度。也可点击“方块颜色”菜单内的选项,更改方块颜色等,也可以通过“自定义”菜单内的选项,来更改游戏的一些属性。
5>按键盘键字母P键可以控制游戏暂停,然后按子母键C键可以控制游戏继续上次游戏。按“结束游戏”按钮,游戏会彻底停止正在进行的当局游戏,再按“开始”或“控制”菜单内的“重新开始”会开始新游戏。
6>当方块占满整个窗口,不能再有新方块下落时,游戏会弹出“Game Over”的对话框提示游戏结束。
游戏的基本流程图如图4—1所示:
图4-1游戏的基本流程图
4.1.2 基本流程的功能模块
本系统基于游戏的各项功能来设计游戏的各个功能模块。图4-2为本游戏的系统功能模块示意图,如图所示,本游戏主要有两大模块:游戏界面区,游戏控制区。游戏界面区分显示玩家可选操作、显示玩家操作结果两个部分。游戏控制区分更改颜色、开始、更改游戏等级为初级、更改游戏等级为中级、更改游戏等级为高级、自定义下落速度、更改背景、退出以及其他等一些功能模块。
图4-2系统功能模块示意图
图4-3为游戏界面区模块设计示意图,如图所示,游戏界面区模块可细分为闯进新游戏界面、处理玩家操作、显示玩家操作结果三个功能模块。
图4-3界面模块示意图
图3-4为游戏控制区设计示意图,如图所示,游戏控制区模块分为开始、自定义操作设置、初始游戏级别设置、初始颜色设置、退出等功能模块。
5 系统的详细设计与实现
Java是一种纯面向对象(Object-Oriented)的程序语言,它的诸多优点在此就不作详细论述了。从面向对象的观念出发,本程序主要可分为以下几个模块:
●游戏主界面显示模块
●方块及数据显示模块
●方块移动控制模块
●游戏界面颜色控制模块
●游戏进度、等级控制模块
分析对象的技巧在于它的功能的扩展性及维护效率。试想,如果因为外部环境或者用户需求的变化需要对程序进行功能扩展或者维护,就要对代码作大幅度的更动甚至重写,这样就失去了面向对象的优势,所以在本程序分析时将独立性高的模块作为一个对象,以提高程序的可扩展性和可维护性。以下该游戏中类的设计:
MyFrame类:继承自JFrame类,作为游戏的主类,负责对游戏的主体全局进行控制,连接与指挥各个类的枢纽。
PreView类:继承自JPanel类,作为操作面板类,负责安放主游戏窗口,积分板,级别控制按钮等窗口用以控制游戏进程。
GameCanvas类:继承自JPanel类,ChangeBlockColor线程类动态改变画布类的方格颜色,画布类通过检查方格颜色来体现ChangeBlockColor方块的移动情况与消去状况。
Box类:方格类,组成方块的基本元素,主要表达方式为颜色。
Block类:作为操控方块的类,控制方块的移动,下落以及变形。
5.1 游戏主界面显示模块
一个优秀的软件系统不仅体现在核心的功能的多样性和强大上,如果使用者所面对的是枯燥的、陈旧的界面的话,那么这个的软件系统是不成功的,所以好的、精美的界面设计是极为重要的环节。为玩家设计制作布局合理、视觉效果良好的界面的重要性就不言而喻了。
游戏主界面采用Swing组件开发,并且向其注册监听器,以实现各种控制功能,综合游戏窗体的设计,其上至少需要注册三个监听器,分别是动作监听器(ActionListener)、键盘监听器(KeyListener)、选项监听器(ItemListener)。
根据初步设计,可以确定客户端上所要用到的Swing组件对象有JFrame对象、JPanel对象,JLabel对象、JButton对象、JMenuBar对象、JMenu对象、JMenuItem对象、JTextField对象、JTextArea对象、JDialog对象等,至少十个Swing组件对象。下图5-1为游戏主界面截图。
图5-1游戏主界面截图
本游戏主界面设计的初始颜色搭配基于对比鲜明的原则,默认背景色为深绿色,左上角设置俄罗斯方块图标,得分初始值为0,等级初始值为1,最高分记录初始值为0。游戏主窗体尺寸设置为(520,580),方块移动范围窗格由一个20行、12列的二维数组控制,且左上角图标设置为方块图案,起标识作用。
5.2 画布、方块显示模块
本游戏中将画布设计为自定义图片,可以根据自己的需求来自己动手更改背景图片,在方块下落过程中,根据颜色的变化识别下落的方块。
5.2.1 背景画布模块设计
该游戏的主背景画布是一个20行、12列的二维数组,方块显示是由相应颜色变化来标识,主窗体用颜色填充后可形成呈现出来背景样式和方块。本游戏用继承自JPanel的GameCanvas类控制背景画布的显示,用rows代表画布的行数,cols代表画布的列数,行数和列数决定着画布拥有方格的数目。背景画布主要实现代码如下:
首先,用一个画布类的构造函数来表示整个主界面的行数、列数以及主界
中的相对位置:
/**
* 画布类的构造函数
* @param rows int, 画布的行数
* @param cols int, 画布的列数
* 行数和列数决定着画布拥有方格的数目
*/
public GameCanvas(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.setOpaque(false);
boxes = new Box[rows][cols];
for (int i = 0; i < boxes.length; i++) {
for (int j = 0; j < boxes[i].length; j++) {
boxes[i][j] = new Box(false);
}
}
setBounds(0, 0, 300, 500);//设置相对位置坐标
setBorder(new EtchedBorder(
EtchedBorder.RAISED, Color.white, new Color(148, 145, 140)));
}
/**
* 取得画布中方格的行数
* @return int, 方格的行数
*/
public int getRows() {
return rows;
}
/**
* 取得画布中方格的列数
* @return int, 方格的列数
*/
public int getCols() {
return cols;
}
其次,在设置一个画布类的构造函数来表示整个主界面的前景色,背景色并获取其前景色和背景色:
/**
* 画布类的构造函数
* @param rows 与public GameCanvas(int rows, int cols)同
* @param cols 与public GameCanvas(int rows, int cols)同
* @param backColor Color, 背景色
* @param frontColor Color, 前景色
*/
public GameCanvas(int rows, int cols,
Color backColor, Color frontColor) {
this(rows, cols);
this.backColor = backColor;
this.frontColor = frontColor;
}
/**
* 设置游戏背景色彩
* @param backColor Color, 背景色彩
*/
public void setBackgroundColor(Color backColor) {
this.backColor = backColor;
}
/**
* 取得游戏背景色彩
* @return Color, 背景色彩
*/
public Color getBackgroundColor() {
return backColor;
}
5.2.2 预览方块模块设计
方块和数据信息是游戏中最基本的功能模块。Box这个类方格类,是组成块的基本元素,用自己的颜色来表示块的外观 ,MyTask继承TimerTask类用来定时下落,用计数方式来实现速度的改变,MyListener类继承KeyAdapter类用来实现按键监听,控制方块的上下左右。定义一个4x4方阵,共16个小格。用“0”和“1”来表示每个方格是绘制新颜色还是保留底色。
每得到一个新方块,都是随机从七种形态的方块中选取一种。游戏定义了一个变量,代表新方块的模型。比如定义int型数组STYLE代表28中方块类型,7行4列,每个元素代表其中一种方块。即0<=blockkindnum<=6,0=<blockstatusnum<=3
那么,当方块落下需要得到新方块时,只需随机得到一对blockkindnum,blockstatusnum值,然后再根据这个STYLE的值构画相应的方块。剩下的问题就是应该怎么随机到一对STYLE行列值。
Java语言包中的Math类提供了一个生成随机数的方法random(),调用这个方法会产生一个在0-1之间的双精度浮点数。所以每次要得到新方块时,只需调用一次这个方法,得到一个0-1的双精度浮点数,然后用该数乘以7,之后强转成整型,即可得到1—7的整数,用来控制行。用该数乘以4,之后强转成整型,即可得到1—4的整数,用来控制列。
由此可以组合出多种图形定义然后用代码实现下列功能:
1>每次执行首先为随机数产生不同的初值。
int col = (int) (Math.random() * (gc.getCols() - 3));//随即位置生成列
int style = Constant.STYLES[(int) (Math.random() * Block.get_addl())][(int) (Math.random() * 4)];
图5-2随机产生方块流程图
2>随机选取一个图形,图5-2随机产生方块图具体描述用生成的随机数控
产生的图形。
3>当前图形在其4*4网格中的位置信息。
绘制4行4列的方块预显方格,随机生成预显示的方块样式。本游戏用二维数组存储方块的28种样式。
值得注意的是:在传统的俄罗斯方块游戏的基础上,本游戏系统为了体现出创新的思维,本着为了学习的原则,在传统游戏的基础上增加了中级三种其他的方块样式和高级三种其他的方块样式。一共有52种方块样式,具体的存储方式主要实现代码如下:
/**
* 分别对应对13种模型的52种状态
*/
public final static int[][] STYLES = {// 共28种状态
{0xf000, 0x8888, 0xf000, 0x8888}, // 长条型的四种状态
{0x4e00, 0x4640, 0xe400, 0x4c40}, // 'T'型的四种状态
{0x4620, 0x6c00, 0x4620, 0x6c00}, // 反'Z'型的四种状态
{0x2640, 0xc600, 0x2640, 0xc600}, // 'Z'型的四种状态
{0x6220, 0x1700, 0x2230, 0x7400}, // '7'型的四种状态
{0x6440, 0xe200, 0x44c0, 0x8e00}, // 反'7'型的四种状态
{0x6600, 0x6600, 0x6600, 0x6600}, // 方块的四种状态
{0x8c88,0xf200,0x44c4,0x4f00},//增加的中级样式方块3个
{0xea00,0xc4c0,0xae00,0xc8c0},
{0x8c00,0xc800,0xc400,0x4c00},
{0xac00,0xcc40,0x6e00,0x8cc0},//增加的高级样式方块3个
{0x4e40,0x4e40,0x4e40,0x4e40},
{0x8480,0xa400,0x4840,0x4a00},
};
传统俄罗斯方块游戏的7种方块样式,相信很多人都知道,在这里就不一一截图展示常见的方块样式。以下是在传统游戏的模式下增加的三种中级难度和三种高级难度的方块模型:
5.2.3 方块移动、旋转模块设计
方块的翻转与移动比较容易实现,方块移动只需要改变方块的横坐标或纵坐标,然后重新绘制方块即可。方块翻转也只需要改变背景数组的值,重新绘制方块即可。
本游戏方块下落时,进行动态绘制,实现Cloneable接口, 以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。方块的操作类BlockOperation继承Thread类,重写run()方法,以实现方块的动态正确下落。当然,在线程中要判定方块是处于moving状态还是pausing状态。
publicvoid run()
{
//moving判定方块是否在动态下落
while (moving)
{
try
{
//betweenleveltime指示相邻等级之间相差时间
sleep(betweenleveltime
* (ControlMainGame.maxlevel - level + flatgene));
} catch (InterruptedException ie)
{
ie.printStackTrace();
}
//pausing判定游戏是否处于暂停状态
if (!pausing)
moving = (moveTo(y + 1, x) && moving);
//moving是在等待的100毫秒间,moving没被改变
}}
当然,在游戏中还要判定方块移动的边界问题, 比如,一个方块在它左边正好差一个格子的空间才能够翻转,但是它的右边恰好有一个格子的空间,这种情况,如果方块不能够翻转,就不方便用户操作,如果能够翻转,就会发生越界,将已经存在的方块挤占掉。要想实现翻转又不发生越界,那么,就应该在方块翻转后把它往右边移动一个格子,然后再绘制方块,这样,方块就不会挤占掉其它已经固定住的方块了,以下解决越界问题。
1>方块翻转判定
在两种情况可能发生越界,一种是方块落下去固定住以后,第二种是周围的空间不允许它进行翻转。
第一种情况只需要参考方块落下去后不能够再移动的判定即可。
对于第二种情况,在每次方块翻转前,必须首先计算出方块周围的空间,如果空间允许则翻转。否则,不能翻转。
因为七种方块是不规则的,每种方块要求的翻转空间都是不一样的,甚至是在它的不同翻转状态下,所要求的翻转空间也是不一样的,首先想到的自然就是为每一种方块,方块的每一种状态都写一个判定条件,但是这样做未免过于麻烦。
根据观察,不难发现,七种形态的方块,长条形的方块如果以横条的形态下落,则只要能够下落,就能翻转,如果以竖条的形态下落,那么它翻转后所处的位置必须要有4x1个格子的空间才能够翻转。对于田字形的方块,只有能够继续下坠,就一定能够翻转,所以田字型的方块只要没有落下,就一直能够翻转。而其它五种形态的方块,又有一个共同点,就是它们都有两种翻转状态横向占三个格子的空间,竖直方向占两个空间,另外两种翻转状态横向占两个格子的空间,竖直方向占三个格子空间,如果他们是以横向占三个格子的状态下落,那么只要能下落,就一定能够翻转,如果是以横向两个格子的状态下落,那么在翻转后,周围必须要有3x2个格子的空间。
所以,方块翻转的判定,要分三种情况,第一种情况是方块落下去后不能翻转;第二种情况是对竖直状态出现的长条形的方块进行翻转判定;第三种情况是对除长条形和田字形之外的其它五种以横向占两个格子的状态出现的方块进行翻转判定。
何种情况下方块能够翻转的问题解决了,接下来,我们就应该解决方块翻转后所处的位置的问题了,因为只有事先知道方块翻转后所处的位置,才能够对那个位置的空间范围进行判定,判定它是否能够容纳方块。
可以确定的是,无论方块怎么翻转,都处在方块数组中,也就是说方块必定是在游戏地图中某一4x4个格子的空间范围内。
方块数组在游戏主界面中的坐标是确定的,不确定的是方块翻转后到底处在方块数组的哪个位置,为了解决这个问题,我们可以限定方块在方块数组中的存储原则是靠左、靠上,这样,无论翻转怎么翻转,方块数组中第一行和第一列都是有方块的,这样也就确定了方块在方块数组中的位置,也就可以得知方块翻转后在游戏地图中的位置了。
假定方块数组的横纵坐标是x和y,那么,这个位置就是,长条形的方块翻转后所处的那一行是游戏地图的第y行,所占的列是第x到x+3列,长条形和田字形以外的五种方块翻转后的所占的行数是游戏地图的第y和第y+1行,所占的列是第x到x+2列。
所以,如果以上空间有空格子,方块就能够翻转。
2>翻转越界纠正
只要方块翻转后所处的空间足够,方块就能够翻转,但是,如果方块翻转后所处的空间不足够,而在它的另一边却有足够的空间呢?
方块在边界处时,翻转后不仅可能翻出地图外,还可能发生数组越界,当然,只需要将地图数组定义得大一些,就能够避免数组越界错误,对于方块越界,如果在它的另一边有足够空间,那么,就应该把方块往另一个方向移动适当的单位,纠正方块越界错误。如图5-12方块翻转流程图所示,方块翻转需要经三次判定:是否已经下落到底部、翻转后是否有足够空间、翻转后是否越界。
图5-12 方块翻转处理流程图
玩家操作键盘实现方块的移动、旋转,代码引进ControlKeyListener类继承KeyAdapter类进行键盘监听功能的实现。KeyAdapter类继承自Object类,实现KeyListener接口,用来接收键盘事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。扩展此类即可创建 KeyEvent 侦听器并重写所需事件的方法,即是 ControlKeyListener类。使用ControlKeyListener可创建侦听器对象,然后使用组件的 addKeyListener 方法向该组件注册此侦听器对象。当按下、释放或键入某个键时,将调用该侦听器对象中的相应方法,并将 KeyEvent 传递给相应的方法。实现代码如下:
privateclass ControlKeyListener extends KeyAdapter
{
publicvoid keyPressed(KeyEvent ke)
{
if (!game.isPlaying())
return;
BlockOperation blockope = game.getCurBlock();
switch (ke.getKeyCode())
{
case KeyEvent.VK_DOWN:
blockope.moveDown();
break;
case KeyEvent.VK_LEFT:
blockope.moveLeft();
break;
case KeyEvent.VK_RIGHT:
blockope.moveRight();
break;
case KeyEvent.VK_UP:
blockope.turnNext();
break;
default:
break;}}}
5.3 控制面版模块
5.3.1 菜单栏模块设计
菜单栏中有“游戏”、“帮助”四个菜单选项。“游戏”选项又分“开局”、“初级”、“中级”、“高级”、“自定义”、“方块颜色”、“退出”等七个选项。“帮助”选项中有“关于”选项,用于显示游戏版本等信息。
1>“开局”的按钮功能为实现游戏画布的重新绘制,类似reset的功能。该按钮的监听实现代码如下:
/**
* 重置画布
*/
public void reset() {
for (int i = 0; i < boxes.length; i++) {
for (int j = 0; j < boxes[i].length; j++)
boxes[i][j].setColor(false);
}
repaint();
}
2>“初级”、“中级”、“高级”按钮用来手动调节游戏的等级,从而改变游戏的等级难度。 “退出”按钮控制游戏随时退出,终止游戏。
3>“帮助”按钮中点击“关于”按钮显示与游戏软件本身相关信息,具体信息如图所示:
图4—19 “关于”选项截图
5.3.2 控制面板按钮设计
本游戏控制面板中包含得分统计、等级统计等字段。
其中的TextField控件均由游戏本身统计给出,玩家不能私自编辑。本游戏的游戏规则为每消一行得10分,每增加100分上升一个等级,初始得分为0,初始等级为1。
以下给出得分、等级更新等功能实现的主要代码:
/**
* 判断是否满行,满行则调用消行方法。
*/
private void isFullLine() {
// TODO Auto-generated method stub
for (int i = 0; i < 20; i++) {
int row = 0;
boolean flag = true;
for (int j = 0; j < 12; j++) {
if (!gc.getBox(i, j).isColorBox()) {
flag = false;
break;
}
}
if (flag == true) {
row = i;
gc.delete(row);//删除行
if(isMusic==true)
{mp.playEraseSound();}
addScor();//增加分数
if(scor%100==0)//设置为100分增加一个等级
upspeed=true;//将速度增加标志位至为true
if(upspeed==true)
upLevel();
}
}
}
/**
* 得分的计算方法
*/
private void addScor() {
scor=scor+10;
jt9.setText("得分:"+MyFrame.scor);
}
}
private void reset() {
scor=0;
rank=0;
jt10.setText("等级:"+rank);
jt9.setText("得分:"+scor);
upspeed=false;
playing=true;
runstop=false;
gc.setGameOver(false);
gc.repaint();
gc.reset();
}
控制面板中按钮的功能在4.3.1中已给出代码,在此不再赘述。
6 系统的测试运行
6.1 测试概述
系统测试,是将软件,计算机硬件,外围设备,网络等元素确认在一起进行各种信息系统的组装测试和确认测试,系统测试是为整个产品系统进行测试,目的是验证是否 系统满足需求规格的定义,找出与需求规格不一致或矛盾的地方,以提出更全面的方案。系统测试发现问题后,尝试找出错误的原因和位置,然后进行更正。 是基于黑盒子类测试的整体系统要求,应该覆盖系统的所有组件。 对象不仅包括要测试的软件,还包括软件依赖的硬件,外围设备甚至包括某些数据,一些支持软件及其接口。
系统测试是一个集成测试软件,作为计算机系统的一部分,结合系统的其他部分,在计算机系统的实际操作环境中进行一系列严格有效的测试,以找出软件潜在的问题,确保系统的正常运行。
系统测试的目的是验证最终软件系统是否符合用户要求。
主要内容包括:
(1)功能测试。也就是说,测试软件系统的功能是正确的,根据文档的要求,如《产品需求规格说明书》。 因为正确性是软件最重要的品质因素,因此功能测试至关重要。
(2)健壮性测试。也就是说,在异常情况下测试软件系统的能力是否正常运行。健壮性有两个含义:一个是容错,另一个是恢复能力。
6.1.1 测试原则
软件测试的基本原则,齐全的检测的产品用户的角度,尽可能多发现系统使用的问题过程中的问题和漏洞、研究和分析、在产品中,有缺陷的方面提出问题与改进建议。详细的测试原理如下:
(1)软件测试计划是软件测试的行动导向,实际的测试应该细心严格执行,高可行性的严格执行测试计划,特别是确定测试方法和测试目的。
(2)测试标准,建立基于用户需求,软件测试,主要目的是为了确保产品的一致性和验证产品能够满足客户的需求,所以在测试过程中应该在用户的角度始终站在看问题,并发现软件缺陷和不足所带来的影响,系统中最严重的错误无法满足用户需求的程序以及功能缺陷。
(3)不能随意对待测试。
尤其是对系统的测试,反复测试,如果不严格执行测试计划,很有可能会因为疏忽导致的新BUG的产生。因此,反复测试阶段也应给予充分重视,早期检测中有很多错误,大多是因为疏忽而没被发现。
目的:
(1)确保系统测试的活动正常进行;
(2)验证软件产品和系统要求不匹配或矛盾的情况;
(3)建立完善的系统测试缺陷跟踪数据库;
(4)确保软件系统的测试活动和结果及时通知相关团体和个人。
6.1.2 测试方法
为了全方位的测试系统,找出系统中存在的问题和故障,使用多种测试方法一起测试,可以更加全面的总结出系统设计的优缺点。采用的测试方法有以下几个:
功能测试:测试系统中各个功能模块下的功能点是否可以正常使用;
手动测试:主要测试输入、点击等各项功能;
黑盒测试:输入后查看得出的结果是否正确。
恢复测试:恢复测试作为系统测试,主要关注导致软件运行失败的各种条件,并验证恢复过程可以正常实施。 在某些情况下,系统需要具有容错能力。 此外,系统故障必须在规定的时间内更正,否则将导致严重的经济损失。恢复测试主要检查系统的容错能力。当系统出错时,能否在指定时间间隔内修正错误并重新启动系统。恢复测试首先要采用各种办法强迫系统失败,然后验证系统是否能尽快恢复。对于自动恢复需验证重新初始化(reinitialization)、检查点(checkpointing mechanisms)、数据恢复(data recovery)和重新启动 (restart)等机制的正确性;对于人工干预的恢复系统,还需估测平均修复时间,确定其是否在可接受的范围内。
安全测试:安全测试用于验证系统内的保护机制,防止非法入侵。 在安全测试中,测试人员扮演着试图入侵系统的角色,采用多种方式试图突破防线。 所以系统安全设计的标准是找出使入侵系统成本更高的方法。安全测试检查系统对非法侵入的防范能力。安全测试期间,测试人员假扮非法入侵者,采用各种办法试图突破防线。例如,①想方设法截取或破译口令;②专门定做软件破坏系统的保护机制;③故意导致系统失败,企图趁恢复之机非法进入;④试图通过浏览非保密数据,推导所需信息,等等。理论上讲,只要有足够的时间和资源,没有不可进入的系统。因此系统安全设计的准则是,使非法侵入的代价超过被保护信息的价值。此时非法侵入者已无利可图。
压力测试:压力测试是指在正常资源下使用异常流量,频率或数据量来实施系统。 以下试验可以在压力试验中进行:
①如果平均中断次数是每秒一到两次,那么特殊测试用例的设计每秒产生10次中断。
②将输入数据量增加一个数量级,以确定输入函数如何响应。
③在虚拟操作系统中,需要产生最大量的内存或其他资源的测试用例,或产生过多的磁盘存储数据。
一般的情况下,系统都要反复测试,因为在系统时间和功能的限制,所以系统不可能完美无缺。因此,有必要对各种测试方法一起检测。
强度测试
强度测试检查程序对异常情况的抵抗能力。强度测试总是迫使系统在异常的资源配置下运行。例如,①当中断的正常频率为每秒一至两个时,运行每秒产生十个中断的测试用例;②定量地增长数据输入率,检查输入子功能的反映能力;③运行需要最大存储空间(或其他资源)的测试用例;④运行可能导致虚存操作系统崩溃或磁盘数据剧烈抖动的测试用例,等等。
性能测试
对于那些实时和嵌入式系统,软件部分即使满足功能要求,也未必能够满足性能要求,虽然从单元测试起,每一测试步骤都包含性能测试,领测认为只有当系统真正集成之后,在真实环境中才能全面、可靠地测试运行性能系统性能测试是为了完成这一任务。性能测试有时与强度测试相结合,经常需要其他软硬件的配套支持。
6.1.3 测试意义及注意事项
软件测试是软件设计过程中极其重要的一个环节,是保证软件的质量的重要保障。测试的方法的好坏会直接影响到软件的好坏,进行软件测试可以找出其中的错误、不足并加以改进,从而得到一个高效、可靠的系统。
软件应从多角度进行测试和分析,这样才能找出其中错误的地方。测试的时间最好找一些与设计系统无关的人员,或者分析人员。因为在开发软件的时候,开发人员已经形成了自己的思维定势,在测试的时候始终受到这种思想的束缚,很难找出其中的错误而与设计无关的人员和那些分析人员很容易找出错误所在。
在程序调试过程中一定要耐心仔细,一个细微的错误将会导致整个功能不能实现导致浪费很多的时间去修改。应在以下几方面加以注意:
语法错误是经常碰到的错误。例如,命令拼写错误或传递给函数的参数不正确都将产生错误。语法错误可能导致不能继续编写代码。
2>逻辑错误
逻辑错误通常可能是潜在和难以检测的。当有因键入错误或程序逻辑流程引起的逻辑错误,可能会成功运行,但产生的结果却是错的。例如,当本应使用小于符号比较数值,但却使用了大于符号时,那么将返回不正确的结果。
3>运行时错误
运行时错误是在执行过程中指令试图执行不可能的动作而导致的,必须纠正运行时产生的错误,这样才能保证软件运行的可靠性。
本游戏在开发过程中采用了多种有效措施进行测试以保证软件质量,对本游戏进行了边界处旋转、方块翻转越界等方面的测试,极大的保证了软件质量和出错几率。但是系统中可能还存在着一些其他的错误和缺陷,因此,游戏必须要经过反复的运行测试,尽最大量将bug减到最少。
6.2 游戏代码、算法的测试
1>写get()方法时需要有返回值,但是程序中没有写return语句,使程序在编译时出现错误。解决方法是,在方法中加入return语句,返回相应的内容即可。
2>使用随机函数产生方块时没有给各个方块传入参数,编译不能通过。解决方法是,根据各个方块的构造传入相应的参数。
3>写T字形方块各方格的默认位置时,将控制方块位置的变量i,初始化为0,运行的结果是丁字形方块默认成了竖形方块。解决方法是,将变量i的初始化数值改为1,即可达到设计的效果。
4>运行程序时,统计的分数只是每一次消除满行后的分数,而以前的分数就会被覆盖,没有累计。解决方法是,将程序中的“score=”改为“score+=”,就可以使分数累加。
5>算法流程的错误主要集中在如何检测及消去方块,还有如何在通关之后对分数的累加进行处理,是否升级的判定这些方面,经过与同学的讨论以及参考资料,都最终得到了解决。
6.3 游戏界面菜单选项的功能测试
1>“游戏”菜单测试
表6.1游戏菜单测试用例
测试用例编号 | 测试项目名称 | 测试执行步骤 | 输出 | 测试结果 |
01 | “开局”按钮测试 | 点击“游戏”→“开局” | 游戏重置 | 成功 |
02 | “结束游戏”按钮测试 | 点击“游戏”→“结束游戏” | 游戏结束 | 成功 |
03 | “初级”按钮测试 | 点击“游戏”→“初级” | 游戏等级选择为初级 | 成功 |
04 | “中级”按钮测试 | 点击“游戏”→“中级” | 游戏等级选择为中级 | 成功 |
05 | “高级”按钮测试 | 点击“游戏”→“高级” | 游戏等级选择为高级 | 成功 |
06 | “自定义”按钮测试 | “自定义”按钮测试 | 弹出对话框,可以更改自定义信息 | 成功 |
07 | “下落速度”滑块测试 | 点击“游戏”→“自定义”→“下落速度” | 拖动滑块可更改方块下落速度 | 成功 |
08 | “方块形状”单选框按钮测试 | 点击“游戏”→“自定义”→“方块形状”单选框 | 可选择方块形状初级、中级、高级、来改变方块的形状 | 成功 |
09 | “方块是否自动上涨”选择框测试 | 点击“游戏”→“自定义”→“方块是否自动上涨”选择框 | 可勾选小方格,选中则方块自动上涨,不选中则方块不自动上涨 | 成功 |
10 | “游戏过程是否播放声音”选择框测试 | 点击“游戏”→“自定义”→“游戏过程是否播放声音”选择框 | 可勾选小方格,选中则游戏过程中播放声音,不选中则游戏过程中不播放声音。 | 成功 |
11 | “更换背景”选择框 | 点击“游戏”→“自定义”→“游戏过程是否播放声音”选择框 | 可勾选小方格,选中则更换游戏背景图片,不选中则不更换游戏背景图片 | 成功 |
12 | “确定”和“取消”按钮测试 | 点击“游戏”→“自定义”→“确定”或“取消”按钮 | 点击确定保存更改设置退出对话框,点击取消则不更改设置退出对话框 | 成功 |
13 | “方块颜色”按钮测试 | 点击“游戏”→“方块颜色” | 弹出对话框,可以更改方块颜色,HSB,RGB等自定义信息 | 成功 |
14 | “退出”按钮测试 | 点击“游戏”→“退出” | 退出游戏并关闭主界面窗口 | 成功 |
2>“帮助”菜单测试
表6.2 “帮助”菜单测试用例
测试用例编号 | 测试项目名称 | 测试执行步骤 | 输出 | 测试结果 |
15 | “关于”按钮测试 | 点击“帮助”→“关于” | 弹出对话框,提示游戏版本等信息 | 成功 |
6.4 按键事件的功能测试
表6.3按键事件功能测试用例
测试用例编号 | 测试项目名称 | 测试执行步骤 | 输出 | 测试结果 |
16 | 方块移动测试 | 游戏过程中,点击“左、右、下” | 方块正常移动,不会移出边界 | 成功 |
17 | 方块旋转测试 | 游戏过程中,点击“上”方向键 | 方块无边界和障碍物阻挡的情况下可反转 | 成功 |
6.5 方块的堆砌与消行功能测试
表6.4 方块的堆砌与消行功能测试用例
测试用例编号 | 测试项目名称 | 测试执行步骤 | 输出 | 测试结果 |
18 | 方块堆砌测试 | 当方块下落到最底面或与障碍物接触时 | 方块成功堆砌在底部 | 成功 |
19 | 方块消行测试 | 当出现满行现象时 | 所有满行被消除,方块依次下移 | 成功 |
20 | 游戏结束测试 | 当出现满屏现象时 | 弹出会话窗口,提示“Game Over” | 成功 |
6.6 测试结果
经过多种测试方法对系统各个方面、功能的测试多次测试,测试结果表明系统基本符合的整体设计要求,预期功能基本完成。系统基本可满足设计开发之初的要求,测试结束。不过整体功能还不够强大,创新方面做的稍微逊色,作为开发的第一个版本,游戏在功能、界面设计等很多方面还需要进一步完善。
结 论
在做毕业设计之前,我对Java相关的开发只是停留在理论知识的水平上,此次毕业设计让我明白“纸上得来终觉浅,绝知此事要躬行”的道理。缺乏实际的软件开发经验,是我给自己下的定论。通过这次毕业设计,我完成了俄罗斯方块游戏的全部开发任务。在整个开发过程中遇到了很多问题,如方块的绘制和变形、线程的创建问题、同步的控制、满行判断、消行的处理以及最高分数记录的功能实现,但最终都被我一一解决,对其中比较主要的几点体会总结如下:
第一,为了熟悉俄罗斯方块的相关功能和设计,我时常从各大游戏下载网站下载单机版俄罗斯方块游戏,并研究其中功能的实现和界面的设计,思考和查阅资料进行分析,经过逐步的设计与反复的修改论证,才完成了整个游戏的开发。
第二,在游戏设计过程中,我采用从粗到精的设计模式,从小到大测试的原则。先设计游戏框架,并逐层测试,而后再添加具体实现代码并逐步进行更细化的测试。设计过程中,经常会遇到难题,我会通过反复思考和测试,然后找出自己的错误并加以改正,再进行下一个步骤,确保万无一失,尽力减轻最后的调试工作量。
第三,毕业设计业可以作为一个不断学习新鲜事物的过程,从设计初的不懂到最后能够圆满完成,我体会到在实践中不断学习的重要性,这对于将来我走上工作岗位具有重要的教育意义。通过毕业设计的创作,我对Java这门课程有了更深一步的了解,也对我今后的就业之路打下了一定的基础。
毕业设计是我们作为学生学习阶段的最后一步,是基础知识和专业知识的综合应用,是一个全面的重新学习,然后改进过程,学生学习能力的过程和独立思考和工作能力也是一个培训,而毕业设计水平也反映了大学教育的综合水平,所以学校非常重视毕业设计这一环节,加强毕业设计工作和动员教育的指导。在大学学习过程中,毕业设计是我们社会参与实际工作的重要组成部分,也是为了我们学习和解决生活问题的能力,是学校生活和社会生活的转型。毕业设计完成后,我尝试研究设计和实践工作的有机结合。这更有利于我们增强自己的能力。
经过一段时间的努力,在一些同学和老师的帮助下,我终于完成毕业项目,这是一项重要任务。回想一下我们设计的过程,可以说是困难和容易共存的。其中,把大学学习的知识被纳入内部,其实对我来说,也是一个不小的挑战,而且也是一次大学的知识的考试。
在毕业设计的过程中遇到了很多困难,而且很多都是没有遇到过的问题,如果不是亲自做,可能很难在某种程度上找到自己所缺乏的知识,对我们来说,找到问题,到解决问题,这是最实际的。面对自身难以解决的问题,在获取一些信息的同时,在老师和学生的帮助下,这些问题可以解决,所以毕业设计顺利完成。据了解,该项目的知识依然非常深奥,所以我们不仅现在,在未来更是要继续探索。
理论与实践的结合不仅包括课堂参与的知识,还包括技能培训的结合,以及指导学生如何去理解并接触与社会相关的东西。学生毕业设计,在专业理论知识的指导下,可以通过多种方式解决一些实际问题。在设计过程中,学生可以运用理论知识进行实践,不仅要加深对专业理论知识的理解,而且要丰富和发展本书的理论知识,使之变成更高层次的经验、技能。由于现有的教学模式,理论知识和技能与生产实践有着严重的分离,学生无法学习课堂以外的知识,实际生产问题常常与学习无关,无法有效得到应用。通过合理选择课题,引导学生有意识地运用知识和技能体系进行分析思考,为有机地整合理论知识和实践做出贡献。
社会不断变化,目前社会正在转型发展,人才的要求也越来越高,利用眼光看待问题,学习创新,学习适应社会发展要求。在校外,进入社会,抓住今天的机遇,创造未来。老师的影响力和教授的知识,让我了解很多道理,以一定的创新精神去面对将来的挑战。
总之,对于这一次毕业设计,我感觉个人不但比以前更加熟悉了一些专业方面的知识,还锻炼了自己的动手能力,觉得收获颇丰。同时也会有一种小小的成就感,因为自己在这项任务进行的过程中努力过了。而在以后的实际工作中,我们也应该同样努力,不求最好、只求更好! 还有就是,想在此对于我的指导老师和同学们表示忠心的感谢,感谢他们在这毕业设计过程中给我的帮助!
程序无论是从技术还是功能上都基本地满足了用户的需求。但由于初次设计,功能不够完善,细节方面的设计还有不足。
这次的毕业设计,我受益匪浅,让我的思维方式更加缜密,能多个角度的看待、处理问题;知道遇到问题该如何去分析问题、解决问题。相信这些都会让我在以后的工作中受益无穷的。