java实战项目--拼图小游戏(附带全套源代码)

news2024/11/18 13:55:16
  • 个人主页VON

  • 所属专栏java实战项目
  • 游戏参考黑马程序员

一、效果展示

二、功能介绍

游戏中所有的图片以及代码均已打包,玩家直接安装游戏即可,不用idea也可以畅玩。

游戏功能比较单一,只有简单的拼图功能。

  • a:展示原图
  • 重新游戏:图片会被重新打乱
  • 控制:上下左右来控制空白格子的移动

三、代码分析

1、初始化界面

//初始化界面
    private void initJFame() {
        //设置窗口大小
        this.setSize(603, 680);
        //设置窗口标题
        this.setTitle("拼图小游戏");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭方式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消默认居中放置
        this.setLayout(null);
        //添加键盘监听事件
        this.addKeyListener(this);
    }

设置窗口大小:

this.setSize(603, 680);

这行代码设置窗口的大小为宽度603像素,高度680像素。

设置窗口标题:

this.setTitle("拼图小游戏");

这行代码设置窗口的标题为 "拼图小游戏"。

设置界面置顶:

this.setAlwaysOnTop(true);

这行代码将窗口设置为总是置顶,即无论其他窗口如何操作,该窗口始终在最上层显示。

设置界面居中:

this.setLocationRelativeTo(null);

这行代码将窗口设置为居中显示在屏幕上,参数 null 表示相对于屏幕居中。

设置关闭方式:

this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

这行代码设置窗口关闭时的默认操作,即关闭窗口时退出程序。

取消默认居中放置:

this.setLayout(null);

这行代码取消了窗口默认的布局管理器,将布局设置为手动控制位置和大小。

添加键盘监听事件:

this.addKeyListener(this);

这行代码将当前对象添加为键盘事件的监听器,以便处理键盘输入事件。

2、初始化菜单

