侧边栏壁纸
博主头像
青菜-halo2 博主等级

行动起来,活在当下

  • 累计撰写 74 篇文章
  • 累计创建 6 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

17-阶段项目-拼图小游戏_02

Administrator
2025-11-28 / 0 评论 / 0 点赞 / 8 阅读 / 0 字

6.美化界面

6.1 调整 jLabel 小图片位置

    private void initImage() {
                //指定图片位置
                jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 
    }

6.2 加入背景图片

//细节:先加载的图片会在上方,后加载的图片在下面
​
        //添加背景图片
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
        JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
        background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
        this.getContentPane().add(background);  //将背景添加到界面中

6.3 JLabel 中给图片设置边框

                //给图片添加边框  0:让图片凸起来   1:表示让图片凹下去
                jLabel.setBorder(new BevelBorder(1));
                //jLabel.setBorder(new BevelBorder(BevelBorder.RAISED)); //让图片凸起来 0
                //jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); //让图片凹下去 1

6.4 路径优化

//路径分为两种:
//绝对路径:从盘符开始
//相对路径:非盘符开始
                JLabel jLabel = new JLabel(new ImageIcon("day16-day17\\image\\animal\\animal3\\" + num + ".jpg"));
​
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
​
​

6.5 完整代码

GameJFrame.java

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.util.Random;
​
public class GameJFrame extends JFrame {
    //创建一个二维数组,用来管理数据,加载图片时,会根据二维数组中的数据进行加载
    int[][] data = new int[4][4];
​
    //游戏相关的所有代码,在此类中
    public GameJFrame() {
        //初始化界面
        initJFrame();
​
        //初始化菜单
        initJMnuBar();
​
        //初始化数据(打乱)
        initData();
​
        //初始化图片(根据打乱之后的结果去加载图片)
        initImage();
​
        //让界面显示,写在最后
        this.setVisible(true);
    }
​
    //初始化数据(打乱)
    private void initData() {
        //定义一个一维数组
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        //打乱数组中数据的顺序
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            //获取随机索引
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[i];
            tempArr[i] = tempArr[index];
            tempArr[index] = temp;
        }
​
        //给二维数组添加数据
        /*
        //解法一:遍历一维数组tempArr得到每一个元素,然后把每一个元素添加到二维数组中
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
        //遍历二维数组
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.print(data[i][j]+ " ");
            }
            System.out.println();
        }
        */
​
        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                data[i][j] = tempArr[index];
                index++;
            }
        }
    }
​
    //初始化图片,添加图片时,需要按照二维数组中管理的数据添加图片
    private void initImage() {
​
​
        //细节:先加载的图片会在上方,后加载的图片在下面
​
        //外循环 -- 将内循环重复执行了4次
        for (int i = 0; i < 4; i++) {
            //内循环 -- 表示在一行添加4张图片
            for (int j = 0; j < 4; j++) {
                //获取当前加载图片的序号
                int num = data[i][j];
​
                //创建一个JLable的对象(管理容器)
                JLabel jLabel = new JLabel(new ImageIcon("day16-day17\\image\\animal\\animal3\\" + num + ".jpg"));
                //指定图片位置
                jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);
​
                //给图片添加边框  0:让图片凸起来   1:表示让图片凹下去
                jLabel.setBorder(new BevelBorder(1));
                //jLabel.setBorder(new BevelBorder(BevelBorder.RAISED)); //让图片凸起来 0
                //jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); //让图片凹下去 1
​
                //将管理容器添加到界面中
                //this.add(jLabel);
                this.getContentPane().add(jLabel);
            }
        }
​
        //添加背景图片
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
        JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
        background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
        this.getContentPane().add(background);  //将背景添加到界面中
    }
​
​
    private void initJMnuBar() {
​
        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();
​
        //创建菜单上面的两个选项的对象(功能 关于我们)
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我们");
​
        //创建选项下面的条目对象
        JMenuItem replayItem = new JMenuItem("重新游戏");
        JMenuItem reLoginItem = new JMenuItem("重新登录");
        JMenuItem closeItem = new JMenuItem("关闭游戏");
​
        JMenuItem accountItem = new JMenuItem("公众号");
​
        //将每一个选项下面的条目,添加到选项中
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);
​
        aboutJMenu.add(accountItem);
