此小游戏可通过按钮来实现上下左右的拼图,还可以通过求助和重置按钮来复原和重新开始游戏。
在项目开始之前,希望大家多多支持,点个赞。谢谢!
思路分析:
- – 绘制游戏界面
- – 实现图片打乱
- – 给按钮添加事件
- – 移动空白图片按钮的实现
- – 求助按钮的实现
- – 重置按钮的实现
1、用 GUI 绘制游戏界面
思路分析:
- – 新建一个类:PictureFrame,让这个类继承自JFrame。
- – 在PictureFrame类中编写无参 构造方法 ,在构造方法中调用两个方法;initFrame()方法,用于窗口的基本设置。setVisible(true)方法,用于设置窗口可见。
- – 在initFrame()方法中设置窗口可见:
- 1、窗口大小
- 2、窗口标题
- 3、窗口居中
- 4、窗口关闭是退出程序
- 5、窗口位于其他窗口之上
- 6、取消窗口默认布局
- – 定义方法用于窗口上组件的绘制:paintView();并在构造方法中调用。
- – 把所有的按钮和面板定义为成员变量,写进PictureFrame类中。
- – 定义测试类App;创建PictureFrame的对象进行测试。
public class PictureFrame extends JFrame { | |
//定义按钮的成员变量 | |
private JButton shangButton; | |
private JButton zuoButton; | |
private JButton xiaButton; | |
private JButton youButton; | |
private JButton qiuZhuButton; | |
private JButton chongZhiButton; | |
//设置一个面板的成员变量 | |
private JPanel imagePanel; | |
public PictureFrame() { | |
//用于 窗体 的基本设置 | |
initFrame(); | |
//窗口上组件的绘制 | |
paintview(); | |
//设置窗体可见 | |
this.setVisible(true); | |
} | |
public void initFrame() { | |
//设置窗口大小 | |
this.setSize(, 565); | |
//设置窗口关闭时默认操作(整数表示:窗口关闭时退出应用程序) | |
this.setDefaultCloseOperation(); | |
//设置位置,值为null,则窗口位置屏幕中央 | |
this.setLocationRelativeTo(null); | |
//设置此窗口是否始终位于其他窗口之上 | |
this.setAlwaysOnTop(true); | |
//设置窗口标题 | |
this.setTitle("动漫拼图"); | |
//取消JFrame的默认布局 | |
this.setLayout(null); | |
} | |
//窗体上组件的绘制 | |
public void paintview() { | |
//标题图片 | |
JLabel titleLabel = new JLabel(new ImageIcon("day\images\title.png")); | |
titleLabel.setBounds(, 27, 232, 57); | |
this.add(titleLabel); | |
//创建面板 | |
imagePanel = new JPanel(); | |
imagePanel.setBounds(, 114, 360, 360); | |
imagePanel.setLayout(null); | |
//遍历 二维数组 ,得到图片编号 | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
//创建JLabel对象,加载图片资源 | |
JLabel imagesJlabel = new JLabel(new ImageIcon("day\\images\\" + datas[i][j] + ".png")); | |
//调整照片位置 | |
imagesJlabel.setBounds(j *, i * 90, 90, 90); | |
imagePanel.add(imagesJlabel); | |
} | |
} | |
//把面板添加到窗体上 | |
this.add(imagePanel); | |
//拼图参照图 | |
JLabel canZhaoTuLabel = new JLabel(new ImageIcon("day\images\canzhaotu.png")); | |
canZhaoTuLabel.setBounds(, 114, 122, 121); | |
this.add(canZhaoTuLabel); | |
//上下左右、求助、重置按钮 | |
shangButton = new JButton(new ImageIcon("day\images\shang.png")); | |
shangButton.setBounds(, 265, 57, 57); | |
this.add(shangButton); | |
zuoButton = new JButton(new ImageIcon("day\images\zuo.png")); | |
zuoButton.setBounds(, 347, 57, 57); | |
this.add(zuoButton); | |
xiaButton = new JButton(new ImageIcon("day\images\xia.png")); | |
xiaButton.setBounds(, 347, 57, 57); | |
this.add(xiaButton); | |
youButton = new JButton(new ImageIcon("day\images\you.png")); | |
youButton.setBounds(, 347, 57, 57); | |
this.add(youButton); | |
qiuZhuButton = new JButton(new ImageIcon("day\images\qiuzhu.png")); | |
qiuZhuButton.setBounds(, 444, 108, 45); | |
this.add(qiuZhuButton); | |
chongZhiButton = new JButton(new ImageIcon("day\images\chongzhi.png")); | |
chongZhiButton.setBounds(, 444, 108, 45); | |
this.add(chongZhiButton); | |
//展示背景图 | |
JLabel backgroundLabel = new JLabel(new ImageIcon("day\images\background.png")); | |
backgroundLabel.setBounds(, 0, 960, 530); | |
this.add(backgroundLabel); | |
} | |
} |
测试类:
public class App { | |
public static void main(String[] args) { | |
PictureFrame pictureFrame = new PictureFrame(); | |
} | |
} |
2、图片打乱并给按钮添加事件(用按钮移动空白图片)
思路分析
- – 定义方法,用于打乱二维数组:initData()
- – 创建Random对象,遍历存储的二维数字,得到每一个元素
- – 产生两个随机索引,进行二维数组元素交换
- – 定义之前现在类中定义一个二维数组
- – 在构造方法中调用initData()方法
- – 数组中的0是用来记录0号索引空白图片
- – 给按钮添加事件,用来实现移动空白图片的位置,
- 1、移动空白图片的位置就是和上下左右的图片进行交互,
- 2、交换完成之后调用重回方法:rePainView(),
- 3、处理边界问题。
- – 在测试类App中测试
“` java
public class PictureFrame extends JFrame { | |
//定义一个二维数组,用来储存图片的编号 | |
private int[][] datas = { | |
{, 2, 3, 4}, | |
{, 6, 7, 8,}, | |
{, 10, 11, 12}, | |
{, 14, 15, 0} | |
}; | |
//定义按钮的成员变量 | |
private JButton shangButton; | |
private JButton zuoButton; | |
private JButton xiaButton; | |
private JButton youButton; | |
private JButton qiuZhuButton; | |
private JButton chongZhiButton; | |
//设置一个面板的成员变量 | |
private JPanel imagePanel; | |
public PictureFrame() { | |
//用于窗体的基本设置 | |
initFrame(); | |
//窗口上组件的绘制 | |
paintview(); | |
//设置窗体可见 | |
this.setVisible(true); | |
} | |
public void initFrame() { | |
//设置窗口大小 | |
this.setSize(, 565); | |
//设置窗体关闭时默认操作(整数表示:窗口关闭时退出应用程序) | |
this.setDefaultCloseOperation(); | |
//设置位置,值为null,则窗口位置屏幕中央 | |
this.setLocationRelativeTo(null); | |
//设置此窗口是否始终位于其他窗口之上 | |
this.setAlwaysOnTop(true); | |
//设置窗口标题 | |
this.setTitle("动漫拼图"); | |
//取消JFrame的默认布局 | |
this.setLayout(null); | |
} | |
//窗体上组件的绘制 | |
public void paintview() { | |
//标题图片 | |
JLabel titleLabel = new JLabel(new ImageIcon("day\images\title.png")); | |
titleLabel.setBounds(, 27, 232, 57); | |
this.add(titleLabel); | |
//创建面板 | |
imagePanel = new JPanel(); | |
imagePanel.setBounds(, 114, 360, 360); | |
imagePanel.setLayout(null); | |
//遍历二维数组,得到图片编号 | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
//创建JLabel对象,加载图片资源 | |
JLabel imagesJlabel = new JLabel(new ImageIcon("day\\images\\" + datas[i][j] + ".png")); | |
//调整照片位置 | |
imagesJlabel.setBounds(j *, i * 90, 90, 90); | |
imagePanel.add(imagesJlabel); | |
} | |
} | |
//把面板添加到窗体上 | |
this.add(imagePanel); | |
//拼图参照图 | |
JLabel canZhaoTuLabel = new JLabel(new ImageIcon("day\images\canzhaotu.png")); | |
canZhaoTuLabel.setBounds(, 114, 122, 121); | |
this.add(canZhaoTuLabel); | |
//上下左右、求助、重置按钮 | |
shangButton = new JButton(new ImageIcon("day\images\shang.png")); | |
shangButton.setBounds(, 265, 57, 57); | |
this.add(shangButton); | |
zuoButton = new JButton(new ImageIcon("day\images\zuo.png")); | |
zuoButton.setBounds(, 347, 57, 57); | |
this.add(zuoButton); | |
xiaButton = new JButton(new ImageIcon("day\images\xia.png")); | |
xiaButton.setBounds(, 347, 57, 57); | |
this.add(xiaButton); | |
youButton = new JButton(new ImageIcon("day\images\you.png")); | |
youButton.setBounds(, 347, 57, 57); | |
this.add(youButton); | |
qiuZhuButton = new JButton(new ImageIcon("day\images\qiuzhu.png")); | |
qiuZhuButton.setBounds(, 444, 108, 45); | |
this.add(qiuZhuButton); | |
chongZhiButton = new JButton(new ImageIcon("day\images\chongzhi.png")); | |
chongZhiButton.setBounds(, 444, 108, 45); | |
this.add(chongZhiButton); | |
//展示背景图 | |
JLabel backgroundLabel = new JLabel(new ImageIcon("day\images\background.png")); | |
backgroundLabel.setBounds(, 0, 960, 530); | |
this.add(backgroundLabel); | |
//按钮添加事件 | |
shangButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (x == 3) { | |
return; | |
} | |
datas[x][y0] = datas[x0 + 1][y0]; | |
//这一步作用是啥,为什么要让datas[x+1][y0]=0; | |
//原理是交换,datas[x][y0]=0是固定的,然后把datas[x0+1][y0]赋值给datas[x0][y0] | |
//再把给datas[x0+1][y0], | |
datas[x + 1][y0] = 0; | |
x = x0 + 1; | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
zuoButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (y == 3) { | |
return; | |
} | |
datas[x][y0] = datas[x0][y0 + 1]; | |
datas[x][y0 + 1] = 0; | |
y = y0 + 1; | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
xiaButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (x == 0) { | |
return; | |
} | |
datas[x][y0] = datas[x0 - 1][y0]; | |
datas[x - 1][y0] = 0; | |
x = x0 - 1; | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
youButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (y == 0) { | |
return; | |
} | |
datas[x][y0] = datas[x0][y0 - 1]; | |
datas[x][y0 - 1] = 0; | |
y = y0 - 1; | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
} | |
//定义两个int类型的变量,用于记录号图片的位置 | |
//号图片作用是啥,为什么要定义0号图片 | |
//号图片作用是和数组里面的编号图片作一交换,用来完成拼图 | |
private int x; | |
private int y; | |
//打乱二维数组 | |
public void randomData() { | |
Random random = new Random(); | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
int x = random.nextInt(datas.length); | |
int y = random.nextInt(datas[i].length); | |
int temp = datas[i][j]; | |
datas[i][j] = datas[x][y]; | |
datas[x][y] = temp; | |
} | |
} | |
//记录号图片的位置 wc作用是啥?wc作用是给最外层for循环起了一个名字,之后用 break 结束整体循环 | |
wc: | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
if (datas[i][j] ==) { | |
x = i; | |
y = j; | |
break wc; | |
} | |
} | |
} | |
} | |
//遍历移动后的图形,移动的图形重新绘制 | |
public void rePaintView() { | |
//移除所有:移除的是JPanel标签上的全部组件,目的就是清空里面的数据 | |
imagePanel.removeAll(); | |
//遍历二维数组 | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
//创建JLabel对象,加载图片资源 | |
JLabel imagesJlabel = new JLabel(new ImageIcon("day09\\images\\" + datas[i][j] + ".png")); | |
//调整照片位置 | |
imagesJlabel.setBounds(j * 90, i * 90, 90, 90); | |
imagePanel.add(imagesJlabel); | |
} | |
} | |
//对JPanel里面的组件进行从新打印 | |
imagePanel.repaint(); | |
} | |
} |
3、求助按钮和重置按钮、游戏成功后的实现
思路分析
- – 定义移动成功分方法:success();
- 1、在方法中实现成功之后按钮不可用,
- – 在求助按钮中调用两个方式实现操作
- 1、调用success();
- 2、调用rePaintView();
- – 当重置之后需要修个数组,使数组变为之前带有0号图片的数组
- – 打乱数组
- – 重绘面板
- – 设置按钮可用
- – 万一有人成功通过游戏怎么办
- 先在PictureFrame类中定义新的成功的二维数组
- 1、定义一个方法,用于比较两个数组(`新的数组和老的数组`)元素是否相同
- 2、每次移动一个按钮调用这个方法,如果返回为true,则调用success()方法;
- – 去测试类中测试代码的可行性就完成了
public class PictureFrame extends JFrame { | |
//定义一个二维数组,用来储存图片的编号 | |
private int[][] datas = { | |
{, 2, 3, 4}, | |
{, 6, 7, 8,}, | |
{, 10, 11, 12}, | |
{, 14, 15, 0} | |
}; | |
//定义一个成功的二维数组 | |
private int[][] winDatas = { | |
{, 2, 3, 4}, | |
{, 6, 7, 8}, | |
{, 10, 11, 12}, | |
{, 14, 15, 0} | |
}; | |
//定义按钮的成员变量 | |
private JButton shangButton; | |
private JButton zuoButton; | |
private JButton xiaButton; | |
private JButton youButton; | |
private JButton qiuZhuButton; | |
private JButton chongZhiButton; | |
//设置一个面板的成员变量 | |
private JPanel imagePanel; | |
public PictureFrame() { | |
//用于窗体的基本设置 | |
initFrame(); | |
//窗口上组件的绘制 | |
paintview(); | |
//设置窗体可见 | |
this.setVisible(true); | |
} | |
public void initFrame() { | |
//设置窗口大小 | |
this.setSize(, 565); | |
//设置窗体关闭时默认操作(整数表示:窗口关闭时退出应用程序) | |
this.setDefaultCloseOperation(); | |
//设置位置,值为null,则窗口位置屏幕中央 | |
this.setLocationRelativeTo(null); | |
//设置此窗口是否始终位于其他窗口之上 | |
this.setAlwaysOnTop(true); | |
//设置窗口标题 | |
this.setTitle("动漫拼图"); | |
//取消JFrame的默认布局 | |
this.setLayout(null); | |
} | |
//窗体上组件的绘制 | |
public void paintview() { | |
//标题图片 | |
JLabel titleLabel = new JLabel(new ImageIcon("day\images\title.png")); | |
titleLabel.setBounds(, 27, 232, 57); | |
this.add(titleLabel); | |
//创建面板 | |
imagePanel = new JPanel(); | |
imagePanel.setBounds(, 114, 360, 360); | |
imagePanel.setLayout(null); | |
//遍历二维数组,得到图片编号 | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
//创建JLabel对象,加载图片资源 | |
JLabel imagesJlabel = new JLabel(new ImageIcon("day\\images\\" + datas[i][j] + ".png")); | |
//调整照片位置 | |
imagesJlabel.setBounds(j *, i * 90, 90, 90); | |
imagePanel.add(imagesJlabel); | |
} | |
} | |
//把面板添加到窗体上 | |
this.add(imagePanel); | |
//拼图参照图 | |
JLabel canZhaoTuLabel = new JLabel(new ImageIcon("day\images\canzhaotu.png")); | |
canZhaoTuLabel.setBounds(, 114, 122, 121); | |
this.add(canZhaoTuLabel); | |
//上下左右、求助、重置按钮 | |
shangButton = new JButton(new ImageIcon("day\images\shang.png")); | |
shangButton.setBounds(, 265, 57, 57); | |
this.add(shangButton); | |
zuoButton = new JButton(new ImageIcon("day\images\zuo.png")); | |
zuoButton.setBounds(, 347, 57, 57); | |
this.add(zuoButton); | |
xiaButton = new JButton(new ImageIcon("day\images\xia.png")); | |
xiaButton.setBounds(, 347, 57, 57); | |
this.add(xiaButton); | |
youButton = new JButton(new ImageIcon("day\images\you.png")); | |
youButton.setBounds(, 347, 57, 57); | |
this.add(youButton); | |
qiuZhuButton = new JButton(new ImageIcon("day\images\qiuzhu.png")); | |
qiuZhuButton.setBounds(, 444, 108, 45); | |
this.add(qiuZhuButton); | |
chongZhiButton = new JButton(new ImageIcon("day\images\chongzhi.png")); | |
chongZhiButton.setBounds(, 444, 108, 45); | |
this.add(chongZhiButton); | |
//展示背景图 | |
JLabel backgroundLabel = new JLabel(new ImageIcon("day\images\background.png")); | |
backgroundLabel.setBounds(, 0, 960, 530); | |
this.add(backgroundLabel); | |
//按钮添加事件 | |
shangButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (x == 3) { | |
return; | |
} | |
datas[x][y0] = datas[x0 + 1][y0]; | |
//这一步作用是啥,为什么要让datas[x+1][y0]=0; | |
//原理是交换,datas[x][y0]=0是固定的,然后把datas[x0+1][y0]赋值给datas[x0][y0] | |
//再把给datas[x0+1][y0], | |
datas[x + 1][y0] = 0; | |
x = x0 + 1; | |
//调用判断方法,成功之后调用提示按钮的方法 | |
if (isSuccess()) { | |
success(); | |
} | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
zuoButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (y == 3) { | |
return; | |
} | |
datas[x][y0] = datas[x0][y0 + 1]; | |
datas[x][y0 + 1] = 0; | |
y = y0 + 1; | |
//调用判断方法,成功之后调用提示按钮的方法 | |
if (isSuccess()) { | |
success(); | |
} | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
xiaButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (x == 0) { | |
return; | |
} | |
datas[x][y0] = datas[x0 - 1][y0]; | |
datas[x - 1][y0] = 0; | |
x = x0 - 1; | |
//调用判断方法,成功之后调用提示按钮的方法 | |
if (isSuccess()) { | |
success(); | |
} | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
youButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
if (y == 0) { | |
return; | |
} | |
datas[x][y0] = datas[x0][y0 - 1]; | |
datas[x][y0 - 1] = 0; | |
y = y0 - 1; | |
//调用判断方法,成功之后调用提示按钮的方法 | |
if (isSuccess()) { | |
success(); | |
} | |
//对图片进行重新遍历输出 | |
rePaintView(); | |
} | |
}); | |
} | |
//定义两个int类型的变量,用于记录号图片的位置 | |
//号图片作用是啥,为什么要定义0号图片 | |
//号图片作用是和数组里面的编号图片作一交换,用来完成拼图 | |
private int x; | |
private int y; | |
//打乱二维数组 | |
public void randomData() { | |
Random random = new Random(); | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
int x = random.nextInt(datas.length); | |
int y = random.nextInt(datas[i].length); | |
int temp = datas[i][j]; | |
datas[i][j] = datas[x][y]; | |
datas[x][y] = temp; | |
} | |
} | |
//记录号图片的位置 wc作用是啥?wc作用是给最外层for循环起了一个名字,之后用break结束整体循环 | |
wc: | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
if (datas[i][j] ==) { | |
x = i; | |
y = j; | |
break wc; | |
} | |
} | |
} | |
} | |
//遍历移动后的图形,移动的图形重新绘制 | |
public void rePaintView() { | |
//移除所有:移除的是JPanel标签上的全部组件,目的就是清空里面的数据 | |
imagePanel.removeAll(); | |
//遍历二维数组 | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
//创建JLabel对象,加载图片资源 | |
JLabel imagesJlabel = new JLabel(new ImageIcon("day09\\images\\" + datas[i][j] + ".png")); | |
//调整照片位置 | |
imagesJlabel.setBounds(j * 90, i * 90, 90, 90); | |
imagePanel.add(imagesJlabel); | |
} | |
} | |
//对JPanel里面的组件进行从新打印 | |
imagePanel.repaint(); | |
} | |
//定义一个成功的操作,用提示来调用 | |
public void success() { | |
datas = new int[][]{ | |
{, 2, 3, 4}, | |
{, 6, 7, 8}, | |
{, 10, 11, 12}, | |
{, 14, 15, 16} | |
}; | |
shangButton.setEnabled(false); | |
zuoButton.setEnabled(false); | |
xiaButton.setEnabled(false); | |
youButton.setEnabled(false); | |
} | |
//定义一个点击按钮判断是否成功的方法 | |
public boolean isSuccess() { | |
for (int i =; i < datas.length; i++) { | |
for (int j =; j < datas[i].length; j++) { | |
if (datas[i][j] != winDatas[i][j]) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
} |