//初始化菜单
    private void initJMenuBar() {

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

        //菜单选项
        JMenu function = new JMenu("功能");
        JMenu about = new JMenu("关于我们");
        JMenu help = new JMenu("支持一下");

        //将条目添加到菜单中
        function.add(replayItem);
        function.add(closeItem);

        about.add(accountItem);

        help.add(pay);

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

        accountItem.addActionListener(this);
        pay.addActionListener(this);


        //将菜单添加到菜单对象中
        jMenuBar.add(function);
        jMenuBar.add(about);
        jMenuBar.add(help);

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

创建菜单对象:

JMenuBar jMenuBar = new JMenuBar();

创建了一个 JMenuBar 对象 jMenuBar,用于存放整个菜单栏。

创建菜单选项:

JMenu function = new JMenu("功能");
JMenu about = new JMenu("关于我们");
JMenu help = new JMenu("支持一下");

创建了三个菜单选项:functionabouthelp,分别用于显示 "功能"、"关于我们" 和 "支持一下"。

添加菜单条目:

function.add(replayItem);
function.add(closeItem);

about.add(accountItem);

help.add(pay);

将具体的菜单条目 replayItemcloseItemaccountItempay 分别添加到对应的菜单中。这些条目是 JMenuItem 对象,用于表示菜单中的具体选项。

绑定事件监听器:

replayItem.addActionListener(this);
closeItem.addActionListener(this);
accountItem.addActionListener(this);
pay.addActionListener(this);

给每个菜单条目添加事件监听器,这里 this 是当前类的实例,实现了 ActionListener 接口,用于处理菜单项的点击事件。

将菜单添加到菜单对象中:

jMenuBar.add(function);
jMenuBar.add(about);
jMenuBar.add(help);

将创建好的菜单选项 functionabouthelp 分别添加到菜单栏对象 jMenuBar 中。

设置界面的菜单栏:

this.setJMenuBar(jMenuBar);

最后,将整个菜单栏 jMenuBar 设置为当前界面的菜单栏,以使菜单栏显示在界面顶部。

3、初始化图片

//初始化图片
    private void initImage() {
        //清除原本已经出现的所有图片
        this.getContentPane().removeAll();
        //判断是否胜利
        if(isWin()){
            //显示胜利的图标
            JLabel win = new JLabel(new ImageIcon("image\\win.png"));
            win.setBounds(203,283,197,73);
            this.getContentPane().add(win);
        }
        JLabel stepCount = new JLabel("步数:"+count);
        stepCount.setBounds(50, 30, 100, 20);
        this.getContentPane().add(stepCount);
        //先加载的图片在上方,后添加的在下方
        //添加图片
        //添加行
        for (int i = 0; i < 4; i++) {
            //添加列
            for (int j = 0; j < 4; j++) {
                //获取要加载图片的序号
                int number=data[i][j];
                //创建ImageIcon对象
                ImageIcon icon = new ImageIcon(path+number+ ".jpg");
                //创建JLabel对象(管理容器)
                JLabel jLabel = new JLabel(icon);
                //设置图片位置
                jLabel.setBounds(105*j+83, 105*i+134, 105, 105);
                //给图片添加边框
                jLabel.setBorder(new BevelBorder(0));
                //将管理容器添加到界面
                this.getContentPane().add(jLabel);
            }
        }
        //添加背景图片
        //创建ImageIcon对象
        ImageIcon bgIcon = new ImageIcon("image\\background.png");
        //创建JLabel对象(管理容器)
        JLabel bg = new JLabel(bgIcon);
        //设置图片位置
        bg.setBounds(40, 40, 508, 560);
        //将管理容器添加到界面
        this.getContentPane().add(bg);

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

清除原有图片:

this.getContentPane().removeAll();

这行代码的作用是清除当前界面上已经存在的所有组件,为后续的重新加载做准备。

判断是否胜利并显示胜利图标:

if (isWin()) {
    JLabel win = new JLabel(new ImageIcon("image\\win.png"));
    win.setBounds(203, 283, 197, 73);
    this.getContentPane().add(win);
}

如果 isWin() 方法返回 true,表示游戏已经胜利,那么会在界面上显示一个胜利的图标。图标的位置和大小由 setBounds() 方法指定。

显示步数信息:

JLabel stepCount = new JLabel("步数:" + count);
stepCount.setBounds(50, 30, 100, 20);
this.getContentPane().add(stepCount);

在界面上显示当前的步数信息,步数由变量 count 提供,显示位置和大小也由 setBounds() 方法指定。

加载和显示拼图的小块:

for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++) {
        int number = data[i][j];  // 获取要加载图片的序号
        ImageIcon icon = new ImageIcon(path + number + ".jpg");  // 创建 ImageIcon 对象
        JLabel jLabel = new JLabel(icon);  // 创建 JLabel 对象
        jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);  // 设置图片位置
        jLabel.setBorder(new BevelBorder(0));  // 给图片添加边框
        this.getContentPane().add(jLabel);  // 将图片添加到界面
    }
}

使用嵌套循环加载和显示一个 4x4 的拼图小块。data[i][j] 数组存储了每个拼图块的序号,通过拼接路径 path + number + ".jpg" 加载对应的图片。每个拼图小块用 JLabelImageIcon 来表示,位置由 setBounds() 方法设置,同时为每个图片添加了边框。

添加背景图片:

ImageIcon bgIcon = new ImageIcon("image\\background.png");
JLabel bg = new JLabel(bgIcon);
bg.setBounds(40, 40, 508, 560);
this.getContentPane().add(bg);

在界面上添加一个背景图片,该背景图片的位置和大小由 setBounds() 方法指定。

刷新界面:

this.getContentPane().repaint();

最后,调用 repaint() 方法刷新整个界面,确保所有修改和添加的组件都能立即显示出来。

4、打乱图片