​
        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);
​
        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }
​
    private void initJFrame() {
        //设置界面的宽高
        this.setSize(603, 680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        //this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setDefaultCloseOperation(3);
​
        //取消默认剧中放置
        this.setLayout(null);
    }
}

App.java

import com.yq.ui.GameJFrame;
​
public class App {
    public static void main(String[] args) {
        //表示程序的启动入口
        //new LoginJFrame();
        //new RegisterJFrame();
        new GameJFrame();
    }
}

7.移动图片

上移动:将空白下面的图片,向上移动

7.1 添加事件

给整个界面添加键盘监听事件 KeyListener

public class GameJFrame extends JFrame implements KeyListener {
    private void initJFrame() {
        //。。。
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
​
    }
​
    @Override
    public void keyPressed(KeyEvent e) {
​
    }
​
    @Override
    public void keyReleased(KeyEvent e) {
​
    }
}
​

7.2 统计空白图片的位置

data 数据中,值为0 的索引(x, y)记录

public class GameJFrame extends JFrame implements KeyListener {
    //记录空白方块在二维数组中的位置
    int x = 0;
    int y = 0;
​
    //游戏相关的所有代码,在此类中
    public GameJFrame() {
        //...
    }
​
    //初始化数据(打乱)
    private void initData() {
​
        //给二维数组添加数据
        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (tempArr[index] == 0) {
                    x = i;
                    y = j;
                    index++;
                } else {
                    data[i][j] = tempArr[index];
                    index++;
                }
            }
        }
        
        
    }
}
​

7.3 移动逻辑

逻辑:将空白下方的数字往上移动

值为0 的索引(2, 1) 表示空白方块,(2+1, 1)表示空白下方的方块

值为0 的索引(x, y) 表示空白方块,(x+1, y)表示空白下方的方块

image-20251118230344111

示例代码:

//按键逻辑
@Override
public void keyReleased(KeyEvent e) {
    //对 上37、下38、左39、右40 进行判断
	int code = e.getKeyCode();
    if (code == 38) {
                System.out.println("向上移动");
                //将空白方块与下方的方块进行调换
                data[x][y] = data[x+1][y]; //空白下面方块的值,赋值给空白方块
                data[x+1][y] = 0; //空白下方方块的值,定义为0
                x++; //调换以后,表示空白的索引(x,y)发生了变化,需要x+1
                initImage(); //重新加载图片

    }
}

//更新重新加载图片的代码
    private void initImage() {
        //清空如果已经存在的图片
        this.getContentPane().removeAll();

        //刷新界面
        this.getContentPane().repaint();
    }

7.4 移动的小bug

需要处理空白方块在边界时,索引的变化问题

//按键逻辑
@Override
public void keyReleased(KeyEvent e) {
    
    //对 上37、下38、左39、右40 进行判断
	int code = e.getKeyCode();
    if (code == 38) {
        System.out.println("向上移动");
        if (x == 3) {
                //表示空白方块已经在最下方,下面没有方块,不能再执行往上移动
                return;
        }
        //将空白方块与下方的方块进行调换
        data[x][y] = data[x+1][y]; //空白下面方块的值,赋值给空白方块
        data[x+1][y] = 0; //空白下方方块的值,定义为0
        x++; //调换以后,表示空白的索引(x,y)发生了变化,需要x+1
        initImage(); //重新加载图片
    }
    
}

7.5 完整代码

