《Java程序设计》实训报告.docx
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(ints) 。分别实现方块的重画、翻转、左移、右移、下落、同步显示等功能。2.2 、 Comman,d 处理控制类。这是一个实现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 、 GameOve,r 游戏结束弹出提示框类。当游戏结束时,系统弹出提示,包括玩家分数以 及询问玩家要继续游戏还是退出。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类图表示1.Square2.in t pattern3.int SquareType4.int SquareState5.int blockState6.int row,col7.GameSett ing scr8.+ void reset()9.+ void leftTurn()10.+ void leftMove()11.+ void rightMove()12.+ boolea n fallDow n()13.boolea n assertValid(i nt t,i nt s,i nt row,i nt col)14.+ synchroni zed void dispBlock(i nt s)5. (Square 类的UML类图表示)15.GameSett ing16.int un itSize17.int rowNum18.int colu mnNum19.int maxAllowRowNum20.int Square In itRo21.int Square In itCol22.in t scrArr23. Square b24. initScr()25. + void pain t(Graphics g)26. + void draw Un it(i nt row,i nt col,i nt type)27. + Square getBlock()28. + int getScrArrXY(i nt row,i nt col)29. + int getI ni tRow()30. + in t getI ni tCol()31. void deleteFullLine()32. boolean isGameEnd()33. + void keyPressed(KeyEve nt e)三、详细设计:1模型层设计1)图形的产生通过图形工厂类 ShapeFactory的getShape(ShapeListener listener)方法随机产生方块的某种状态,这里运用了工厂设计模式,这种设计模式是为了实现高内聚低耦合而存在的,这种设计模式的通俗解释就是:你想要一个产品,你需要让工厂给你生产一个,你要告诉工厂你要生产什么产品,就把你需要生产的这个产品当做参数传给工厂类的生产产品的方法,然后根据你传进来的产品,而决定工厂人生产什么产品,产生出来产品后,最后要返回您要的这个东西。随机产生一个数一字形 Z字形 反Z形 7字形 反7形 倒T形 田字型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个方向的方块,在不同旋转角度显示不同方向的方块来完成的。所以程序要控制方块的旋转方向,只要控制显示哪副图就可以了。本游戏是用一个三维数组in t shapes = new in t;作为存储方块的数据结构来保存方块的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 RussiaBoxROWSCOLS; int key = 0x8000;for (int i = 0; i < boxes.length; i+)for (int j = 0; j < boxesi.length; j+) boolean isColor = (style & key) != 0); boxesij = new RussiaBox(isColor); key >>= 1;display();以下这段代码是 3 个子模块的代码,通过实例化按钮,标签,文本域,图形面板等,用 add 方法进行添加等,具体解释在代码中有体现public ControlPanel(final RussiaBlocksGame game) this.game = game;/*图形界面部分设置控制面板布局方式为网格状布局板tipBlockPanel = new TipBlockPanel();/新建一个图形界面面板中的子面*/ setLayout(new GridLayout(3, 1, 0, 4);/tipPanel = new JPanel(new BorderLayout();/ 设置为位置布局方式 tipPanel.add(new JLabel("Next Block:"), BorderLayout.NORTH);/添加新的标签在子面板中,设置布局在北部BorderLayout.CENTER);/ 添 加tipPanel.add(tipBlockPanel,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");/ 新建一个得分区域,并设置其值为 0scoreField.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于 Rilssi « Bloc-! x|图74.2开始和结束控制菜单,如图 8图8图94.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、源代码Con trolPa nel.java/*虚拟的单个方格类,控制方格的颜色*/class RussiaBox impleme nts Cion eable private boolean isColor;public RussiaBox(boolea n isColor) this.isColor = isColor;/*设置颜色*/public void setColor(boolea n isColor) this.isColor = isColor;/*返回颜色*/public boolea n isColorBox() retur n isColor;public Object cion e() Object o = n ull;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 RussiaBoxrowscols;for (int i = 0; i < boxes.length; i+)for (int j = 0; j < boxesi.length; j+)boxesij = 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 boxesrowcol;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 < boxesi.length; j+) Color color = boxesij.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+) boxesij = (RussiaBox) boxesi - 1j.clone(); /* 重置 为初始时的状态*/public void reset() for (int i = 0; i < boxes.length; i+)for (int j = 0; j < boxesi.length; j+) boxesij.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 RussiaBoxROWSCOLS;int key = 0x8000;for (int i = 0; i < boxes.length; i+)for (int j = 0; j < boxesi.length; j+) boolean isColor = (style & key) != 0); boxesij = new RussiaBox(isColor); key >>= 1;display();/* 线程的 run 方法控制放块的下落及下落速度*/ public void run() while (moving) / 方块移动循环 try sleep(BETWEEN_LEVELS_TIMElevel +* (RussiaBlocksGame.MAX_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;elsereturn 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();ca nvas.repai nt();俄罗斯方块重画 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 < boxesi.length; j+) if (boxesij.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 < STYLESi.length; j+) if (style = STYLESij) newStyle = STYLESi(j + 1) % BLOCK_STATUS_NUMBER; break;turnTo(newStyle);/* 通过旋转变能否变为 newStyle 状态*/private synchronized boolean turnTo(int newStyle) / erase(); 擦除之后在判断isTurnNextAbleif (!moving | !isTu