//初始化数据(打乱图片)
    private void initdate() {
        int[]arr={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        Random random=new Random();
        //打乱一维数组中的数据
        for (int i = 0; i < arr.length; i++) {
            int index= random.nextInt(arr.length);
            int temp=arr[i];
            arr[i]=arr[index];
            arr[index]=temp;
        }
        //将一维数组中的数据赋值给二维数组
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]==0){
                x=i/4;
                y=i%4;
            }data[i/4][i%4]=arr[i];
        }
    }

定义和初始化数组:

int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

这里定义了一个长度为16的一维数组 arr,包含了数字0到15,用来表示拼图块的顺序。

打乱一维数组中的数据:

Random random = new Random();
for (int i = 0; i < arr.length; i++) {
    int index = random.nextInt(arr.length);
    int temp = arr[i];
    arr[i] = arr[index];
    arr[index] = temp;
}

使用 Random 类打乱一维数组 arr 中元素的顺序。在每次迭代中,生成一个随机的索引 index,然后交换当前索引 i 和随机索引 index 处的元素值,以达到打乱数组的效果。

将打乱后的一维数组赋值给二维数组 data

for (int i = 0; i < arr.length; i++) {
    if (arr[i] == 0) {
        x = i / 4;  // 计算空白块在二维数组中的行索引
        y = i % 4;  // 计算空白块在二维数组中的列索引
    }
    data[i / 4][i % 4] = arr[i];  // 将打乱后的值赋给二维数组 data
}

如果当前元素 arr[i] 的值为0,这表示找到了拼图中的空白块。通过计算可以确定空白块在二维数组 data 中的位置:行索引为 i / 4,列索引为 i % 4

然后,将打乱后的一维数组 arr 中的每个元素依次赋给二维数组 data,以初始化拼图的初始状态。

5、判断是否胜利

//初始化数据(打乱图片)
    private void initdate() {
        int[]arr={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        Random random=new Random();
        //打乱一维数组中的数据
        for (int i = 0; i < arr.length; i++) {
            int index= random.nextInt(arr.length);
            int temp=arr[i];
            arr[i]=arr[index];
            arr[index]=temp;
        }
        //将一维数组中的数据赋值给二维数组
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]==0){
                x=i/4;
                y=i%4;
            }data[i/4][i%4]=arr[i];
        }
    }
  • 双重循环遍历: 方法首先通过两个嵌套的 for 循环遍历二维数组 data。这个数组存储了当前拼图的布局状态。
  • 比较数组内容: 在每个位置 (i, j) 处,方法会比较 data[i][j] 和 right[i][j] 的值。
    • data 是当前拼图的状态数组。
    • right 可能是一个预设的正确的拼图状态数组,用来与当前拼图状态进行比较,判断是否完成。
  • 判断条件: 如果在任何位置 (i, j) 处,data[i][j] 不等于 right[i][j],则表示当前拼图状态与正确状态不符,直接返回 false,表示未完成胜利条件。
  • 完全相同返回true: 如果所有位置的数据都与 right 数组相同,则说明拼图已经按正确的顺序排列,返回 true,表示已经完成拼图,达到胜利条件。

 6、重写内容

按键响应

