------------java基础d9--1---项目实战2-游戏开发-数字华容道介绍---------------------------------------------
还是AI结合GUI;完成一个有趣点的项目。
准备环节:
- 创建一个模块用于开发石头迷阵游戏,模块名称为:stone-maze
- 导入项目需要的资源包到src目录下:主要是一些图片文件,
- 创建项目包:con.itheima.
------------java基础d9--2---项目实战2-游戏开发-游戏界面展示------------------------------------------------
1、创建石头迷阵的界面
- 定义主界面类,MainFrame继承JFrame。自定义窗口
- 初始化窗口大小
- 初始化界面图片
- 初始化界面菜单:系统退出,重启游戏。
PS:***JLabel label = new JLabel(icon);***可以把图片封装成一个对象;
然后***ImageIcon icon = new ImageIcon("图片地址" + imageData[i][j] + ".png");***就可以把图片给到jabel对象;;
***label.setBounds(j * 110, i * 110, 110, 110);***把这个label对象展示在某个位置。四个数据分别是X轴坐标、Y轴坐标、展示图片的宽度、展示图片的高度。
java
package com.itheima;
import javax.swing.*;
//自定义窗口类,创建对象,展示一个主窗口
public class MainFrame extends JFrame {
//2-3-1、设置图片位置
private static final String imagePath = "stone-maze/src/image/";
//2-1-1准备一个数组,用于存储数字色块的行列位置:4行4列;
private int[][] imageData = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
public MainFrame(){
//1、调用一个初始化方法,初始化窗口大小等信息。
initFrame();
//2、初始化界面,展示数字色块、背景图片
initImage();
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
initMenu();
//3、设置窗口的显示
this.setVisible(true);
}
private void initMenu() {
JMenuBar menuBar = new JMenuBar(); //创建一个菜单条
JMenu menu = new JMenu("系统"); //创建一个菜单
// menu.add(new JMenuItem("退出")); //正常来说这是一个子菜单,但是要给子菜单加功能,所以要换个写法,给他搞个对象。
//给子菜单添加一个选项,退出。
JMenuItem exitJi = new JMenuItem("退出");
menu.add(exitJi); //给子菜单添加功能
exitJi.addActionListener(e -> { //监听点击事件
dispose(); //对象exitJi的功能:销毁窗口
});
//给子菜单添加一个选项,重启
JMenuItem restartJi = new JMenuItem("重启");
menu.add(restartJi);
restartJi.addActionListener(e -> {
//功能:重启游戏
// new MainFrame();
// dispose();
});
//现在把子菜单添加到菜单条中
menuBar.add(menu);
//把菜单条添加到窗口中
this.setJMenuBar(menuBar);
}
private void initImage() {
//2-1、展示一个行列矩阵的图片,依次铺满窗口(4 * 4);
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
//2-2拿到图片名称
String imageName = imageData[i][j] + ".png";
//2-4、创建一个标签对象,把图片设置到标签上
JLabel label = new JLabel();
//2-3、创建一个数字色块对象
// label.setIcon(new ImageIcon("stone-maze/src/image/" + imageName)); //因为这里的路径写死了,以后如果项目名更改之类的,不方便
label.setIcon(new ImageIcon(imagePath + imageName)); //所以最上边写了常量路径。
//2-5、设置标签的位置
label.setBounds(22+j * 100, 60+i * 100, 100, 100);
//2-6、把图片添加到窗口中
this.add(label);
}
}
//2-7、设置窗口的背景图片
JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
background.setBounds(0, 0, 450, 484);
this.add(background);
}
private void initFrame() {
//设置窗口的标题
this.setTitle("石头迷宫 V1.0 ybz");
//设置窗口的宽高
this.setSize(465, 555);
//设置窗口的关闭模式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口居中显示
this.setLocationRelativeTo(null);
//设置窗口的绝对布局
this.setLayout(null);
// //设置窗口的显示
// this.setVisible(true); //因为发现图片不显示,所以要先布局好图片后,最后再显示窗口。这行显示代码搞到无参构造器了。
}
public static void main(String[] args) {
new MainFrame();
}
}
------------java基础d9--3---项目实战2-游戏开发-打乱游戏的界面顺序---------------------------------------
2、打乱顺序
打乱界面的图片顺序,让游戏具备可玩性:使用方法如下:
打乱二维数组中的元素顺序:initRandomArray()
java
//5、打乱二维数组中的数字
private void initRandomArray() {
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
int random = (int)(Math.random() * 16);
int temp = imageData[i][j];
imageData[i][j] = imageData[random / 4][random % 4];
imageData[random / 4][random % 4] = temp;
}
}
}
先打乱然后再显示图片:
java
public MainFrame(){
//1、调用一个初始化方法,初始化窗口大小等信息。
initFrame();
//5、打乱数组色块的顺序,再展示图片
initRandomArray();
//2、初始化界面,展示数字色块、背景图片
initImage();
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
initMenu();
//3、设置窗口的显示
this.setVisible(true);
}
------------java基础d9--4---项目实战2-游戏开发-上下左右的事件监听---------------------------------------
3、控制上下左右移动
- 给窗口绑定上下左右按键事件
- 控制位置的交换
- 重新绘制主界面的内容。
java
public MainFrame(){
//1、调用一个初始化方法,初始化窗口大小等信息。
initFrame();
//5、打乱数组色块的顺序,再展示图片
initRandomArray();
//2、初始化界面,展示数字色块、背景图片
initImage();
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
initMenu();
//6、给当前窗口绑定上下左右按键事件
initKeyPressEvent();
//3、设置窗口的显示
this.setVisible(true);
}
java
//6、给当前窗口绑定上下左右按键事件
private void initKeyPressEvent() {
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取按键的键值
int keyCode = e.getKeyCode();
//判断这个编号是否是上下左右按键
switch (keyCode) {
case KeyEvent.VK_UP:
switchAndMove(Direction.UP);
break;
case KeyEvent.VK_DOWN:
switchAndMove(Direction.DOWN);
break;
case KeyEvent.VK_LEFT:
switchAndMove(Direction.LEFT);
break;
case KeyEvent.VK_RIGHT:
switchAndMove(Direction.RIGHT);
break;
default:
System.out.println("ct运势");
break;
}
}
});
}
//6-2、控制图片移动、、、业务和功能分开。上变只负责监听,这里只负责做动作。
private void switchAndMove(Direction r) {
//控制图片移动
//想用枚举来获取按键的编号
//判断图片的方向,再控制图片移动
switch (r) {
case UP:
System.out.println("上");
break;
case DOWN:
System.out.println("下");
break;
case Direction.LEFT:
System.out.println("左");
break;
case Direction.RIGHT:
System.out.println("右");
break;
}
}
java
package com.itheima;
public enum Direction {
UP, DOWN, LEFT, RIGHT;
}
------------java基础d9--5---项目实战2-游戏开发-界面移动控制------------------------------------------------
3、控制上下左右移动
- 给窗口绑定上下左右按键事件
- 控制位置的交换
- 定位当前恐怖色块的位置
- 根据用户点击的方位确定交换哪个数据,到数组中去交换
- 重新绘制主界面的内容。
- 让主界面按照二维数组的最新内容刷新界面。
java
private void switchAndMove(Direction r) {
//控制图片移动
//想用枚举来获取按键的编号
//判断图片的方向,再控制图片移动
switch (r) {
case UP:
//上交换的条件是:行>0,才开始交换
if (rou > 0) {
//当前空白色块位置:rou, col
int temp = imageData[rou - 1][col];
imageData[rou - 1][col] = 0;
imageData[rou][col] = temp;
rou--;
}
System.out.println("上");
break;
case DOWN:
//下交换的条件是:行<3,才开始交换
if (rou < imageData.length - 1) {
//当前空白色块位置:rou, col
int temp = imageData[rou + 1][col];
imageData[rou + 1][col] = 0;
imageData[rou][col] = temp;
rou++;
}
System.out.println("下");
break;
case Direction.LEFT:
//左交换的条件是:列>0,才开始交换
if (col > 0) {
int temp = imageData[rou][col - 1];
imageData[rou][col - 1] = 0;
imageData[rou][col] = temp;
col--;
}
System.out.println("左");
break;
case Direction.RIGHT:
//右交换的条件是:列<3,才开始交换
if (col < imageData[0].length - 1) {
int temp = imageData[rou][col + 1];
imageData[rou][col + 1] = 0;
imageData[rou][col] = temp;
col++;
}
System.out.println("右");
break;
}
initImage(); //直接这样有bug;因为图片生成在了界面的底下,我们看不到。所以要更新一下initImage的代码。
}
java
//更新
private void initImage() {
//先清空窗口上的全部图层,再重新生成图片
this.getContentPane().removeAll(); //this就是指这个窗口;getContentPance是指窗口这个容器,默认有这个桌布;removeAll()是清空;合起来就是情况图层的图片。
//2-1、展示一个行列矩阵的图片,依次铺满窗口(4 * 4);
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
//2-2拿到图片名称
String imageName = imageData[i][j] + ".png";
//2-4、创建一个标签对象,把图片设置到标签上
JLabel label = new JLabel();
//2-3、创建一个数字色块对象
// label.setIcon(new ImageIcon("stone-maze/src/image/" + imageName)); //因为这里的路径写死了,以后如果项目名更改之类的,不方便
label.setIcon(new ImageIcon(imagePath + imageName)); //所以最上边写了常量路径。
//2-5、设置标签的位置
label.setBounds(22+j * 100, 60+i * 100, 100, 100);
//2-6、把图片添加到窗口中
this.add(label);
}
}
//2-7、设置窗口的背景图片
JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
background.setBounds(0, 0, 450, 484);
this.add(background);
//刷新图层重新绘制;
this.repaint();
}
------------java基础d9--6---项目实战2-游戏开发-胜利判断、游戏演示---------------------------------------
4、判断是否通过
- 用户每操作一次,需要立即判断是否已经通关,如果通过,需要显示胜利的标记。
java
//只要刷新界面,就判断一下是否赢了。
if (isWin()) {
JLabel label = new JLabel(new ImageIcon(imagePath + "win.png"));
label.setBounds(124, 230, 266, 88);
this.add(label);
}
//加在了这个代码后边。
private void initImage() {
//先清空窗口上的全部图层,再重新生成图片
this.getContentPane().removeAll(); //this就是指这个窗口;getContentPance是指窗口这个容器,默认有这个桌布;removeAll()是清空;合起来就是情况图层的图片。
//只要刷新界面,就判断一下是否赢了。
//
java
private boolean isWin() {
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if(imageData[i][j] != imageData1[i][j]){
return false;
}
}
}
return true;
}
------------java基础d9--7---项目实战2-游戏开发-重启-步数-乱序问题------------------------------------------
5、统计移动步骤、重启游戏
- 每成功移动一步,都需要累加一次步数。
- 定义一个遍历用于累加步数,并实时展示到界面上。
重启游戏:
就是重新打乱一下二维数组,然后再刷新一下界面就好了。
java
package com.itheima;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
//自定义窗口类,创建对象,展示一个主窗口
public class MainFrame extends JFrame {
//2-3-1、设置图片位置
private static final String imagePath = "stone-maze/src/image/";
//2-1-1准备一个数组,用于存储数字色块的行列位置:4行4列;
private int[][] imageData = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
private final int[][] imageData1 = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
//6-3 定义两个整数记录0所在的位置;
private int rou, col; //记录数字0所在的行列。
private int count; //统计移动的步数
public MainFrame(){
//1、调用一个初始化方法,初始化窗口大小等信息。
initFrame();
//5、打乱数组色块的顺序,再展示图片
initRandomArray();
//2、初始化界面,展示数字色块、背景图片
initImage();
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
initMenu();
//6、给当前窗口绑定上下左右按键事件
initKeyPressEvent();
//3、设置窗口的显示
this.setVisible(true);
}
//6、给当前窗口绑定上下左右按键事件
private void initKeyPressEvent() {
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取按键的键值
int keyCode = e.getKeyCode();
//判断这个编号是否是上下左右按键
switch (keyCode) {
case KeyEvent.VK_UP:
switchAndMove(Direction.UP);
break;
case KeyEvent.VK_DOWN:
switchAndMove(Direction.DOWN);
break;
case KeyEvent.VK_LEFT:
switchAndMove(Direction.LEFT);
break;
case KeyEvent.VK_RIGHT:
switchAndMove(Direction.RIGHT);
break;
case KeyEvent.VK_SPACE:
switchAndMove(Direction.SPACE);
break;
default:
System.out.println("ct运势");
break;
}
}
});
}
//6-2、控制图片移动、、、业务和功能分开。上变只负责监听,这里只负责做动作。
private void switchAndMove(Direction r) {
//控制图片移动
//想用枚举来获取按键的编号
//判断图片的方向,再控制图片移动
switch (r) {
case UP:
//上交换的条件是:行>0,才开始交换
if (rou > 0) {
//当前空白色块位置:rou, col
int temp = imageData[rou - 1][col];
imageData[rou - 1][col] = 0;
imageData[rou][col] = temp;
rou--;
count++;
}
System.out.println("上");
break;
case DOWN:
//下交换的条件是:行<3,才开始交换
if (rou < imageData.length - 1) {
//当前空白色块位置:rou, col
int temp = imageData[rou + 1][col];
imageData[rou + 1][col] = 0;
imageData[rou][col] = temp;
rou++;
count++;
}
System.out.println("下");
break;
case Direction.LEFT:
//左交换的条件是:列>0,才开始交换
if (col > 0) {
int temp = imageData[rou][col - 1];
imageData[rou][col - 1] = 0;
imageData[rou][col] = temp;
col--;
count++;
}
System.out.println("左");
break;
case Direction.RIGHT:
//右交换的条件是:列<3,才开始交换
if (col < imageData[0].length - 1) {
int temp = imageData[rou][col + 1];
imageData[rou][col + 1] = 0;
imageData[rou][col] = temp;
col++;
count++;
}
System.out.println("右");
break;
case Direction.SPACE:
imageData = imageData1;
initZhao0();
initImage();
break;
}
initImage(); //直接这样有bug;因为图片生成在了界面的底下,我们看不到。所以要更新一下initImage的代码。
}
//5、打乱二维数组中的数字
private void initRandomArray() {
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
int random = (int)(Math.random() * 16);
int temp = imageData[i][j];
imageData[i][j] = imageData[random / 4][random % 4];
imageData[random / 4][random % 4] = temp;
}
}
//找到数字零,直接把最后一个数字和0换位置。
initZhao0();
}
private void initZhao0() {
//找到0的行和列
OUT: //随便定义什么名字,一般叫 OUT。
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if (imageData[i][j] == 0) {
//定位到空白色块的位置
rou = i;
col = j;
// break; //只是结束了里面的for循环
break OUT; //结束OUT循环(即这两个for循环)。
}
}
}
}
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
private void initMenu() {
JMenuBar menuBar = new JMenuBar(); //创建一个菜单条
JMenu menu = new JMenu("系统"); //创建一个菜单
// menu.add(new JMenuItem("退出")); //正常来说这是一个子菜单,但是要给子菜单加功能,所以要换个写法,给他搞个对象。
//给子菜单添加一个选项,退出。
JMenuItem exitJi = new JMenuItem("退出");
menu.add(exitJi); //给子菜单添加功能
exitJi.addActionListener(e -> { //监听点击事件
dispose(); //对象exitJi的功能:销毁窗口
});
//给子菜单添加一个选项,重启
JMenuItem restartJi = new JMenuItem("重启");
menu.add(restartJi);
restartJi.addActionListener(e -> {
//功能:重启游戏
initRandomArray(); //重新打乱数组
initImage(); //重新生成图片
});
//现在把子菜单添加到菜单条中
menuBar.add(menu);
//把菜单条添加到窗口中
this.setJMenuBar(menuBar);
}
//2、初始化界面,展示数字色块、背景图片
private void initImage() {
//先清空窗口上的全部图层,再重新生成图片
this.getContentPane().removeAll(); //this就是指这个窗口;getContentPance是指窗口这个容器,默认有这个桌布;removeAll()是清空;合起来就是情况图层的图片。
//刷新界面的时候,显示步数:
//给窗口添加一个展示文字的组件:
JLabel countTxt = new JLabel("当前移动" + count + "步");
countTxt.setBounds(20, 20, 150, 20);
//设置文字颜色为红色
countTxt.setForeground(Color.red);
countTxt.setFont(new Font("楷体", Font.BOLD, 16));
this.add(countTxt);
//只要刷新界面,就判断一下是否赢了。
if (isWin()) {
JLabel label = new JLabel(new ImageIcon(imagePath + "win.png"));
label.setBounds(124, 230, 266, 88);
this.add(label);
}
//2-1、展示一个行列矩阵的图片,依次铺满窗口(4 * 4);
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
//2-2拿到图片名称
String imageName = imageData[i][j] + ".png";
//2-4、创建一个标签对象,把图片设置到标签上
JLabel label = new JLabel();
//2-3、创建一个数字色块对象
// label.setIcon(new ImageIcon("stone-maze/src/image/" + imageName)); //因为这里的路径写死了,以后如果项目名更改之类的,不方便
label.setIcon(new ImageIcon(imagePath + imageName)); //所以最上边写了常量路径。
//2-5、设置标签的位置
label.setBounds(22+j * 100, 60+i * 100, 100, 100);
//2-6、把图片添加到窗口中
this.add(label);
}
}
//2-7、设置窗口的背景图片
JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
background.setBounds(0, 0, 450, 484);
this.add(background);
//刷新图层重新绘制;
this.repaint();
}
//判断是否赢了
private boolean isWin() {
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if(imageData[i][j] != imageData1[i][j]){
return false;
}
}
}
return true;
}
//1、初始化窗口大小等信息。
private void initFrame() {
//设置窗口的标题
this.setTitle("石头迷宫 V1.0 ybz");
//设置窗口的宽高
this.setSize(465, 555);
//设置窗口的关闭模式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口居中显示
this.setLocationRelativeTo(null);
//设置窗口的绝对布局
this.setLayout(null);
// //设置窗口的显示
// this.setVisible(true); //因为发现图片不显示,所以要先布局好图片后,最后再显示窗口。这行显示代码搞到无参构造器了。
}
public static void main(String[] args) {
new MainFrame();
}
}
自己加了一个按空格就直接恢复正确顺序。
16分钟,还有一个算法问题,随机打乱顺序可能有无法复原的情况。
大概原理就是让电脑循环一定次数,电脑来直接模拟人的操作来进行打乱,把原先的打乱模式去掉。
总代码:
java
package com.itheima;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
//自定义窗口类,创建对象,展示一个主窗口
public class MainFrame extends JFrame {
//2-3-1、设置图片位置
private static final String imagePath = "stone-maze/src/image/";
//2-1-1准备一个数组,用于存储数字色块的行列位置:4行4列;
private int[][] imageData = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
private final int[][] imageData1 = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
//6-3 定义两个整数记录0所在的位置;
private int rou, col; //记录数字0所在的行列。
private int count; //统计移动的步数
public MainFrame(){
//1、调用一个初始化方法,初始化窗口大小等信息。
initFrame();
//5、打乱数组色块的顺序,再展示图片
initRandomArray();
//2、初始化界面,展示数字色块、背景图片
initImage();
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
initMenu();
//6、给当前窗口绑定上下左右按键事件
initKeyPressEvent();
//3、设置窗口的显示
this.setVisible(true);
}
//6、给当前窗口绑定上下左右按键事件
private void initKeyPressEvent() {
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取按键的键值
int keyCode = e.getKeyCode();
//判断这个编号是否是上下左右按键
switch (keyCode) {
case KeyEvent.VK_UP:
switchAndMove(Direction.UP);
break;
case KeyEvent.VK_DOWN:
switchAndMove(Direction.DOWN);
break;
case KeyEvent.VK_LEFT:
switchAndMove(Direction.LEFT);
break;
case KeyEvent.VK_RIGHT:
switchAndMove(Direction.RIGHT);
break;
case KeyEvent.VK_SPACE:
switchAndMove(Direction.SPACE);
break;
default:
System.out.println("ct运势");
break;
}
}
});
}
//6-2、控制图片移动、、、业务和功能分开。上变只负责监听,这里只负责做动作。
private void switchAndMove(Direction r) {
//控制图片移动
//想用枚举来获取按键的编号
//判断图片的方向,再控制图片移动
switch (r) {
case UP:
//上交换的条件是:行>0,才开始交换
if (rou > 0) {
//当前空白色块位置:rou, col
int temp = imageData[rou - 1][col];
imageData[rou - 1][col] = 0;
imageData[rou][col] = temp;
rou--;
count++;
}
System.out.println("上");
break;
case DOWN:
//下交换的条件是:行<3,才开始交换
if (rou < imageData.length - 1) {
//当前空白色块位置:rou, col
int temp = imageData[rou + 1][col];
imageData[rou + 1][col] = 0;
imageData[rou][col] = temp;
rou++;
count++;
}
System.out.println("下");
break;
case Direction.LEFT:
//左交换的条件是:列>0,才开始交换
if (col > 0) {
int temp = imageData[rou][col - 1];
imageData[rou][col - 1] = 0;
imageData[rou][col] = temp;
col--;
count++;
}
System.out.println("左");
break;
case Direction.RIGHT:
//右交换的条件是:列<3,才开始交换
if (col < imageData[0].length - 1) {
int temp = imageData[rou][col + 1];
imageData[rou][col + 1] = 0;
imageData[rou][col] = temp;
col++;
count++;
}
System.out.println("右");
break;
case Direction.SPACE:
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
imageData[i][j] = imageData1[i][j];
}
}
initZhao0();
initImage();
break;
}
initImage(); //直接这样有bug;因为图片生成在了界面的底下,我们看不到。所以要更新一下initImage的代码。
}
//5、打乱二维数组中的数字
private void initRandomArray() {
//这种方式可能会导致无法复原,所以搞另一种打乱方式:
// for (int i = 0; i < imageData.length; i++) {
// for (int j = 0; j < imageData[i].length; j++) {
// int random = (int)(Math.random() * 16);
// int temp = imageData[i][j];
// imageData[i][j] = imageData[random / 4][random % 4];
// imageData[random / 4][random % 4] = temp;
// }
// }
//找到数字零,直接把最后一个数字和0换位置。
initZhao0();
//生成一个10的随机数
int random = (int)(Math.random() * 100);
random = random + 200;
for (int i = 0; i < random; i++) {
//生成一个4的随机数
int random1 = (int)(Math.random() * 4);
switch (random1) {
case 0:
switchAndMove(Direction.UP);
break;
case 1:
switchAndMove(Direction.DOWN);
break;
case 2:
switchAndMove(Direction.LEFT);
break;
case 3:
switchAndMove(Direction.RIGHT);
break;
}
}
count = 0;
}
private void initZhao0() {
//找到0的行和列
OUT: //随便定义什么名字,一般叫 OUT。
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if (imageData[i][j] == 0) {
//定位到空白色块的位置
rou = i;
col = j;
// break; //只是结束了里面的for循环
break OUT; //结束OUT循环(即这两个for循环)。
}
}
}
}
//4、初始化系统的菜单,点击弹出菜单信息是系统退出、重启游戏。
private void initMenu() {
JMenuBar menuBar = new JMenuBar(); //创建一个菜单条
JMenu menu = new JMenu("系统"); //创建一个菜单
// menu.add(new JMenuItem("退出")); //正常来说这是一个子菜单,但是要给子菜单加功能,所以要换个写法,给他搞个对象。
//给子菜单添加一个选项,退出。
JMenuItem exitJi = new JMenuItem("退出");
menu.add(exitJi); //给子菜单添加功能
exitJi.addActionListener(e -> { //监听点击事件
dispose(); //对象exitJi的功能:销毁窗口
});
//给子菜单添加一个选项,重启
JMenuItem restartJi = new JMenuItem("重启");
menu.add(restartJi);
restartJi.addActionListener(e -> {
//功能:重启游戏
initRandomArray(); //重新打乱数组
initImage(); //重新生成图片
});
//现在把子菜单添加到菜单条中
menuBar.add(menu);
//把菜单条添加到窗口中
this.setJMenuBar(menuBar);
}
//2、初始化界面,展示数字色块、背景图片
private void initImage() {
//先清空窗口上的全部图层,再重新生成图片
this.getContentPane().removeAll(); //this就是指这个窗口;getContentPance是指窗口这个容器,默认有这个桌布;removeAll()是清空;合起来就是情况图层的图片。
//刷新界面的时候,显示步数:
//给窗口添加一个展示文字的组件:
JLabel countTxt = new JLabel("当前移动" + count + "步");
countTxt.setBounds(20, 20, 150, 20);
//设置文字颜色为红色
countTxt.setForeground(Color.red);
countTxt.setFont(new Font("楷体", Font.BOLD, 16));
this.add(countTxt);
//只要刷新界面,就判断一下是否赢了。
if (isWin()) {
JLabel label = new JLabel(new ImageIcon(imagePath + "win.png"));
label.setBounds(124, 230, 266, 88);
this.add(label);
}
//2-1、展示一个行列矩阵的图片,依次铺满窗口(4 * 4);
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
//2-2拿到图片名称
String imageName = imageData[i][j] + ".png";
//2-4、创建一个标签对象,把图片设置到标签上
JLabel label = new JLabel();
//2-3、创建一个数字色块对象
// label.setIcon(new ImageIcon("stone-maze/src/image/" + imageName)); //因为这里的路径写死了,以后如果项目名更改之类的,不方便
label.setIcon(new ImageIcon(imagePath + imageName)); //所以最上边写了常量路径。
//2-5、设置标签的位置
label.setBounds(22+j * 100, 60+i * 100, 100, 100);
//2-6、把图片添加到窗口中
this.add(label);
}
}
//2-7、设置窗口的背景图片
JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
background.setBounds(0, 0, 450, 484);
this.add(background);
//刷新图层重新绘制;
this.repaint();
}
//判断是否赢了
private boolean isWin() {
for (int i = 0; i < imageData.length; i++) {
for (int j = 0; j < imageData[i].length; j++) {
if(imageData[i][j] != imageData1[i][j]){
return false;
}
}
}
return true;
}
//1、初始化窗口大小等信息。
private void initFrame() {
//设置窗口的标题
this.setTitle("石头迷宫 V1.0 ybz");
//设置窗口的宽高
this.setSize(465, 555);
//设置窗口的关闭模式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口居中显示
this.setLocationRelativeTo(null);
//设置窗口的绝对布局
this.setLayout(null);
// //设置窗口的显示
// this.setVisible(true); //因为发现图片不显示,所以要先布局好图片后,最后再显示窗口。这行显示代码搞到无参构造器了。
}
public static void main(String[] args) {
new MainFrame();
}
}