GameJFrame.java

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class GameJFrame extends JFrame implements KeyListener {
    //创建一个二维数组,用来管理数据,加载图片时,会根据二维数组中的数据进行加载
    int[][] data = new int[4][4];

    //记录空白方块在二维数组中的位置
    int x = 0;
    int y = 0;

    //游戏相关的所有代码,在此类中
    public GameJFrame() {
        //初始化界面
        initJFrame();

        //初始化菜单
        initJMnuBar();

        //初始化数据(打乱)
        initData();

        //初始化图片(根据打乱之后的结果去加载图片)
        initImage();

        //让界面显示,写在最后
        this.setVisible(true);
    }

    //初始化数据(打乱)
    private void initData() {
        //定义一个一维数组
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        //打乱数组中数据的顺序
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            //获取随机索引
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[i];
            tempArr[i] = tempArr[index];
            tempArr[index] = temp;
        }

        //给二维数组添加数据
        /*
        //解法一:遍历一维数组tempArr得到每一个元素,然后把每一个元素添加到二维数组中
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
        //遍历二维数组
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.print(data[i][j]+ " ");
            }
            System.out.println();
        }
        */

        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (tempArr[index] == 0) {
                    x = i;
                    y = j;
                    index++;
                } else {
                    data[i][j] = tempArr[index];
                    index++;
                }
            }
        }
    }

    //初始化图片,添加图片时,需要按照二维数组中管理的数据添加图片
    private void initImage() {

        //清空如果已经存在的图片
        this.getContentPane().removeAll();
        //细节:先加载的图片会在上方,后加载的图片在下面

        //外循环 -- 将内循环重复执行了4次
        for (int i = 0; i < 4; i++) {
            //内循环 -- 表示在一行添加4张图片
            for (int j = 0; j < 4; j++) {
                //获取当前加载图片的序号
                int num = data[i][j];

                //创建一个JLable的对象(管理容器)
                JLabel jLabel = new JLabel(new ImageIcon("day16-day17\\image\\animal\\animal3\\" + num + ".jpg"));
                //指定图片位置
                jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);

                //给图片添加边框  0:让图片凸起来   1:表示让图片凹下去
                jLabel.setBorder(new BevelBorder(1));
                //jLabel.setBorder(new BevelBorder(BevelBorder.RAISED)); //让图片凸起来 0
                //jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); //让图片凹下去 1

                //将管理容器添加到界面中
                //this.add(jLabel);
                this.getContentPane().add(jLabel);
            }
        }

        //添加背景图片
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
        JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
        background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
        this.getContentPane().add(background);  //将背景添加到界面中

        //刷新界面
        this.getContentPane().repaint();
    }


    private void initJMnuBar() {

        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();

        //创建菜单上面的两个选项的对象(功能 关于我们)
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我们");

        //创建选项下面的条目对象
        JMenuItem replayItem = new JMenuItem("重新游戏");
        JMenuItem reLoginItem = new JMenuItem("重新登录");
        JMenuItem closeItem = new JMenuItem("关闭游戏");

        JMenuItem accountItem = new JMenuItem("公众号");

        //将每一个选项下面的条目,添加到选项中
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        aboutJMenu.add(accountItem);

        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }

    private void initJFrame() {
        //设置界面的宽高
        this.setSize(603, 680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        //this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setDefaultCloseOperation(3);

        //取消默认剧中放置
        this.setLayout(null);
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {
        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 37) {
            System.out.println("向左移动");
            if (y == 3) {
                return;
            }
            data[x][y] = data[x][y + 1];
            data[x][y + 1] = 0;
            y++;
            initImage();
        } else if (code == 38) {
            System.out.println("向上移动");
            if (x == 3) {
                //表示空白方块已经在最下方,下面没有方块,不能再执行往上移动
                return;
            }
            //将空白方块与下方的方块进行调换
            data[x][y] = data[x + 1][y]; //空白下面方块的值,赋值给空白方块
            data[x + 1][y] = 0; //空白下方方块的值,定义为0
            x++; //调换以后,表示空白的索引(x,y)发生了变化,需要x+1
            initImage(); //重新加载图片

        } else if (code == 39) {
            System.out.println("向右移动");
            if (y == 0) {
                return;
            }
            data[x][y] = data[x][y - 1];
            data[x][y - 1] = 0;
            y--;
            initImage();
        } else if (code == 40) {
            System.out.println("向下移动");
            if (x == 0) {
                return;
            }
            data[x][y] = data[x - 1][y];
            data[x - 1][y] = 0;
            x--;
            initImage();
        }
    }

}

App.java

public class App {
    public static void main(String[] args) {
        //表示程序的启动入口
        //new LoginJFrame();
        //new RegisterJFrame();
        new GameJFrame();
    }
}

8.查看完整图片

8.1 完整图片的键盘事件

GameJFrame.java