@Override
    public void keyTyped(KeyEvent e) {

    }
    //按下不松时
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if(code==65){
            //删除界面中的全部图片
            this.getContentPane().removeAll();
            //加载完整图片
            JLabel all = new JLabel(new ImageIcon(path+"all.jpg"));
            all.setBounds(83, 134, 420,420);
            this.getContentPane().add(all);
            //加载背景图片
            JLabel bg = new JLabel(new ImageIcon("image\\background.png"));
            bg.setBounds(40, 40, 508, 560);
            //将管理容器添加到界面
            this.getContentPane().add(bg);
            //刷新界面
            this.getContentPane().repaint();
        }
    }
    //松下按键时
    @Override
    public void keyReleased(KeyEvent e) {
        //如果游戏胜利了,就不能够进行移动操作了
        if(isWin()){
            return;//直接退出该方法
        }
        //对上下左右进行判断
        int code=e.getKeyCode();
        switch (code){
            case 37: // 向左
                System.out.println("向左");
                if (y > 0) { // 检查是否还有空间向左移动
                    data[x][y] = data[x][y-1];
                    data[x][y-1] = 0;
                    //每移动一次,步数加1
                    count++;
                    y--;
                }
                initImage();
                break;
            case 38: // 向上
                System.out.println("向上");
                if (x > 0) { // 检查是否还有空间向上移动
                    data[x][y] = data[x-1][y];
                    data[x-1][y] = 0;
                    //每移动一次,步数加1
                    count++;
                    x--;
                }
                initImage();
                break;
            case 39: // 向右
                System.out.println("向右");
                if (y < data[0].length - 1) { // 检查是否还有空间向右移动
                    data[x][y] = data[x][y+1];
                    data[x][y+1] = 0;
                    //每移动一次,步数加1
                    count++;
                    y++;
                }
                initImage();
                break;
            case 40: // 向下
                System.out.println("向下");
                if (x < data.length - 1) { // 检查是否还有空间向下移动
                    data[x][y] = data[x+1][y];
                    data[x+1][y] = 0;
                    //每移动一次,步数加1
                    count++;
                    x++;
                }
                initImage();
                break;
            case 65:
                initImage();
                break;
            case 87://w键
                data=new int[][]{
                        {1,2,3,4},
                        {5,6,7,8},
                        {9,10,11,12},
                        {13,14,15,0}
                };
                initImage();
                break;
            default:
                break;
        }
    }
方法说明
  • keyPressed(KeyEvent e) 方法响应按键按下事件。
  • keyReleased(KeyEvent e) 方法响应按键释放事件。
  • keyTyped(KeyEvent e) 方法在此处被省略,因为它通常用于处理按键输入,对于游戏中的按键操作可能不是必需的。
keyPressed(KeyEvent e) 方法分析
  • 当按键按下时,首先获取按键的键码 (e.getKeyCode())。
  • 如果按下的是键码为 65(对应于字母 'A'),则执行以下操作:
  • 移除当前容器中的所有组件 (this.getContentPane().removeAll()),通常用于清空当前界面。
  • 加载一个完整的图片 all.jpg,并创建一个 JLabel 来显示这个图片,设置其位置和大小。
  • 加载背景图片 background.png,同样创建一个 JLabel 并设置其位置和大小。
  • 将这些 JLabel 添加到界面的内容面板中 (this.getContentPane().add(...))。
  • 最后,调用 repaint() 方法来刷新界面,确保更新后的内容可见。
keyReleased(KeyEvent e) 方法分析
  • 首先检查游戏是否已经胜利(通过 isWin() 方法判断)。
  • 如果已经胜利,则直接返回,不执行后续的按键操作处理。
  • 如果游戏未胜利,则根据按键的不同键码执行相应的移动操作:
  • 37 表示向左移动,更新 data 数组中的元素位置,并调用 initImage() 方法更新界面。
  • 38 表示向上移动,同样更新 data 数组并刷新界面。
  • 39 表示向右移动,更新数组并刷新。
  • 40 表示向下移动,同样更新数组并刷新。
  • 65 键码表示重新初始化界面,调用 initImage() 方法。
  • 87 键码('W' 键)表示重置游戏的 data 数组为一个预设的初始状态,并刷新界面。

 功能实现

@Override
    public void actionPerformed(ActionEvent e) {
        //获取被点击的菜单项
        Object source = e.getSource();
        if (source == replayItem) {
            System.out.println("重新游戏");
            //清零记步数
            count=0;
            //打乱二维数组的数据
            initdate();
            //重新加载图片
            initImage();
        } else if (source == closeItem) {
            System.out.println("关闭游戏");
            System.exit(0);
        }else if(source==accountItem){
            System.out.println("微信号");
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //设置图片
            JLabel jLabel = new JLabel(new ImageIcon("image\\about.jpg"));
            //设置位置和宽高
            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);
        }else if(source==pay){
            System.out.println("付款码");
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //设置图片
            JLabel jLabel = new JLabel(new ImageIcon("image\\pay.jpg"));
            //设置位置和宽高
            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);
        }
    }
