拼图小游戏开发日记 | 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++; // 步数+1initPicture(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);}
}