今天整理之前的项目,发现了在大二上学期的java课程设计中编写的智能拼图小游戏,觉得有意思,所以打算写篇文章和大伙分享分享。
一、项目功能
1)本游戏是一个Java语言的拼图游戏,有一个格子是空的,其他格子内随机放置由要拿来拼图的图片切割成的若干个小图片,图片的切割按照一定的公式计算,用户可以自己选择图片到游戏中,据不同的难度,按照公式会切割成不同的小图片块数(有3*3,4*4,5*5)。
2)在开始游戏之前,可以选择游戏难度后再点击“开始”菜单里的“开始游戏”,进行拼图游戏,通过将空格旁边的小图片移入空格子内(不断的移动方块),来实现拼图,直到方块一行一行的按图片的原始样子拼好即可完成该游戏。
3)游戏进行时,可以点击“图片预览”查看完整图片,以便拼图的方便。
4)游戏拼完后,会弹出一个“信息”框,显示时间和步数。并且可以输入玩家名字。
5)游戏的简单规则在游戏界面的“帮助”菜单内的“游戏规则”信息框内已经简单介绍了。游戏前可以先预览看看。
二、设计思路
(一)主窗口界面设计
1、游戏初始界面
当游戏运行时,主窗口界面中包含三个菜单,分别是开始、选择、帮助。主体部分是一个拼图的界面,有9块格子,其中有一块是空白的,状态栏有记录步数和游戏状态的标签。
2、游戏运行时
选择好图片后,便可以进行游戏的进行状态。游戏过程中,可以点击“选择”菜单里的“图片预览”菜单项进行完整图片的预览。
当游戏者,在游戏过程中半途暂停游戏的话,将出现游戏暂停状态的界面。当游戏者又想继续游戏时,直接单击界面上的“继续”字样,就可以继续游戏了。
4、游戏结束
拼图完成后,会自动弹出已完成的信息提示框。并且在打破记录后会弹出输入玩家姓名的输入框。
(二)主窗口菜单功能
1、“开始”菜单。包括了“开始游戏”、“成绩记录”、“退出游戏”。
开始游戏:单击可以开始游戏;
成绩记录:保存的前三名玩家的成绩,保存在外存的.txt文档里。
退出游戏:退出程序。
2、“选择”菜单。包括了“等级”、“游戏图片”、“增加图片”。当运行游戏前,先选择等级和游戏图片。
等级:在游戏者开始游戏之前,要进行游戏等级选择,共有3*3、4*4和5*5三个选择。其图片的切割块数,会根据选择的等级不同,而有所不同。
游戏图片:里面存放了该游戏的游戏图片图,直接选择某个图片名即可选择此图片作为游戏图片。
增加图片:点击该菜单项会弹出文件选择框,选择本地电脑的图片到游戏图片库。
3、“帮助”菜单。包括了“游戏规则”、“关于我们”。
游戏规则:击查看游戏的简单规则。
关于我们:可查看该游戏的版本、作者等相关信息。
(三)需要用的对话框
1、提示信息框
当游戏者运行游戏时,如果没有把“background”这个文件夹放入主程序的目录下,在运行游戏选择背景图片时,将没有图片可选,若此时直接“开始”->“新游戏”,将会弹出信息框,提示玩家图片不存在。
2、拼图成功后的提示框
当玩家拼图成功后,会弹出提示框告诉玩家所用的时间和步数。
3、成绩记录输入框
当玩家完成游戏后,并且打破前三名的记录时,将会出现一个成绩记录框。
4、前三名成绩显示框
输入成绩后,会弹出前三名玩家的成绩,包括玩家姓名,等级,时间和步数。
(四)功能实现思想
由于这个是java课程设计,属于团队合作开发的小项目,所以对代码的可移植性以及重复利用性要求较高,为了达到这一目的,需要把不同的功能写成不同的类(.java),再把类似的功能由同一人写,并且放在一个自定义包里。
三、功能核心代码
(一)记录坐标的类
//point.java package Function; public class point//坐标 { int row;//行坐标 int col;//列坐标 public point(int r, int c) { row = r; col = c; }//构造函数初始化 public void set(int r, int c) { row = r; col = c; }//设置坐标 public int getRow() { return row; }//获取行坐标 public int getCol() { return col; }//获取列坐标 public boolean neighbor(int r, int c) { int n = Math.abs(row - r) + Math.abs(col - c); return n == 1; }//判断(r,c)与(row,col)是否相邻,相邻则返回true }
(二)分割图片的类
需要将选择的一张图片按照3*3或其他格式进行分割,然后随机摆放在主界面的9个格子中
//Split.java package PictureOperation; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import Arg.*; //Singleton class public class Split { public static final int HARD = 0; public static final int NORMAL = 1; public static final int EASY = 2; public static final String pvo = "png"; public static final int [] level = { 72, 90, 120 }; private static Split Ob; private String filename; private String path; private Split() {} public static Split get() { if (Ob == null) Ob = new Split(); return Ob; } public boolean set(String fn) { filename = fn; path = Arg.path + "/" + filename; File file = new File(path); return file.exists(); } public BufferedImage[][] divid(int type) { try { if (filename == null) return null; BufferedImage image = ImageIO.read(new File(path)); BufferedImage imagei = new BufferedImage(360, 360,BufferedImage.TYPE_INT_RGB ); imagei.getGraphics().drawImage(image, 0, 0, 360, 360, null); image=imagei; int len = level[type]; int cal = image.getWidth() / len; int row = image.getHeight() / len; BufferedImage [][] subimage = new BufferedImage[row][cal]; for (int i = 0; i < row; i++) for (int j = 0; j < cal; j++) subimage[i][j] = image.getSubimage(j*len, i*len, len, len); return subimage; } catch (Exception e) { return null; } } }
(三)图片交换类
当点击一张图片时,如果它的周围四个位置有一个为空白,则可以移动到空白位,并让该图片位置变成空白。
//Matrix.java package PictureOperation; import Function.*; import java.awt.image.BufferedImage; import javax.swing.JPanel; import javax.swing.JButton; import javax.swing.ImageIcon; public class Matrix { private JButton [][] button; private JPanel panel; private int row; private int col; private int [][] matrix; private GameOver gOver; public Matrix(JButton [][] b, JPanel p, int len, GameOver g) { this.button = b; this.panel = p; this.gOver = g; row = b.length;//长 col = b[0].length;//宽 matrix = new int[row][col]; matrix[row-1][col-1] = row * col; gOver.start(matrix); panel.removeAll(); point pint = new point(row-1, col-1); for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) { button[i][j] = new JButton(); button[i][j].setBounds(j*len, i*len, len, len); button[i][j].addActionListener(new ButtonClick(button, pint, matrix, i, j, gOver)); panel.add(button[i][j]); } } public void init(BufferedImage [][] image) { if (button == null || image == null) return; ImageIcon icon; int r, c, rad, d, m; boolean [] visit = new boolean[row*col-1]; for (int i = 0; i < row*col - 1; i++) { r = i / col; c = i % col; rad = (int)(Math.random()*(row*col-1-i)); for (d = m = 0; d < row*col - 1 && m <= rad; d++) if (!visit[d]) m++; matrix[i/col][i%col] = d; visit[--d] = true; icon = new ImageIcon(image[d/col][d%col]);//分割 button[i/col][i%col].setIcon(icon); } } }
(四)其他代码
由于博文篇幅太长容易造成大伙的视觉疲劳,所以有兴趣实现的小伙伴可以到附件下载Puzzle_lite.rar。还有就是写这个游戏的时候,学校课程还在C++和Java不断的切换,所以写出来的代码还有点C++的风格,望海涵。
四、不足之处
测试过程中发现,有的拼图拼到最后出现有1对板块是对调的,怎么都还原不到完整的顺序,这样的拼图其实是不可还原的拼图。
由于我们设计时,是将板块随机打乱,实际上并不是所有随机打乱之后都是可以还原的!确切的说,随机打乱后,有是不可以被还原的。
谢谢您的关注和阅读,文章不当之处还请您不吝赐教~~~