replayItem(重新游戏)
  • 当用户点击 replayItem 菜单项时,打印出 "重新游戏"。
  • 将计步数 count 清零。
  • 调用 initdate() 方法,可能是用来打乱二维数组的数据。
  • 调用 initImage() 方法,重新加载图片,可能是重新初始化游戏界面的图片显示。
closeItem(关闭游戏)
  • 当用户点击 closeItem 菜单项时,打印出 "关闭游戏"。
  • 调用 System.exit(0) 来终止程序,退出游戏。
accountItem(微信号)pay(付款码)
  • 当用户点击 accountItem 菜单项时,创建一个 JDialog 对话框。
  • 在对话框中显示名为 "image\about.jpg" 的图片。
  • 设置对话框的大小为 344x344 像素,位置居中显示。
  • 将对话框设置为模态,即打开时阻止与其它窗口的交互。
  • 最后显示这个对话框。
  • 同样地,当用户点击 pay 菜单项时,创建另一个对话框来显示名为 "image\pay.jpg" 的图片,设置其属性并显示出来。

四、全套源码

package von.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;

    //使用一个变量记录展示图片的路径前半段
    Random random=new Random();
    String[]type={"animal","girl","sport"};
    int num=random.nextInt(8)+1;
    String typeimage=type[random.nextInt(type.length)];
    String path="image\\"+typeimage+"\\"+typeimage+num+"\\";

    //定义一个二维数组用来存放正确是数据
    int[][]right=new int[][]{
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };

    //计算步数
    int count =0;

    //菜单条目
    JMenuItem replayItem = new JMenuItem("重新游戏");
    JMenuItem closeItem = new JMenuItem("关闭游戏");

    JMenuItem accountItem = new JMenuItem("微信号");
    JMenuItem pay = new JMenuItem("付款码");

    public GameJFrame() {
        //初始化界面
        initJFame();
        //初始化菜单
        initJMenuBar();
        //初始化数据(打乱图片)
        initdate();
        //初始化图片
        initImage();


        //设置显示模式(写在最后)
        this.setVisible(true);
    }
    //初始化数据(打乱图片)
    private void initdate() {
        int[]arr={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        Random random=new Random();
        //打乱一维数组中的数据
        for (int i = 0; i < arr.length; i++) {
            int index= random.nextInt(arr.length);
            int temp=arr[i];
            arr[i]=arr[index];
            arr[index]=temp;
        }
        //将一维数组中的数据赋值给二维数组
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]==0){
                x=i/4;
                y=i%4;
            }data[i/4][i%4]=arr[i];
        }
    }

    //初始化图片
    private void initImage() {
        //清除原本已经出现的所有图片
        this.getContentPane().removeAll();
        //判断是否胜利
        if(isWin()){
            //显示胜利的图标
            JLabel win = new JLabel(new ImageIcon("image\\win.png"));
            win.setBounds(203,283,197,73);
            this.getContentPane().add(win);
        }
        JLabel stepCount = new JLabel("步数:"+count);
        stepCount.setBounds(50, 30, 100, 20);
        this.getContentPane().add(stepCount);
        //先加载的图片在上方,后添加的在下方
        //添加图片
        //添加行
        for (int i = 0; i < 4; i++) {
            //添加列
            for (int j = 0; j < 4; j++) {
                //获取要加载图片的序号
                int number=data[i][j];
                //创建ImageIcon对象
                ImageIcon icon = new ImageIcon(path+number+ ".jpg");
                //创建JLabel对象(管理容器)
                JLabel jLabel = new JLabel(icon);
                //设置图片位置
                jLabel.setBounds(105*j+83, 105*i+134, 105, 105);
                //给图片添加边框
                jLabel.setBorder(new BevelBorder(0));
                //将管理容器添加到界面
                this.getContentPane().add(jLabel);
            }
        }
        //添加背景图片
        //创建ImageIcon对象
        ImageIcon bgIcon = new ImageIcon("image\\background.png");
        //创建JLabel对象(管理容器)
        JLabel bg = new JLabel(bgIcon);
        //设置图片位置
        bg.setBounds(40, 40, 508, 560);
        //将管理容器添加到界面
        this.getContentPane().add(bg);

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


    //初始化界面
    private void initJFame() {
        //设置窗口大小
        this.setSize(603, 680);
        //设置窗口标题
        this.setTitle("拼图小游戏");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭方式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消默认居中放置
        this.setLayout(null);
        //添加键盘监听事件
        this.addKeyListener(this);
    }

    //初始化菜单
    private void initJMenuBar() {

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

        //菜单选项
        JMenu function = new JMenu("功能");
        JMenu about = new JMenu("关于我们");
        JMenu help = new JMenu("支持一下");

        //将条目添加到菜单中
        function.add(replayItem);
        function.add(closeItem);

        about.add(accountItem);

        help.add(pay);

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

        accountItem.addActionListener(this);
        pay.addActionListener(this);


        //将菜单添加到菜单对象中
        jMenuBar.add(function);
        jMenuBar.add(about);
        jMenuBar.add(help);

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

    @Override
    public void keyTyped(KeyEvent e) {

    }
    //按下不松时
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if(code==65){
            //删除界面中的全部图片
            this.getContentPane().removeAll();
            //加载完整图片
            JLabel all = new JLabel(new ImageIcon(path+"all.jpg"));
            all.setBounds(83, 134, 420,420);
            this.getContentPane().add(all);
            //加载背景图片
            JLabel bg = new JLabel(new ImageIcon("image\\background.png"));
            bg.setBounds(40, 40, 508, 560);
            //将管理容器添加到界面
            this.getContentPane().add(bg);
            //刷新界面
            this.getContentPane().repaint();
        }
    }
    //松下按键时
    @Override
    public void keyReleased(KeyEvent e) {
        //如果游戏胜利了,就不能够进行移动操作了
        if(isWin()){
            return;//直接退出该方法
        }
        //对上下左右进行判断
        int code=e.getKeyCode();
        switch (code){
            case 37: // 向左
                System.out.println("向左");
                if (y > 0) { // 检查是否还有空间向左移动
                    data[x][y] = data[x][y-1];
                    data[x][y-1] = 0;
                    //每移动一次,步数加1
                    count++;
                    y--;
                }
                initImage();
                break;
            case 38: // 向上
                System.out.println("向上");
                if (x > 0) { // 检查是否还有空间向上移动
                    data[x][y] = data[x-1][y];
                    data[x-1][y] = 0;
                    //每移动一次,步数加1
                    count++;
                    x--;
                }
                initImage();
                break;
            case 39: // 向右
                System.out.println("向右");
                if (y < data[0].length - 1) { // 检查是否还有空间向右移动
                    data[x][y] = data[x][y+1];
                    data[x][y+1] = 0;
                    //每移动一次,步数加1
                    count++;
                    y++;
                }
                initImage();
                break;
            case 40: // 向下
                System.out.println("向下");
                if (x < data.length - 1) { // 检查是否还有空间向下移动
                    data[x][y] = data[x+1][y];
                    data[x+1][y] = 0;
                    //每移动一次,步数加1
                    count++;
                    x++;
                }
                initImage();
                break;
            case 65:
                initImage();
                break;
            case 87://w键
                data=new int[][]{
                        {1,2,3,4},
                        {5,6,7,8},
                        {9,10,11,12},
                        {13,14,15,0}
                };
                initImage();
                break;
            default:
                break;
        }
    }

    //判断是否胜利
    public boolean isWin(){
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != right[i][j]) {
                    //只要有一个不同,就是false
                    return false;
                }
            }
        }
        //完全相同返回true
        return true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //获取被点击的菜单项
        Object source = e.getSource();
        if (source == replayItem) {
            System.out.println("重新游戏");
            //清零记步数
            count=0;
            //打乱二维数组的数据
            initdate();
            //重新加载图片
            initImage();
        } else if (source == closeItem) {
            System.out.println("关闭游戏");
            System.exit(0);
        }else if(source==accountItem){
            System.out.println("微信号");
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //设置图片
            JLabel jLabel = new JLabel(new ImageIcon("image\\about.jpg"));
            //设置位置和宽高
            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);
        }else if(source==pay){
            System.out.println("付款码");
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //设置图片
            JLabel jLabel = new JLabel(new ImageIcon("image\\pay.jpg"));
            //设置位置和宽高
            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);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1955556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初涉JVM