public class GameJFrame extends JFrame implements KeyListener {

    
//按下不松时会调用此方法
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == 65){
            System.out.println("按着A不松");
            //删除界面中所有的图片
            this.getContentPane().removeAll();
            //加载第一张完整的图片
            JLabel all = new JLabel(new ImageIcon("day16-day17\\image\\animal\\animal4\\all.jpg"));
            all.setBounds(83,134,420,420);
            this.getContentPane().add(all);
            //添加背景图片
            ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
            JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
            background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
            this.getContentPane().add(background);  //将背景添加到界面中
            //刷新界面
            this.getContentPane().repaint();

        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 65) {
            initImage();
        }
    }
}

8.2 优化路径设置

GameJFrame.java

public class GameJFrame extends JFrame implements KeyListener {
	//定义一个变量,记录图片路径
    String path = "day16-day17\\image\\animal\\animal4\\";
    
    
   
    //创建一个JLable的对象(管理容器)
                JLabel jLabel = new JLabel(new ImageIcon(path + num + ".jpg"));
    
    
    //加载第一张完整的图片
            JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));

8.3 完整代码

GameJFrame.java

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class GameJFrame extends JFrame implements KeyListener {
    //创建一个二维数组,用来管理数据,加载图片时,会根据二维数组中的数据进行加载
    int[][] data = new int[4][4];

    //记录空白方块在二维数组中的位置
    int x = 0;
    int y = 0;

    //定义一个变量,记录图片路径
    String path = "day16-day17\\image\\animal\\animal4\\";

    //游戏相关的所有代码,在此类中
    public GameJFrame() {
        //初始化界面
        initJFrame();

        //初始化菜单
        initJMnuBar();

        //初始化数据(打乱)
        initData();

        //初始化图片(根据打乱之后的结果去加载图片)
        initImage();

        //让界面显示,写在最后
        this.setVisible(true);
    }

    //初始化数据(打乱)
    private void initData() {
        //定义一个一维数组
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        //打乱数组中数据的顺序
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            //获取随机索引
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[i];
            tempArr[i] = tempArr[index];
            tempArr[index] = temp;
        }

        //给二维数组添加数据
        /*
        //解法一:遍历一维数组tempArr得到每一个元素,然后把每一个元素添加到二维数组中
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
        //遍历二维数组
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.print(data[i][j]+ " ");
            }
            System.out.println();
        }
        */

        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (tempArr[index] == 0) {
                    x = i;
                    y = j;
                    index++;
                } else {
                    data[i][j] = tempArr[index];
                    index++;
                }
            }
        }
    }

    //初始化图片,添加图片时,需要按照二维数组中管理的数据添加图片
    private void initImage() {

        //清空如果已经存在的图片
        this.getContentPane().removeAll();
        //细节:先加载的图片会在上方,后加载的图片在下面

        //外循环 -- 将内循环重复执行了4次
        for (int i = 0; i < 4; i++) {
            //内循环 -- 表示在一行添加4张图片
            for (int j = 0; j < 4; j++) {
                //获取当前加载图片的序号
                int num = data[i][j];

                //创建一个JLable的对象(管理容器)
                JLabel jLabel = new JLabel(new ImageIcon(path + num + ".jpg"));
                //指定图片位置
                jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);

                //给图片添加边框  0:让图片凸起来   1:表示让图片凹下去
                jLabel.setBorder(new BevelBorder(1));
                //jLabel.setBorder(new BevelBorder(BevelBorder.RAISED)); //让图片凸起来 0
                //jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); //让图片凹下去 1

                //将管理容器添加到界面中
                //this.add(jLabel);
                this.getContentPane().add(jLabel);
            }
        }

        //添加背景图片
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
        JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
        background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
        this.getContentPane().add(background);  //将背景添加到界面中

        //刷新界面
        this.getContentPane().repaint();
    }


    private void initJMnuBar() {

        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();

        //创建菜单上面的两个选项的对象(功能 关于我们)
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我们");

        //创建选项下面的条目对象
        JMenuItem replayItem = new JMenuItem("重新游戏");
        JMenuItem reLoginItem = new JMenuItem("重新登录");
        JMenuItem closeItem = new JMenuItem("关闭游戏");

        JMenuItem accountItem = new JMenuItem("公众号");

        //将每一个选项下面的条目,添加到选项中
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        aboutJMenu.add(accountItem);

        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }

    private void initJFrame() {
        //设置界面的宽高
        this.setSize(603, 680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        //this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setDefaultCloseOperation(3);

        //取消默认剧中放置
        this.setLayout(null);
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //按下不松时会调用此方法
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == 65){
            System.out.println("按着A不松");
            //删除界面中所有的图片
            this.getContentPane().removeAll();
            //加载第一张完整的图片
            JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));
            all.setBounds(83,134,420,420);
            this.getContentPane().add(all);
            //添加背景图片
            ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
            JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
            background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
            this.getContentPane().add(background);  //将背景添加到界面中
            //刷新界面
            this.getContentPane().repaint();

        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 37) {
            System.out.println("向左移动");
            if (y == 3) {
                return;
            }
            data[x][y] = data[x][y + 1];
            data[x][y + 1] = 0;
            y++;
            initImage();
        } else if (code == 38) {
            System.out.println("向上移动");
            if (x == 3) {
                //表示空白方块已经在最下方,下面没有方块,不能再执行往上移动
                return;
            }
            //将空白方块与下方的方块进行调换
            data[x][y] = data[x + 1][y]; //空白下面方块的值,赋值给空白方块
            data[x + 1][y] = 0; //空白下方方块的值,定义为0
            x++; //调换以后,表示空白的索引(x,y)发生了变化,需要x+1
            initImage(); //重新加载图片

        } else if (code == 39) {
            System.out.println("向右移动");
            if (y == 0) {
                return;
            }
            data[x][y] = data[x][y - 1];
            data[x][y - 1] = 0;
            y--;
            initImage();
        } else if (code == 40) {
            System.out.println("向下移动");
            if (x == 0) {
                return;
            }
            data[x][y] = data[x - 1][y];
            data[x - 1][y] = 0;
            x--;
            initImage();
        } else if (code == 65) {
            initImage();
        }
    }

}

