拼图小游戏开发日记 | Day3(已完结)

1. 成员变量扩展

复制代码
// 统计移动步数
int step = 0;
// 胜利时的目标数组(每个方块的"正确位置")
int[][] win = new int[][]{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 0}};
// 图片资源主路径(后续可切换动物、风景等主题)
String path = "image/animal/animal1/";
// 空白方块在二维数组中的坐标(x行y列)
int x = 0, y = 0;
// 记录当前拼图方块的位置(动态变化)
int[][] arr = new int[4][4];
// 菜单栏的菜单项(用于绑定点击事件)
JMenuItem rePlayItem = new JMenuItem("重置游戏");
JMenuItem reLogo = new JMenuItem("重新登录");
JMenuItem closeGame = new JMenuItem("关闭游戏");
JMenuItem gongZhongHao = new JMenuItem("公众号");
(1)胜利判定:win1()

判断当前拼图数组arr是否与 "目标数组win" 完全一致

复制代码
private boolean win1() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (arr[i][j] != win[i][j]) {
                return false; // 有一个位置不一致,未胜利
            }
        }
    }
    return true; // 所有位置一致,判定胜利
}
(2)随机打乱图片:randomPicture(int[][] arr)

用 "洗牌算法" 随机交换数组元素,实现拼图打乱

复制代码
private void randomPicture(int[][] arr) {
    int[] temp = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
    Random r = new Random();
    // 第一步:数组元素"洗牌"(随机交换)
    for (int i = 0; i < temp.length; i++) {
        int index = r.nextInt(arr.length * arr[0].length); // 生成随机下标
        int t = temp[i];
        temp[i] = temp[index];
        temp[index] = t;
    }
    // 第二步:将一维数组转二维,并记录空白方块位置
    for (int i = 0; i < temp.length; i++) {
        if (temp[i] == 0) { // 找到空白方块(值为0)
            x = i / 4; // 计算所在行
            y = i % 4; // 计算所在列
        }
        arr[i / 4][i % 4] = temp[i];
    }
}
(3)初始化 / 刷新拼图:initPicture(int[][] arr)

根据数组arr的状态,刷新界面上的拼图图

复制代码
private void initPicture(int[][] arr) {
    this.getContentPane().removeAll(); // 清空原有组件
    
    // 显示步数
    JLabel stepCount = new JLabel("步数:" + step);
    stepCount.setBounds(20, 20, 60, 20);
    this.getContentPane().add(stepCount);
    
    // 胜利判定:若拼图完成,显示胜利图片
    if (win1()) {
        ImageIcon winPicture = new ImageIcon("image/win.png");
        JLabel label = new JLabel(winPicture);
        label.setBounds(100, 100, winPicture.getIconWidth(), winPicture.getIconHeight());
        this.getContentPane().add(label);
    }
    
    // 绘制拼图方块(根据arr数组)
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            ImageIcon icon = new ImageIcon(path + arr[i][j] + ".jpg");
            JLabel label = new JLabel(icon);
            label.setBounds(105 * j + 100, 105 * i + 100, icon.getIconWidth(), icon.getIconHeight());
            this.getContentPane().add(label);
        }
    }
    
    // 绘制背景图
    ImageIcon background = new ImageIcon("image/background.png");
    JLabel label2 = new JLabel(background);
    label2.setBounds(56, 8, background.getIconWidth(), background.getIconHeight());
    this.getContentPane().add(label2);
    
    this.getContentPane().repaint(); // 刷新界面
}
(4)键盘事件监听:控制方块移动

通过 方向键(←↑→↓)控制空白方块移动,A键显示全图,W键直接通关

复制代码
@Override
public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    // 按A键:显示完整图片(方便参考拼图)
    if (code == 65) { 
        this.getContentPane().removeAll();
        ImageIcon all = new ImageIcon(path + "all.jpg");
        JLabel label = new JLabel(all);
        label.setBounds(100, 102, all.getIconWidth(), all.getIconHeight());
        this.add(label);
        ImageIcon background = new ImageIcon("image/background.png");
        JLabel label2 = new JLabel(background);
        label2.setBounds(56, 8, background.getIconWidth(), background.getIconHeight());
        this.add(label2);
        this.getContentPane().repaint();
    }
}