JVM 字节码、类的生命周期、内存区域、垃圾回收 JVM主要功能&#xff1a; 解释运行&#xff08;翻译字节码&#xff09;内存管理&#xff08;GC&#xff09;即使编译&#xff08;Just - In - Time&#xff0c; JIT&#xff09; 将短时间内常使用到的字节码翻译成机器码存储在内…

whaler_通过镜像导出dockerfile

1、Whaler简介 Whaler:从镜像导出Dockerfile&#xff0c;whaler英文释义捕鲸船。 2、下载安装 # wget -cO /usr/local/bin/whaler https://github.com/P3GLEG/Whaler/releases/download/1.0/Whaler_linux_amd64 3、赋予可执行权限 [rootlocalhost ~]# chmod x /usr/local/…

Android OTA刷机包制作学习笔记

前言 OTA是一个再常见不过的需求&#xff0c;Android提供了recovery用于完成相关操作。 常规OTA包制作有两种&#xff1a; 有项目的完整AOSP源码&#xff0c;可以在成构建产物zip包后利用官方脚本制作。具体参阅&#xff1a;Office OTA假设你没有1的条件那么可以利用官方非A/…

exo-tinggrad 架构解析

目录 exo-tinggrad 架构解析 8B 模型配置 70B 模型配置 exo-tinggrad 架构解析 这个项目目录包含了一系列与Python相关的文件和文件夹,它们共同构成了一个可能的项目或库。这些文件和文件夹按照特定的命名和组织方式被放置在了一起,以便于管理、开发和维护。 tinygrad: 这…

