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