《Java程序设计》实训报告——俄罗斯方块
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《Java程序设计》实训报告
——《俄罗斯方块》
一、实训任务及要求:
1.1、实训任务
1.运用Java实现小游戏的开发
2.了解Java开发项目的流程
3.掌握规划,设计,开发,测试的能力
1.2、实训要求
熟悉java的编程环境J2SDK,掌握Application 和Applet的程序结构,并能熟练编写和调试两类程序。
熟练使用各种常用类库。
理解JDK的事件处理机制,掌握java.awt 、javax.swing,javax.swing.event中的GUI标准组件的用法,学会合理运用布局策略、综合运用各种界面元素,编程构造满足应用需要的图形工作界面。
二、需求分析:
1.课程设计的目的和意义
俄罗斯方块游戏是一个经典的小游戏,由于它简单有趣,因而得到了广泛的流行,男女老幼都适合。
而俄罗斯方块游戏的设计工作复杂且富有挑战性,它包含的内容多,涉及的知识广泛,与图形界面联系较大,包括界面的显示与更新、数据收集等,在设计的过程中,必将运用到各方面的知识,这对于visualbasi语言设计者而言,是个很好的锻炼机会。
2.系统功能设计
1.本系统主要设计以下几种功能
2.1、游戏难度选择功能
3.游戏难度选择界面设置在程序运行开始时,一共有九种难度供玩家选择,每选一级难度,
都会相应地显示出代表该难度的图片。
开始时不设置任何默认的难度,如果玩家不选难度直接按“Enter”进入,将会弹出提示框,提示其先选难度再进入。
4.2、方块下落、变形功能
5.在整个俄罗斯方块游戏中,方块的设计是核心。
这里设计了一个方块类:Square( ),
用来生成方块以及实现块的左移、右移、向下、变形、重画、同步显示、初始化新块等。
6.3、自动升级功能
7.当分数累积到一定大小时,系统将自动为玩家提高难度。
这里设置了每消除10行方块,
就增加一级难度。
当难度增加的时候,方块会相应地改变颜色,以作为对玩家的提示。
8.4、游戏音乐功能
9.游戏开始音乐就自动播放,游戏暂停与结束时音乐相应消除。
10.5、获取帮助功能
11.这里设置了一个类,用来显示帮助,按F1键就能弹出窗口,显示游戏规则。
3.系统功能设计分析
1.俄罗斯方块游戏根据功能的不同,设置了如下12个类:Square, Command, GameArea,
GameSetting, GameOver, Help, ImagePanel, JieMian, MyPanel, MyTimer, PlayMidi, WinListener,每个类的描述如下:
2.1、Square,方块类。
这个类中定义了生成方块的方法,用二维数组int[][] pattern,存放7种方块的四种状态。
在构造方法中以随机的形式生成方块,同时提供了以下几种方法:reset( ),leftTurn( ),leftMove( ),rightMove( ),fallDown( ),assertValid(int t,int s,int row,int col),dispBlock(int s)。
分别实现方块的重画、翻转、左移、右移、下落、同步显示等功能。
2.2、Command,处理控制类。
这是一个实现ActionListener接口的类,主要处理点击按钮事件。
类中定义了三个int型变量:button_play,button_quit,button_pause,和一个boolean型的变量:pause_resume,并赋值。
在GameArea类中通过事件响应,在按钮执行方法中调用其值,使用switch语句,根据不同按钮不同的值,来响应不同的事件。
2.3、GameArea,游戏界面类。
GameArea继承了JFrame,是俄罗斯方块的主要游戏界面。
这个类定义了GameSetting类的gameScr对象和ImagePanel类的imagepanel对象作为游戏区域面板和控制区域面板。
在游戏区域,主要是根据相应格子的设置标志来显示相应的图形图片,这样就实现了俄罗斯方块的实时显示。
2.4、GameSetting, 游戏画布类。
这个类生成的对象将作为游戏界面的方块下落区域,画布的设置为15行10列,当中的方格边长为30,类中还定义了一个二维数组int [][] scrArr 作为屏幕数组,表示每一个方格。
游戏区域中每一个方格是否存在游戏方块是由该方格的值来决定的,如果该方格的值为1,则表示该方格中存在游戏方块;如果该方格中的值为0,则表示该方格中不存在游戏方块,因此二维数组用于记录游戏区域中每个小方格的值。
此外,类中还定义了画方块的方法,根据不同的难度画出不同颜色的方块。
单击Play按钮时,系统调用initScr( )方法,初始化屏幕,将屏幕数组清零。
当满足满行删除的条件时,系统调用deleteFullLine( )方法,进行删行加分,而且每删除十行,难度自动增加一级,方块颜色改变,并在难度显示框中相应显示。
2.5、GameOver,游戏结束弹出提示框类。
当游戏结束时,系统弹出提示,包括玩家分数以及询问玩家要继续游戏还是退出。
2.6、Help,帮助类。
在游戏界面,按F1键,弹出提示窗口,获取帮助。
2.7、ImagePanel,背景图片类。
这个类继承了JPanel类,用来作为游戏界面中控制区域的容器,并添加图片。
2.8、JieMian,主界面类。
这个类继承了JPanel类,作为游戏的第一个界面,也是难度选择界面。
定义了9个单选按钮,当玩家未选任何难度就按Enter时,系统会弹出一个提示框,提示玩家先选难度再进入。
2.9、MyPanel,重写MyPanel类,使Panel的四周留空间。
2.10、MyTimer,定时线程类。
类中定义了一个run()方法,用sleep()函数实现方块下落的快慢,即调节难度。
2.11、PlayMidi,添加音乐类。
在游戏过程中添加背景音乐。
2.12、WinListener,关闭窗口类。
4.主要类的UML类图表示
5.(Square类的UML类图表示)
三、详细设计:
1模型层设计
1)图形的产生
通过图形工厂类ShapeFactory的getShape(ShapeListener listener)方法随机产生方块的某种状态,这里运用了工厂设计模式,这种设计模式是为了实现高内聚低耦合而存在的,这种设计模式的通俗解释就是:你想要一个产品,你需要让工厂给你生产一个,你要告诉工厂你要生产什么产品,就把你需要生产的这个产品当做参数传给工厂类的生产产品的方法,然后根据你传进来的产品,而决定工厂人生产什么产品,产生出来产品后,最后要返回您要的这个东西。
2)图形数据结购
定义一个4x4方阵,共16个小格。
用“0”和“1”来表示每个方格是绘制还是空白,
由此可以组合出多种图形,如图所示:
其中图一表示为{0,0,0,0,1,1,1,1 ,0,0,0,0,0,0,0,0}
其中图二表示为{0,0,0,0,0,1,1,0 ,0,1,1,0,0,0,0,0}
其中图三表示为{0,0,0,0,0,1,0,0 ,0,1,1,1,0,0,0,0}
其中图四表示为{0,0,0,0,0,1,0,1 ,0,1,1,0,0,0,1,0} 方块的旋转是通过绘制4个方向的方块,在不同旋转角度显示不同方向的方块来完成的。
所以程序要控制方块的旋转方向,只要控制显示哪副图就可以了。
本游戏是用一个三维数组int[][][] shapes = new int[][][];作为存储方块的数据结构来保存方块的28种状态的。
代码如下:
public final static int[][] STYLES = {// 共28种状态
{ 0x0f00, 0x4444, 0x0f00, 0x4444 }, // 长条型的四种状态
{ 0x04e0, 0x0464, 0x00e4, 0x04c4 }, // 'T'型的四种状态
{ 0x4620, 0x6c00, 0x4620, 0x6c00 }, // 反'Z'型的四种状态
{ 0x2640, 0xc600, 0x2640, 0xc600 }, // 'Z'型的四种状态
{ 0x6220, 0x1700, 0x2230, 0x0740 }, // '7'型的四种状态
{ 0x6440, 0x0e20, 0x44c0, 0x8e00 }, // 反'7'型的四种状态
{ 0x0660, 0x0660, 0x0660, 0x0660 }, // 方块的四种状态};
/*
* 构造函数
*/
public RussiaBlock(int y, int x, int level, int style) {
this.y = y;
this.x = x;
this.level = level;
moving = true;
pausing = false;
this.style = style;
canvas = GameCanvas.getCanvasInstance();
boxes = new RussiaBox[ROWS][COLS];
int key = 0x8000;
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
boolean isColor = ((style & key) != 0);
boxes[i][j] = new RussiaBox(isColor);
key >>= 1;
}
display();
}
以下这段代码是3个子模块的代码,通过实例化按钮,标签,文本域,图形面板等,用add方法进行添加等,具体解释在代码中有体现
public ControlPanel(final RussiaBlocksGame game) {
this.game = game;
/*
* 图形界面部分
*/
setLayout(new GridLayout(3, 1, 0, 4));// 设置控制面板布局方式为网格状布局
tipBlockPanel = new TipBlockPanel();// 新建一个图形界面面板中的子面板
tipPanel = new JPanel(new BorderLayout());// 设置为位置布局方式
tipPanel.add(new JLabel("Next Block:"), BorderLayout.NORTH);// 添加新的标签在子面板中,设置布局在北部
tipPanel.add(tipBlockPanel, BorderLayout.CENTER);// 添加tipblockpanel面板在子面板中
tipPanel.setBorder(border);
// 显示统计面板模块
InfoPanel = new JPanel(new GridLayout(4, 1, 0, 0));// 新建一个显示面板
// 设置4行1列的网格状布局
levelField = new JTextField("" + RussiaBlocksGame.DEFAULT_LEVEL);
levelField.setEditable(false);
scoreField = new JTextField("0");// 新建一个得分区域,并设置其值为0
scoreField.setEditable(false);// 文本区域不能被编辑
InfoPanel.add(new JLabel("当前等级:"));// 信息面板添加新的标签内容为“当前等级”
InfoPanel.add(levelField);// 信息面板添加等级区域
InfoPanel.add(new JLabel("当前分数:"));// 信息面板添加新的标签内容为“当前分数”
InfoPanel.add(scoreField);// 信息面板添加得分区域
InfoPanel.setBorder(border);
// 显示功能按钮面板模块
buttonPanel = new JPanel(new GridLayout(3, 1, 0, 0));// 新建一个按钮面板
// 设置布局方式为网格状布局
// 为3行1列
playButton = new JButton("开始");// 添加开始按钮
pauseButton = new JButton("暂停");// 添加暂停按钮
stopButton = new JButton("停止");// 添加停止按钮
turnHarderButton = new JButton("难一级");// 添加难一级按钮按钮功能未实现
turnEasilyButton = new JButton("简单一级");// 添加简单一级按钮按钮功能未实现
// 按钮面板添加功能按钮
buttonPanel.add(playButton);// 按钮面板添加开始按钮
buttonPanel.add(pauseButton);// 按钮面板添加暂停按钮
buttonPanel.add(stopButton);// 按钮面板添加停止按钮
// buttonPanel.add(turnHarderButton); 添加难一级按钮该功能未实现
// buttonPanel.add(turnEasilyButton); 添加简单一级按钮该功能未实现
buttonPanel.setBorder(border);
addKeyListener(new ControlKeyListener());// 添加键盘监听事件
add(tipPanel);
add(InfoPanel);
add(buttonPanel);
四、运行调试与分析讨论:
4.1游戏演示
4.1游戏界面演示,如7
图7
4.2开始和结束控制菜单,如图8
图8
4.3游戏窗口控制菜单,如图9
图9
4.2系统测试
4.2.1快捷键测试
1.键盘按“Ctrl+N”
效果:游戏开始
结果:正常
2. 键盘按“Ctrl+E”
效果:游戏退出
结果:正常
4.2.2右侧快捷按钮测试
1.点击“开始”按钮
效果:游戏开始
结果:正常
2.点击“暂停”按钮
效果:游戏暂停
结果:正常
3.点击“停止”按钮
效果:游戏重置
结果正常
4.2.3界面菜单选项的功能测试
1.“游戏”菜单的测试
点击“游戏”→“新游戏”
效果:游戏正常开始
结果:正常
2.点击“游戏”→“Exit”
效果:游戏退出
结果:正常
3. “窗口样式”菜单测试
1.点击“窗口样式”→“Windows”
效果:切换为Wingdows模式
结果:正常
2.点击“窗口样式”→“Motif”
效果:切换为Motif样式
结果:正常
3. 点击“窗口样式”→“Mentel”
效果:切换为Mentel模式
结果:正常
4.2.4 按键事件的功能测试
(1) 方块移动测试
游戏过程中,点击“左、右、下”方向键
输出:方块正常移动,不会移出边界
结果:正常
(2) 方块反转测试
游戏过程中,点击向上方向键
输出:方块无边界和障碍物阻挡的情况下可反转
结果:正常
4.2.5方块堆砌与消行测试
(1) 当方块下落到最底面或与障碍物接触时
输出:方块成功堆砌在底部
结果:正常
(2) 当出现满行现象时
输出:所有满行被消除,方块依次下移
结果:正常
4.2.6 测试结果分析
经过测试,本游戏实现了基本的功能,不过整体功能还不是很强大,作为开发的第一个版本,游戏在很多方面还需要进一步完善。
五、设计体会与小结:
课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程.
回顾起课程设计,至今我仍感慨颇多,的确,在这一星期的日子里,可以说得是苦多于甜,但是可以学到很多很多的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。
在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
通过课程设计之后,把以前所学过的知识重新温故。
这次课程设计终于顺利完成了,在设计中遇到了很多编程问题,最后在老师的指导下,
终于迎刃而解。
在此我表示感谢!同时,对给过我帮助的所有同学和各位指导老师再次表示忠心的感谢
六、附录:
1、小组成员及分工情况
系(部):信息工程系
专业班级:软件(1)班
学生姓名:陈学烽
学号:1011302101012
完成日期:2011年12月28日
2、源代码
ControlPanel.java
/*
*虚拟的单个方格类,控制方格的颜色
*/
class RussiaBox implements Cloneable {
private boolean isColor;
public RussiaBox(boolean isColor) {
this.isColor = isColor;
}
/*
* 设置颜色
*/
public void setColor(boolean isColor) {
this.isColor = isColor;
}
/*
* 返回颜色
*/
public boolean isColorBox() {
return isColor;
}
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
GameCanvas.java
//游戏中方块显示的画布类
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
class GameCanvas extends JPanel {
private RussiaBox[][] boxes;//定义小方块
private int rows = 20, cols = 12;//定义20行12列
private static GameCanvas canvas = null;
private int boxWidth, boxHeight;// 默认为零需要调用fanning函数设置
private Color blockColor = Color.RED, bgColor = Color.LIGHT_GRAY;//定义方块色为红色,背景为浅灰色
private EtchedBorder border = new EtchedBorder(EtchedBorder.RAISED,
Color.WHITE, new Color(148, 145, 140));//边框颜色白色
/*
* 采用单件模式,构造函数私有
*/
private GameCanvas() {
boxes = new RussiaBox[rows][cols];
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++)
boxes[i][j] = new RussiaBox(false);
setBorder(border);
}
/*
* 获得GameCanvas实例
*/
public static GameCanvas getCanvasInstance() {
if (canvas == null)
canvas = new GameCanvas();
return canvas;
}
/*
* 设置画布的背景色
*/
public void setBgColor(Color bgColor) { this.bgColor = bgColor;
}
/*
* 获得画布的背景色
*/
public Color getBgColor() {
return bgColor;
}
/*
* 设置方块的颜色
*/
public void setBlockColor(Color blockColor) { this.blockColor = blockColor;
}
/*
* 方块的颜色
*/
public Color getBlockColor() {
return blockColor;
}
/*
* 设置画布中方块的行数
*/
public void setRows(int rows) {
this.rows = rows;
}
/*
* 得到画布中方块的行数
*/
public int getRows() {
return rows;
}
/*
* 设置画布中方块的列数
*/
public void setCols(int cols) {
this.cols = cols;
}
/*
* 得到画布中方块的列数
*/
public int getCols() {
return cols;
}
/*
* 得到row行,col列的方格
*/
public RussiaBox getBox(int row, int col) {
if (row >= 0 && row < rows && col >= 0 && col < cols)
return boxes[row][col];
else
return null;
}
/*
* 在画布中绘制方块
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
fanning();
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
Color color = boxes[i][j].isColorBox() ? blockColor : bgColor;
g.setColor(color);
g.fill3DRect(j * boxWidth, i * boxHeight, boxWidth, boxHeight,
true);
}
}
/*
* 清除第row行
*/
public void removeLine(int row) {
for (int i = row; i > 0; i--)
for (int j = 0; j < cols; j++) {
boxes[i][j] = (RussiaBox) boxes[i - 1][j].clone();
}
}
/*
* 重置为初始时的状态
*/
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();
}
/*
* 根据窗体的大小自动调整方格的大小
*/
public void fanning() {
boxWidth = getSize().width / cols;
boxHeight = getSize().height / rows;
}
}
RussiaBlock.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/*
* 方块类
*/
class RussiaBlock extends Thread {
private int style, y, x, level;
private boolean moving, pausing;
private RussiaBox boxes[][];
private GameCanvas canvas;
public final static int ROWS = 4;
public final static int COLS = 4;
public final static int BLOCK_KIND_NUMBER = 7;
public final static int BLOCK_STATUS_NUMBER = 4;
public final static int BETWEEN_LEVELS_TIME = 50;
public final static int LEVEL_FLATNESS_GENE = 3;
/*
* 方块的所有风格及其不同的状态
*/
public final static int[][] STYLES = {// 共28种状态
{ 0x0f00, 0x4444, 0x0f00, 0x4444 }, // 长条型的四种状态
{ 0x04e0, 0x0464, 0x00e4, 0x04c4 }, // 'T'型的四种状态
{ 0x4620, 0x6c00, 0x4620, 0x6c00 }, // 反'Z'型的四种状态
{ 0x2640, 0xc600, 0x2640, 0xc600 }, // 'Z'型的四种状态
{ 0x6220, 0x1700, 0x2230, 0x0740 }, // '7'型的四种状态
{ 0x6440, 0x0e20, 0x44c0, 0x8e00 }, // 反'7'型的四种状态
{ 0x0660, 0x0660, 0x0660, 0x0660 }, // 方块的四种状态};
/*
* 构造函数
*/
public RussiaBlock(int y, int x, int level, int style) {
this.y = y;
this.x = x;
this.level = level;
moving = true;
pausing = false;
this.style = style;
canvas = GameCanvas.getCanvasInstance();
boxes = new RussiaBox[ROWS][COLS];
int key = 0x8000;
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
boolean isColor = ((style & key) != 0);
boxes[i][j] = new RussiaBox(isColor);
key >>= 1;
}
display();
}
/*
* 线程的run方法控制放块的下落及下落速度
*/
public void run() {
while (moving) {//方块移动循环
try {
sleep(BETWEEN_LEVELS_TIME
* (RussiaBlocksGame.MAX_LEVEL - level + LEVEL_FLATNESS_GENE));
if (!pausing)
moving = (moveTo(y + 1, x) && moving);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
* 暂停移动
*/
public void pauseMove() {
pausing = true;
}
/*
* 从暂停状态恢复
*/
public void resumeMove() {
pausing = false;
}
/*
* 停止移动
*/
public void stopMove() {
moving = false;
}
/*
* 向左移一格
*/
public void moveLeft() {
moveTo(y, x - 1);
}
/*
* 向右移一格
*/
public void moveRight() {
moveTo(y, x + 1);
}
/*
* 向下移一格,返回与其他几个不同,为了一键到底
*/
public boolean moveDown() {
if (moveTo(y + 1, x))
return true;
else
return false;
}
/*
* 移到newRow,newCol位置
*/
public synchronized boolean moveTo(int newRow, int newCol) { // erase();//必须在判断前进行擦除,否则isMoveable将产生错误行为
if (!moving || !isMoveable(newRow, newCol)) {
display();
return false;
}
y = newRow;//y为新的行
x = newCol;//x为新的列
display();
canvas.repaint();//俄罗斯方块重画
return true;
}
/*
* 判断能否移到newRow,newCol位置
*/
private boolean isMoveable(int newRow, int newCol) {
erase();
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
if (boxes[i][j].isColorBox()) {
RussiaBox box = canvas.getBox(newRow + i, newCol + j);
if (box == null || box.isColorBox())
return false;
}
}
return true;
}
/*
* 通过旋转变为下一种状态
*/
public void turnNext() {
int newStyle = 0;
for (int i = 0; i < STYLES.length; i++)
for (int j = 0; j < STYLES[i].length; j++) {
if (style == STYLES[i][j]) {
newStyle = STYLES[i][(j + 1) % BLOCK_STATUS_NUMBER];
break;
}
}
turnTo(newStyle);
}
/*
* 通过旋转变能否变为newStyle状态
*/
private synchronized boolean turnTo(int newStyle) {
// erase();//擦除之后在判断isTurnNextAble
if (!moving || !isTurnable(newStyle)) {
display();
return false;
}
style = newStyle;
int key = 0x8000;
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
boolean isColor = ((key & style) != 0);
boxes[i][j].setColor(isColor);
key >>= 1;
}
display();
canvas.repaint();
return true;
}
/*
* 判断通过旋转能否变为下一种状态
*/
private boolean isTurnable(int newStyle) {
erase();
int key = 0x8000;
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
if ((key & newStyle) != 0) {
RussiaBox box = canvas.getBox(y + i, x + j);
if (box == null || box.isColorBox())
return false;
}
key >>= 1;
}
return true;
}
/*
* 擦除当前方块(只是设置isColor属性,颜色并没有清除,为了判断能否移动之用) */
private void erase() {
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
if (boxes[i][j].isColorBox()) {
RussiaBox box = canvas.getBox(y + i, x + j);
if (box != null)
box.setColor(false);
}
}
}
/*
* 显示当前方块(其实只是设置Color属性,在调用repaint方法时才真正显示)
*/
private void display() {
for (int i = 0; i < boxes.length; i++)
for (int j = 0; j < boxes[i].length; j++) {
if (boxes[i][j].isColorBox()) {
RussiaBox box = canvas.getBox(y + i, x + j);
if (box != null)
box.setColor(true);
}
}
}
}
RussiaBlocksGame.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class RussiaBlocksGame extends JFrame {
public final static int PER_LINE_SCORE = 100;// 消去一行得分
public final static int PER_LEVEL_SCORE = PER_LINE_SCORE * 20;// 升一级需要的分数
public final static int DEFAULT_LEVEL = 1;// 默认级别
public final static int MAX_LEVEL = 10;// 最高级别
private int score = 0, curLevelScore = 0;// 总分和本级得分
private GameCanvas canvas;
private ControlPanel controlPanel;//定义控制面板
private RussiaBlock block;//定义俄罗斯方块
private int style = 0;
boolean playing = false;//设置布尔类型为游戏为不可玩
private JMenuBar bar;//定义菜单栏
private JMenu gameMenu, controlMenu, windowStyleMenu, informationMenu;//定义游戏菜单控制菜单(未实现)样式风格菜单信息菜单
private JMenuItem newGameItem, setBlockColorItem, setBgColorItem,//定义新游戏选项卡设置背景色选项卡(未实现)
turnHardItem, turnEasyItem, exitItem;//难一级选项卡(未实现)简单一级选项卡(未实现)推出选项卡(未实现)
private JMenuItem playItem, pauseItem, resumeItem, stopItem; //开始选项卡暂停选项卡恢复选项卡停止选项卡均未实现
private JRadioButtonMenuItem windowsRadioItem, motifRadioItem,//3种样式风格选项卡metalRadioItem;
private JMenuItem authorItem, helpItem;//作者选项卡帮助选项卡
private ButtonGroup buttonGroup;//按钮组
/*
* 构造函数
*/
public RussiaBlocksGame(String title) {
super(title);
setSize(300, 400);//设置游戏大小为300宽400高
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((scrSize.width - getSize().width) / 2,
(scrSize.height - getSize().height) / 2);
createMenu();//创建菜单
Container container = getContentPane();//新建总面板
container.setLayout(new BorderLayout());//设置为位置布局方式
canvas = GameCanvas.getCanvasInstance();
controlPanel = new ControlPanel(this);//新建一个按钮面板
container.add(canvas, BorderLayout.CENTER); //总面板添加游戏并设为居中样式
container.add(controlPanel, BorderLayout.EAST);//总面板添加按钮面板并设置为居左样式
addWindowListener(new WindowAdapter() {//添加窗口事件监听
public void windowClosing(WindowEvent event) {//窗口关闭事件
stopGame();//停止游戏
System.exit(0);//系统退出
}
});
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent event) {
canvas.fanning();
}
});
canvas.fanning();
setVisible(true);
}
/*
* 判断游戏是否正在进行
*/
public boolean isPlaying() {
return playing;
}
/*
* 开始游戏并设置按钮和菜单项的可用性
*/
public void playGame() {
play();
controlPanel.setPlayButtonEnabled(false);//控制面板设置开始按钮为不可利用playItem.setEnabled(false);//开始选项卡为不可利用
}
/*
* 暂停游戏
*/
public void pauseGame() {
if (block != null)//判断游戏不为空
block.pauseMove();//游戏暂停移动
controlPanel.setPauseButtonLabel(false);//控制面板暂停按钮为不可利用
pauseItem.setEnabled(false);//暂停选项卡设置为不可以用
resumeItem.setEnabled(true);//恢复选项卡为可利用
}
/*
* 从暂停中恢复游戏
*/
public void resumeGame() {
if (block != null)
block.resumeMove();
controlPanel.setPauseButtonLabel(true);
pauseItem.setEnabled(true);
resumeItem.setEnabled(false);
}
/*
* 停止游戏
*/
public void stopGame() {
if (block != null)
block.stopMove();
playing = false;
controlPanel.setPlayButtonEnabled(true);
controlPanel.setPauseButtonLabel(true);
playItem.setEnabled(true);
}
/*
* 得到当前级别
*/
public int getLevel() {
return controlPanel.getLevel();
}
/*
* 设置当前级别,并更新控制面板的显示
*/
public void setLevel(int level) {
if (level > 0 && level < 11)
controlPanel.setLevel(level);
}
/*
* 得到当前总分数
*/
public int getScore() {
if (canvas != null)
return score;
return 0;
}
/*
* 得到本级得分
*/
public int getCurLevelScore() {
if (canvas != null)
return curLevelScore;
return 0;
}
/*
* 更新等级
*/
public void levelUpdate() {
int curLevel = getLevel();
if (curLevel < MAX_LEVEL && curLevelScore >= PER_LEVEL_SCORE) { setLevel(curLevel + 1);
curLevelScore -= PER_LEVEL_SCORE;
}
}
/*
* 获得当前得方块
*/
public RussiaBlock getCurBlock() {
return block;
}
/*
* 开始游戏
*/
private void play() {
playing = true;
Thread thread = new Thread(new Game());
thread.start();
reset();
}
/*
* 重置
*/
private void reset() {
controlPanel.reset();
canvas.reset();
score = 0;
curLevelScore = 0;
}
/*
* 宣告游戏结束
*/
private void reportGameOver() {
JOptionPane.showMessageDialog(this, "Game over!\n\n" + "最终成绩:"
+ curLevelScore + " \n\n等级:" + score);
}
/*
* 创建菜单
*/
private void createMenu() {
gameMenu = new JMenu("游戏");//新建一个jmenu游戏菜单
newGameItem = new JMenuItem("新游戏", KeyEvent.VK_N);//新建一个新游戏选项卡并命名新游戏,设快捷键为N
newGameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
ActionEvent.CTRL_MASK));//设置新游戏选项卡快捷键
setBlockColorItem = new JMenuItem("Set Block Color...");//新建一个设置游戏方块颜色选项卡并命名(未实现)
setBgColorItem = new JMenuItem("Set BackGround Color...");//新建一个设置游戏背景色选项卡并命名(未实现)
turnHardItem = new JMenuItem("难一级");//新建一个难一级选项卡(未实现)
turnEasyItem = new JMenuItem("简单一级");//新建一个简单一级选项卡(未实现)
exitItem = new JMenuItem("Exit", KeyEvent.VK_E);//新建一个退出选项卡并命名设快捷键E
exitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,
ActionEvent.CTRL_MASK));//设置退出选项卡快捷键
gameMenu.add(newGameItem);//游戏菜单添加新游戏选项卡
// gameMenu.add(setBlockColorItem);//游戏菜单添加设置游戏方块颜色选项卡(未实现)
// gameMenu.add(setBgColorItem);//游戏菜单添加设置游戏背景色选项卡(未实现)
// gameMenu.add(turnHardItem);//游戏菜单添加难一级选项卡(未实现)
// gameMenu.add(turnEasyItem);//游戏菜单添加简单一级选项卡(未实现)
gameMenu.add(exitItem);//游戏菜单添加退出选项卡
controlMenu = new JMenu("控制");//添加控制菜单并命名(未实现)
playItem = new JMenuItem("开始", KeyEvent.VK_B);//添加开始选项卡并命名设快捷b(未实现)
playItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B,
ActionEvent.CTRL_MASK));//设置快捷键(未实现)
pauseItem = new JMenuItem("暂停", KeyEvent.VK_P);//添加暂停选项卡并命名设快捷p(未实现)
pauseItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
ActionEvent.CTRL_MASK));//设置快捷键(未实现)
resumeItem = new JMenuItem("重新开始", KeyEvent.VK_R);//添加重新开始选项卡并命名设快捷r(未实现)
resumeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
ActionEvent.CTRL_MASK));//设置快捷键(未实现)
stopItem = new JMenuItem("停止", KeyEvent.VK_S);//添加停止选项卡并命名设快捷s(未实现)
stopItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
ActionEvent.CTRL_MASK));//设置快捷键(未实现)
controlMenu.add(playItem);//控制菜单添加开始选项卡(未实现)
controlMenu.add(pauseItem);//控制菜单添加暂停选项卡(未实现)
controlMenu.add(resumeItem);//控制菜单添加重新开始选项卡(未实现)
controlMenu.add(stopItem);//控制菜单添加停止选项卡(未实现)
windowStyleMenu = new JMenu("窗口样式");//新建一个窗口样式菜单并命名
buttonGroup = new ButtonGroup();//新建一个单选按钮组
windowsRadioItem = new JRadioButtonMenuItem("Windows");//新建一个windows样式选项卡并命名
motifRadioItem = new JRadioButtonMenuItem("Motif"); //新建一个motif样式选项
卡并命名
metalRadioItem = new JRadioButtonMenuItem("Mentel", true);//新建一个mentel样式选项卡并命名设置为默认使用状态
windowStyleMenu.add(windowsRadioItem);//窗口风格菜单添加windows菜单样式选项卡
buttonGroup.add(windowsRadioItem);//单选按钮组添加windows样式菜单选项卡
windowStyleMenu.add(motifRadioItem);//窗口风格菜单添加motif菜单样式选项卡
buttonGroup.add(motifRadioItem);//单选按钮组添加motif样式菜单选项卡
windowStyleMenu.add(metalRadioItem);//窗口风格菜单添加metal菜单样式选项卡
buttonGroup.add(metalRadioItem);//单选按钮组添加metal样式菜单选项卡
informationMenu = new JMenu("游戏说明");//新建一个信息菜单并命名
authorItem = new JMenuItem("作者");//新建一个作者选项卡并命名
helpItem = new JMenuItem("帮助");//新建一个帮助选项卡并命名
informationMenu.add(authorItem);//信息菜单添加作者选项卡
informationMenu.add(helpItem);//信息菜单添加帮助选项卡
bar = new JMenuBar();//实例化一个工具栏
bar.add(gameMenu);//工具栏添加游戏菜单
// bar.add(controlMenu);//工具栏添加控制方法(未实现)
bar.add(windowStyleMenu);//工具栏添加窗口样式菜单
bar.add(informationMenu);//工具栏添加信息菜单
addActionListenerToMenu();//添加菜单栏事件监听
setJMenuBar(bar);//设置菜单栏
}
/*
* 添加菜单响应
*/
private void addActionListenerToMenu() {
newGameItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
stopGame();
reset();
setLevel(DEFAULT_LEVEL);
}
});
setBlockColorItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Color newBlockColor = JColorChooser.showDialog(
RussiaBlocksGame.this, "Set color for block",
canvas.getBlockColor());
if (newBlockColor != null)
canvas.setBlockColor(newBlockColor);
}
});
setBgColorItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
Color newBgColor = JColorChooser.showDialog(
RussiaBlocksGame.this, "Set color for block",
canvas.getBgColor());
if (newBgColor != null)
canvas.setBgColor(newBgColor);
}
});
turnHardItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
int curLevel = getLevel();
if (curLevel < MAX_LEVEL)
setLevel(curLevel + 1);
}
});
turnEasyItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) {
int curLevel = getLevel();
if (curLevel > 1)
setLevel(curLevel - 1);
}
});
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
playItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
playGame();
}
});
pauseItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
pauseGame();
}
});
resumeItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
resumeGame();
}
});
stopItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
stopGame();
}
});
windowsRadioItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
setWindowStyle(plaf);
canvas.fanning();
controlPanel.fanning();
}
});
motifRadioItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
setWindowStyle(plaf);
canvas.fanning();
controlPanel.fanning();
;
}
});
metalRadioItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "javax.swing.plaf.metal.MetalLookAndFeel";
setWindowStyle(plaf);
canvas.fanning();
controlPanel.fanning();
}
});
authorItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == authorItem) {
JOptionPane.showMessageDialog(null,
"RussiaBlocksGame-俄罗斯方块\n\n" + "作者: 117寝室\n\n"
+ "联系方式:软件G091班");
}
}
});
helpItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == helpItem) {
JOptionPane.showMessageDialog(null,
"RussiaBlocksGame-俄罗斯方块\n\n" + "游戏简介\n\n"
+ "1:每消除掉20行,提升一个等级,并增加游戏难度(提高游戏速度)\n"
+ "2: 游戏等级由最初的1级到最高等级10级\n"
+ "3: 游戏窗口风格为3种,玩家可自由选择适合自己的游戏样式风格\n"
+ "4: 此游戏仅为娱乐,如用于商业,概不负责\n");
}
}
});
}
/*
* 设定窗口风格
*/
private void setWindowStyle(String plaf) {
try {
UIManager.setLookAndFeel(plaf);
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
e.printStackTrace();
}
}
private class Game implements Runnable {
/*
* (non-Javadoc)
*
* @see ng.Runnable#run() 游戏线程的run函数
*/
public void run() {
int col = (int) (Math.random() * (canvas.getCols() - 3));
style = RussiaBlock.STYLES[(int) (Math.random() * RussiaBlock.BLOCK_KIND_NUMBER)][(int) (Math
.random() * RussiaBlock.BLOCK_STATUS_NUMBER)];
while (playing) {
if (block != null) { // 第一次循环时,block为空
if (block.isAlive()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
continue;
}
}
checkFullLine();
if (isGameOver()) { // 检查游戏是否应该结束了
playItem.setEnabled(true);
pauseItem.setEnabled(true);
resumeItem.setEnabled(false);
controlPanel.setPlayButtonEnabled(true);
controlPanel.setPauseButtonLabel(true);
reportGameOver();
return;
}
block = new RussiaBlock(-1, col, getLevel(), style);
block.start();
col = (int) (Math.random() * (canvas.getCols() - 3));
style = RussiaBlock.STYLES[(int) (Math.random() * RussiaBlock.BLOCK_KIND_NUMBER)][(int) (Math
.random() * RussiaBlock.BLOCK_STATUS_NUMBER)];
controlPanel.setBlockStyle(style);
}
}
/*
* 判断是否能消去整行
*/
public void checkFullLine() {。