24.7.28(tarjan 割点,割边,多重背包单调队列优化)

星期一&#xff1a; cf round 960 div2 B 简单构造 cf传送门 题意有点绕 思路&#xff1a;开始容易想到 y前和 x后全-1&#xff0c;y到x填1的构造&#xff0c;但对于 5 2 1&#xff0c;1 1 -1 -1 -1有问题&#xff0c;1和5的后缀值都为 -1…

【MySQL进阶之路 | 高级篇】简述Bin Log日志

1. 日志类型 MySQL有不同类型的日志文件&#xff0c;用来存储不同类型的日志&#xff0c;分为二进制日志、错误日志、通用查询日志和慢查询日志&#xff0c;这也是常用的4种。MySQL 8又新增两种支持的日志:中继日志和数据定义语句日志。使用这些日志文件&#xff0c;可以查看M…

树与二叉树【数据结构】

前言 之前我们已经学习过了各种线性的数据结构&#xff0c;顺序表、链表、栈、队列&#xff0c;现在我们一起来了解一下一种非线性的结构----树 1.树的结构和概念 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一…

LLM大模型在融合通信产品中的应用实践

前言 LLM 问题 幻觉&#xff1a;在没有答案的情况下提供虚假信息。 过时&#xff1a;当用户需要特定的当前响应时&#xff0c;提供过时或通用的信息。 来源&#xff1a;从非权威来源创建响应。由于术语混淆&#xff0c;不同的培训来源使用相同的术语来谈论不同的事情&#…

【Gin】智慧架构的巧妙砌筑:Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下)

【Gin】智慧架构的巧妙砌筑&#xff1a;Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下) 大家好 我是寸铁&#x1f44a; 【Gin】智慧架构的巧妙砌筑&#xff1a;Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; …