9.作弊码

9.1 作弊码的键盘事件

GameJFrame.java

public class GameJFrame extends JFrame implements KeyListener {
    //按下按键的时候会调用这个方法
    @Override
    public void keyReleased(KeyEvent e) {
        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 87) {
            data = new int[][]{
                    {1,2,3,4},
                    {5,6,7,8},
                    {9,10,11,12},
                    {13,14,15,0}
            };
            initImage();
        }
    }
}

10.判断胜利

  • 判断二维数组中数字是否正确

1.定义正确的二维数组win
2.加载图片之前,判断二维数组中数字与win数组是否相同
3.相同则显示胜利图标
4.不同则不显示胜利图标

10.1 胜利逻辑

public class GameJFrame extends JFrame implements KeyListener {

    //定义二位数组,存储正确的数据
    int[][] win = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };

    private void initImage() {

        //清空如果已经存在的图片
        this.getContentPane().removeAll();
        //细节:先加载的图片会在上方,后加载的图片在下面

        if (victory()){
            //显示胜利图标
            JLabel winJLbel = new JLabel(new ImageIcon("day16-day17\\image\\win.png"));
            winJLbel.setBounds(203,283,197,73);
            this.getContentPane().add(winJLbel);
        }
        
        //。。。其他逻辑
    }
    
    //判断data数组中数据 与 win数据是否相同。相同则返回true,否则返回false
    public boolean victory() {
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != win[i][j]) {
                    //只要有一个数据不一样,则返回false
                    return false;
                }
            }
        }
        //循环遍历结束,表示全都一样,返回true
        return true;
    }
}

10.2 胜利后不能再移动图片

    public void keyReleased(KeyEvent e) {
        //判断游戏是否胜利,若胜利,此方法不能再执行
        if (victory()) {
            return; //结束方法
        }
    }

11.计步功能

1.定义变量用来统计步数 2.每次按上下左右,变量自增一次

public class GameJFrame extends JFrame implements KeyListener {

    //定义变量,统计步数
    int step = 0;

