今天整理之前的项目,发现了在大二上学期的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对板块是对调的,怎么都还原不到完整的顺序,这样的拼图其实是不可还原的拼图。
由于我们设计时,是将板块随机打乱,实际上并不是所有随机打乱之后都是可以还原的!确切的说,随机打乱后,有是不可以被还原的。
谢谢您的关注和阅读,文章不当之处还请您不吝赐教~~~