Meta 发布 Llama3.1,一站教你如何推理、微调、部署大模型

最近这一两周看到不少互联网公司都已经开始秋招提前批了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

古文:诸葛亮《前出师表》

前出师表 师&#xff1a;军队。 表&#xff1a;就是“奏表”&#xff0c;又称“表文”&#xff0c;是臣属给君王的上书。古代给君王的上书&#xff0c;有各种名称&#xff0c;不同的名称与上书内容有关。刘勰《文心雕龙章表》云&#xff1a;“章以谢恩&#xff0c;奏以按劾&a…

高速板开源项目学习(二)

一定要找一个高速板写的详细的等长规范&#xff1a; 看的出来&#xff0c;这位小哥也是卡着嘉立创最小免费钻孔大小来打孔的&#xff1a; 这里的天线&#xff0c;他做了禁止铺铜和走线处理&#xff0c;模拟信号在这里容易遇到干扰&#xff0c;这样是正确的&#xff0c;值得去学…

解决使用selenium-wire访问链接地址不安全的问题

pip安装selenium-wire 描述&#xff1a;这里用的是python3.12.2 selenium-wire5.1.0 pip3.12 install selenium-wire pip3.12 install blinker1.7 pip3.12 install setuptools 运行以下命令来获取证书 python -m seleniumwire extractcert 安装浏览器ssl证书 Windows上给…

【JavaScript】延迟加载 js 脚本

defer 属性&#xff1a;在 HTML 中通过设置 script 标签的 defer 属性来实现脚本的延迟加载&#xff0c;即脚本的下载与 HTML 的解析不会阻塞彼此&#xff0c;脚本会在 HTML 解析完成后才执⾏。async 属性&#xff1a;在 HTML 中通过设置 script 标签的 async 属性来实现脚本的…

深入理解 Java NIO:ByteBuffer和MappedByteBuffer的特性与使用

目录 前言 ByteBuffer是什么 重要特点 分配缓冲区 读写模式切换 操作文本数据 操作基本数据类型 案例解析-循环输出数据 MappedByteBuffer是什么 MappedByteBuffer 的工作机制 刷盘时机 总结 前言 在深入学习 RocketMQ 这款高性能消息队列框架的源码时&#xff0c…

免费【2024】springboot 畅游游戏销售平台

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

EchoMimicV2,Audio Driven加速模型,推理速度大幅提升

EchoMimic更新啦&#xff0c;我24号刚出的一篇&#xff0c;到了25号官方就更新了新的加速模型。 着实没赶上官方更新的速度...... 那本次我主要讲下更新了什么内容&#xff0c;如何修改使用acc加速模型。 另外还准备了v2版本的整合包&#xff01;大家可以体验下&#xff01; 更…

ProxmoxPVE虚拟化平台--安装PVE虚拟机

Proxmox 虚拟机 Proxmox是一个基于Debian Linux和KVM的虚拟化平台&#xff0c;‌它提供了虚拟化的环境&#xff0c;‌允许用户在同一台物理机上运行多个虚拟机。‌Proxmox虚拟环境&#xff08;‌PVE&#xff09;‌是一个开源项目&#xff0c;‌由Proxmox Server Solutions Gmb…

从与原始的Transformer architecture比较来理解GPT

从与原始的Transformer architecture比较来理解GPT flyfish 一、Transformer architecture 先说名词 不同的文献和资料中有不同的名字&#xff0c;其实是一样的意思 1 编码器-解码器多头注意力机制&#xff08;Encoder-Decoder Multi-Head Attention Mechanism&#xff09; …

CI/CD:Job failed: execution took longer than 1h0m0s seconds

简介&#xff1a;当在CI/CD配置运行Gitlab-runner流水线中&#xff0c;一般默认情况下&#xff0c;Job的执行时间默认为1小时&#xff0c;如果超出1小时&#xff0c;任务会中断。 历史攻略&#xff1a; 定时任务&#xff1a;Jenkins 容器化CICDLocust性能压测 容器化CICDSo…