    private void initImage() {

        //清空如果已经存在的图片
        this.getContentPane().removeAll();
        //细节:先加载的图片会在上方,后加载的图片在下面

        if (victory()) {
            //显示胜利图标
            JLabel winJLbel = new JLabel(new ImageIcon("day16-day17\\image\\win.png"));
            winJLbel.setBounds(203, 283, 197, 73);
            this.getContentPane().add(winJLbel);
        }

        //界面中放入显示步数的位置
        JLabel stepCount = new JLabel("步数: " + step);
        stepCount.setBounds(50, 30, 100, 20);
        this.getContentPane().add(stepCount);
    	
        //...
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
        //判断游戏是否胜利,若胜利,此方法不能再执行
        if (victory()) {
            return; //结束方法
        }

        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 37) {
            System.out.println("向左移动");
            if (y == 3) {
                return;
            }
            data[x][y] = data[x][y + 1];
            data[x][y + 1] = 0;
            y++;

            //每次移动,计步器自增一次
            step++;

            initImage();
        } 
        
        //其他类似
        
    }
}

12.重新开始

1.给重新游戏绑定点击事件 ActionListener 2.重新打乱二维数组中的数字、加载图片 3.计步器清零

public class GameJFrame extends JFrame implements KeyListener, ActionListener {

    //创建选项下面的条目对象
    JMenuItem replayItem = new JMenuItem("重新游戏");
    JMenuItem reLoginItem = new JMenuItem("重新登录");
    JMenuItem closeItem = new JMenuItem("关闭游戏");

    JMenuItem accountItem = new JMenuItem("公众号");
    
    private void initData() {
        //定义一个一维数组
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        //打乱数组中数据的顺序
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            //获取随机索引
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[i];
            tempArr[i] = tempArr[index];
            tempArr[index] = temp;
        }

        //给二维数组添加数据
        /*
        //解法一:遍历一维数组tempArr得到每一个元素,然后把每一个元素添加到二维数组中
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
        //遍历二维数组
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.print(data[i][j]+ " ");
            }
            System.out.println();
        }
        */

        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (tempArr[index] == 0) {
                    x = i;
                    y = j;
                }
                //无论一维数组中的值是否为0,都要赋值给二维数组,避免游戏重开以后,空白图片消失
                data[i][j] = tempArr[index];
                index++;
            }
        }
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        Object obj = e.getSource();
        if (obj == replayItem) {
            System.out.println("重新游戏");
            //计步器清零
            step = 0;
            //再次打乱二位数组中数据
            initData();
            //重新加载图片
            initImage();

        }
    }
    
}

13.重新登录、关闭游戏

    @Override
    public void actionPerformed(ActionEvent e) {
        Object obj = e.getSource();
        if (obj == replayItem) {
            System.out.println("重新游戏");
            //计步器清零
            step = 0;
            //再次打乱二位数组中数据
            initData();
            //重新加载图片
            initImage();

        } else if (obj == reLoginItem) {
            System.out.println("重新登录");
            //关闭当前的游戏界面
            this.setVisible(false);
            //打开登录界面
            new LoginJFrame();
        } else if (obj == closeItem) {
            System.out.println("关闭游戏");
            //直接关闭虚拟机即可
            System.exit(0);
        } 
    }

14.关于我们

    @Override
    public void actionPerformed(ActionEvent e) {
        Object obj = e.getSource();
       
        if (obj == accountItem) {
            System.out.println("公众号");

            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建管理图片的容器对象JLabel
            JLabel jLabel = new JLabel(new ImageIcon("day16-day17\\image\\about.png"));
            jLabel.setBounds(0,0,258,258);  //位置是相对于弹框设置的
            jDialog.getContentPane().add(jLabel); //将图片放入弹框
            jDialog.setSize(344,344); //设置弹框大小
            jDialog.setAlwaysOnTop(true);  //让弹框置顶
            jDialog.setLocationRelativeTo(null); //让弹框居中
            jDialog.setModal(true); //弹框不关闭,则无法操作下面的界面
            jDialog.setVisible(true);  //显示弹框
            
        }
    }

15.完整代码

GameJFrame.java