@Override
public void keyReleased(KeyEvent e) {
    if (win1()) return; // 胜利后,键盘操作无效
    
    int code = e.getKeyCode();
    // ←键:空白方块左移(交换右侧方块)
    if (code == 37) {
        if (y == 0) return; // 最左侧,无法左移
        arr[x][y] = arr[x][y - 1];
        arr[x][y - 1] = 0;
        y--;
        step++; // 步数+1
        initPicture(arr); // 刷新拼图
    } 
    // ↑键:空白方块上移(交换下方方块)
    else if (code == 38) {
        if (x == 0) return; // 最上方,无法上移
        arr[x][y] = arr[x - 1][y];
        arr[x - 1][y] = 0;
        x--;
        step++;
        initPicture(arr);
    } 
    // →键:空白方块右移(交换左侧方块)
    else if (code == 39) {
        if (y == 3) return; // 最右侧,无法右移
        arr[x][y] = arr[x][y + 1];
        arr[x][y + 1] = 0;
        y++;
        step++;
        initPicture(arr);
    } 
    // ↓键:空白方块下移(交换上方方块)
    else if (code == 40) {
        if (x == 3) return; // 最下方,无法下移
        arr[x][y] = arr[x + 1][y];
        arr[x + 1][y] = 0;
        x++;
        step++;
        initPicture(arr);
    } 
    // W键:直接胜利(测试用,后续可移除)
    else if (code == 87) {
        arr = new int[][]{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 0}};
        initPicture(arr);
    }
}
5)菜单栏点击事件:actionPerformed

为 "重置游戏""重新登录""关闭游戏""公众号" 添加具体逻辑

复制代码
@Override
public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    // 重置游戏:步数清零 + 重新打乱图片
    if (source == rePlayItem) {
        step = 0;
        randomPicture(arr);
        initPicture(arr);
    } 
    // 重新登录:隐藏当前窗口,打开启动页
    else if (source == reLogo) {
        this.setVisible(false);
        new LogoJframe();
    } 
    // 关闭游戏:退出程序
    else if (source == closeGame) {
        System.exit(0);
    } 
    // 公众号:弹出包含公众号图片的对话框
    else if (source == gongZhongHao) {
        JDialog jd = new JDialog();
        ImageIcon gongZhongPicture = new ImageIcon("image/小韦(小).png");
        JLabel label = new JLabel(gongZhongPicture);
        label.setBounds(0, 0, 1800, 1800);
        jd.getContentPane().add(label);
        jd.setAlwaysOnTop(true);
        jd.setSize(600, 600);
        jd.setLocationRelativeTo(null);
        jd.setModal(true); // 模态窗口(阻止父窗口交互)
        jd.setVisible(true);
    }
}
相关推荐
Guan jie2 小时前
10.6作业
数据结构·算法·排序算法
她说..3 小时前
Redis项目应用总结(苍穹外卖/黑马头条/乐尚代驾)
java·数据库·redis·缓存·消息队列·redisson·geo
摇滚侠3 小时前
Java进阶教程,全面剖析Java多线程编程,多线程和堆内存栈内存的关系,笔记20
java
haidizym3 小时前
ssc-FinLLM 金融大模型 相关链接
人工智能·算法
小猪绝不放弃.3 小时前
一张图入门 Docker
java·开发语言
Macre Aegir Thrym3 小时前
逻辑回归实践
算法·机器学习·逻辑回归
relis3 小时前
llama.cpp RMSNorm CUDA 优化分析报告
算法·llama
唐僧洗头爱飘柔95273 小时前
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
java·spring·spring cloud·微服务·架构·resttemplate·java微服务技术栈
chaofa用代码打点酱油3 小时前
RAG 进化之路:传统 RAG 到工具与强化学习双轮驱动的 Agentic RAG
算法·llm