package com.yq.ui;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class GameJFrame extends JFrame implements KeyListener, ActionListener {
    //创建一个二维数组,用来管理数据,加载图片时,会根据二维数组中的数据进行加载
    int[][] data = new int[4][4];

    //记录空白方块在二维数组中的位置
    int x = 0;
    int y = 0;

    //定义一个变量,记录图片路径
    String path = "day16-day17\\image\\animal\\animal3\\";

    //定义二位数组,存储正确的数据
    int[][] win = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };

    //定义变量,统计步数
    int step = 0;

    //创建选项下面的条目对象
    JMenuItem replayItem = new JMenuItem("重新游戏");
    JMenuItem reLoginItem = new JMenuItem("重新登录");
    JMenuItem closeItem = new JMenuItem("关闭游戏");

    JMenuItem accountItem = new JMenuItem("公众号");

    //游戏相关的所有代码,在此类中
    public GameJFrame() {
        //初始化界面
        initJFrame();

        //初始化菜单
        initJMnuBar();

        //初始化数据(打乱)
        initData();

        //初始化图片(根据打乱之后的结果去加载图片)
        initImage();

        //让界面显示,写在最后
        this.setVisible(true);
    }

    //初始化数据(打乱)
    private void initData() {
        //定义一个一维数组
        int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
        //打乱数组中数据的顺序
        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            //获取随机索引
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[i];
            tempArr[i] = tempArr[index];
            tempArr[index] = temp;
        }

        //给二维数组添加数据
        /*
        //解法一:遍历一维数组tempArr得到每一个元素,然后把每一个元素添加到二维数组中
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
        //遍历二维数组
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.print(data[i][j]+ " ");
            }
            System.out.println();
        }
        */

        //解法二:遍历二维数组,给里面的每一个数组赋值
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (tempArr[index] == 0) {
                    x = i;
                    y = j;
                }
                data[i][j] = tempArr[index];
                index++;
            }
        }
    }

    //初始化图片,添加图片时,需要按照二维数组中管理的数据添加图片
    private void initImage() {

        //清空如果已经存在的图片
        this.getContentPane().removeAll();
        //细节:先加载的图片会在上方,后加载的图片在下面

        if (victory()) {
            //显示胜利图标
            JLabel winJLbel = new JLabel(new ImageIcon("day16-day17\\image\\win.png"));
            winJLbel.setBounds(203, 283, 197, 73);
            this.getContentPane().add(winJLbel);
        }

        //界面中放入显示步数的位置
        JLabel stepCount = new JLabel("步数: " + step);
        stepCount.setBounds(50, 30, 100, 20);
        this.getContentPane().add(stepCount);

        //外循环 -- 将内循环重复执行了4次
        for (int i = 0; i < 4; i++) {
            //内循环 -- 表示在一行添加4张图片
            for (int j = 0; j < 4; j++) {
                //获取当前加载图片的序号
                int num = data[i][j];

                //创建一个JLable的对象(管理容器)
                JLabel jLabel = new JLabel(new ImageIcon(path + num + ".jpg"));
                //指定图片位置
                jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);

                //给图片添加边框  0:让图片凸起来   1:表示让图片凹下去
                jLabel.setBorder(new BevelBorder(1));
                //jLabel.setBorder(new BevelBorder(BevelBorder.RAISED)); //让图片凸起来 0
                //jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); //让图片凹下去 1

                //将管理容器添加到界面中
                //this.add(jLabel);
                this.getContentPane().add(jLabel);
            }
        }

        //添加背景图片
        ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
        JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
        background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
        this.getContentPane().add(background);  //将背景添加到界面中

        //刷新界面
        this.getContentPane().repaint();
    }


    private void initJMnuBar() {

        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();

        //创建菜单上面的两个选项的对象(功能 关于我们)
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我们");

        //将每一个选项下面的条目,添加到选项中
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        aboutJMenu.add(accountItem);


        //给条目绑定事件
        replayItem.addActionListener(this);
        reLoginItem.addActionListener(this);
        closeItem.addActionListener(this);
        accountItem.addActionListener(this);

        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }

    private void initJFrame() {
        //设置界面的宽高
        this.setSize(603, 680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        //this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setDefaultCloseOperation(3);

        //取消默认剧中放置
        this.setLayout(null);
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //按下不松时会调用此方法
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == 65) {
            System.out.println("按着A不松");
            //删除界面中所有的图片
            this.getContentPane().removeAll();
            //加载第一张完整的图片
            JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));
            all.setBounds(83, 134, 420, 420);
            this.getContentPane().add(all);
            //添加背景图片
            ImageIcon bg = new ImageIcon("day16-day17\\image\\background.png"); //新建ImageIcon,写入图片路径
            JLabel background = new JLabel(bg); //新建JLabel,ImageIcon加入JLabel
            background.setBounds(40, 40, 508, 560);  //JLabel设置位置、宽高
            this.getContentPane().add(background);  //将背景添加到界面中
            //刷新界面
            this.getContentPane().repaint();

        }
    }

    //按下按键的时候会调用这个方法
    @Override
    public void keyReleased(KeyEvent e) {
        //判断游戏是否胜利,若胜利,此方法不能再执行
        if (victory()) {
            return; //结束方法
        }

        //对 上37、下38、左39、右40 进行判断
        int code = e.getKeyCode();
        System.out.println(code);
        if (code == 37) {
            System.out.println("向左移动");
            if (y == 3) {
                return;
            }
            data[x][y] = data[x][y + 1];
            data[x][y + 1] = 0;
            y++;

            //每次移动,计步器自增一次
            step++;

            initImage();
        } else if (code == 38) {
            System.out.println("向上移动");
            if (x == 3) {
                //表示空白方块已经在最下方,下面没有方块,不能再执行往上移动
                return;
            }
            //将空白方块与下方的方块进行调换
            data[x][y] = data[x + 1][y]; //空白下面方块的值,赋值给空白方块
            data[x + 1][y] = 0; //空白下方方块的值,定义为0
            x++; //调换以后,表示空白的索引(x,y)发生了变化,需要x+1
            //每次移动,计步器自增一次
            step++;
            initImage(); //重新加载图片

        } else if (code == 39) {
            System.out.println("向右移动");
            if (y == 0) {
                return;
            }
            data[x][y] = data[x][y - 1];
            data[x][y - 1] = 0;
            y--;
            //每次移动,计步器自增一次
            step++;
            initImage();
        } else if (code == 40) {
            System.out.println("向下移动");
            if (x == 0) {
                return;
            }
            data[x][y] = data[x - 1][y];
            data[x - 1][y] = 0;
            x--;
            //每次移动,计步器自增一次
            step++;
            initImage();
        } else if (code == 65) {
            initImage();
        } else if (code == 87) {
            data = new int[][]{
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 0}
            };
            initImage();
        }
    }

    //判断data数组中数据 与 win数据是否相同。相同则返回true,否则返回false
    public boolean victory() {
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != win[i][j]) {
                    //只要有一个数据不一样,则返回false
                    return false;
                }
            }
        }
        //循环遍历结束,表示全都一样,返回true
        return true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object obj = e.getSource();
        if (obj == replayItem) {
            System.out.println("重新游戏");
            //计步器清零
            step = 0;
            //再次打乱二位数组中数据
            initData();
            //重新加载图片
            initImage();

        } else if (obj == reLoginItem) {
            System.out.println("重新登录");
            //关闭当前的游戏界面
            this.setVisible(false);
            //打开登录界面
            new LoginJFrame();
        } else if (obj == closeItem) {
            System.out.println("关闭游戏");
            //直接关闭虚拟机即可
            System.exit(0);
        } else if (obj == accountItem) {
            System.out.println("公众号");

            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建管理图片的容器对象JLabel
            JLabel jLabel = new JLabel(new ImageIcon("day16-day17\\image\\about.png"));
            jLabel.setBounds(0,0,258,258);  //位置是相对于弹框设置的
            jDialog.getContentPane().add(jLabel); //将图片放入弹框
            jDialog.setSize(344,344); //设置弹框大小
            jDialog.setAlwaysOnTop(true);  //让弹框置顶
            jDialog.setLocationRelativeTo(null); //让弹框居中
            jDialog.setModal(true); //弹框不关闭,则无法操作下面的界面
            jDialog.setVisible(true);  //显示弹框
            
        }
    }
}

App.java

import com.yq.ui.GameJFrame;
import com.yq.ui.LoginJFrame;
import com.yq.ui.RegisterJFrame;

public class App {
    public static void main(String[] args) {
        //表示程序的启动入口
        //new LoginJFrame();
        //new RegisterJFrame();
        new GameJFrame();
    }
}


0

评论区