package cn.edu.caztc.sokobangame; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.nio.file.Path; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * 游戏主体 */ public class MainGame extends JFrame implements MapConfig { int[][][] map1 = new int[18][18][1];// 地图数组 int playerx = 0;//玩家坐标 int playery = 0;//玩家坐标 boolean diy = false;// int level = 1;//关卡 //游戏面板 JPanel panel; GetLevelDialog dialog; private ImageIcon[] currentIcons; private static MainGame instance; private UpdateThread updateThread; public static MainGame getInstance() { return instance; } public MainGame() { // TODO Auto-generated constructor stub instance = this; currentIcons = ThemeSwitcher.getCurrentThemeIcons().clone(); // 从ThemeSwitcher获取当前主题 this.setTitle("推箱子"); this.setSize(900, 950); this.setLayout(new FlowLayout()); this.setDefaultCloseOperation(3); //设置窗体居中 this.setLocationRelativeTo(null); //不可拉伸 this.setResizable(false); JMenuBar menuBar = new JMenuBar(); this.add(menuBar, BorderLayout.NORTH); JMenu menu = new JMenu("菜单"); menuBar.add(menu); JMenuItem menuItem = new JMenuItem("选关"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { // 传入 false 表示是单人模式 dialog = new GetLevelDialog(false); // 修改这里 if (dialog.getValue() != 0) { diy = dialog.isdiy(); level = dialog.getValue(); GetMAP(level, diy); } } }); menu.add(menuItem); // 添加双人模式菜单项 // 修改双人模式菜单项 JMenuItem dualModeItem = new JMenuItem("双人模式"); dualModeItem.addActionListener(e -> { DualGame dualGame = new DualGame(); dualGame.setVisible(true); this.dispose(); // 完全关闭单人模式窗口 System.out.println("切换到双人模式,关闭单人模式"); // 添加切换信息 }); menu.add(dualModeItem); JMenuItem menuItem_1 = new JMenuItem("重新开始"); menuItem_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //重新开始 GetMAP(level,diy); } }); menu.add(menuItem_1); JMenu customMenu = new JMenu("自定义"); menuBar.add(customMenu); JMenuItem editorItem = new JMenuItem("地图编辑器"); editorItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { new CreatMap(); } }); customMenu.add(editorItem); // 添加主题切换菜单项 JMenuItem themeItem = ThemeSwitcher.createThemeMenuItem(); customMenu.add(themeItem); // 添加音乐菜单 JMenu musicMenu = new JMenu("音乐"); menuBar.add(musicMenu); // 音乐开关菜单项 JMenuItem toggleMusicItem = new JMenuItem("开启音乐"); // 音乐切换菜单项 JMenuItem changeMusicItem = new JMenuItem("切换音乐"); toggleMusicItem.addActionListener(e -> { MusicPlayer player = MusicPlayer.getInstance(); if (player.isMuted()) { // 使用getter方法替代直接访问字段 if (player.getCurrentTrackIndex() == -1) { player.playMusic(0); } else { player.toggleMute(); } toggleMusicItem.setText("关闭音乐"); } else { player.toggleMute(); toggleMusicItem.setText("开启音乐"); } }); changeMusicItem.addActionListener(e -> { MusicPlayer.getInstance().nextTrack(); }); musicMenu.add(toggleMusicItem); musicMenu.add(changeMusicItem); JMenu aboutMenu = new JMenu("关于"); JMenuItem aboutItem = new JMenuItem("玩法说明"); aboutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "用键盘的方向键控制人物,将箱子推到指定位置", "关于", JOptionPane.PLAIN_MESSAGE); } }); aboutMenu.add(aboutItem); menuBar.add(aboutMenu); GetMAP(level, diy); //创建游戏面板 panel = setpanel(); this.add(panel); this.setVisible(true); //安装键盘监听器 PanelListenner plis = new PanelListenner(); this.addKeyListener(plis); //启动刷新面板线程 updateThread = new UpdateThread(panel); updateThread.start(); // 窗口关闭时停止音乐 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { MusicPlayer.getInstance().stopMusic(); if (updateThread != null) { updateThread.stopRunning(); } } }); } // 更新主题的方法 public void updateTheme(ImageIcon[] newIcons) { currentIcons = newIcons.clone(); panel.repaint(); } // 修改GetGameImage方法使用当前主题图标 Image GetGameImage(int i) { if (i >= 0 && i < currentIcons.length) { return currentIcons[i].getImage(); } return null; } /** *读取地图数据 * * @param level 关卡 * @param diy */ void GetMAP(int level, boolean diy) { String stringdiy = ""; if (diy) { stringdiy = "diy"; } try { DataInputStream in = new DataInputStream( new BufferedInputStream(new FileInputStream(PATH + "\\" + stringdiy + level + ".map"))); int i = in.readInt(); int j = in.readInt(); for (int ii = 0; ii < i; ii++) { for (int jj = 0; jj < j; jj++) { map1[ii][jj][0] = in.readInt(); if (map1[ii][jj][0] == 5) { playerx = ii; playery = jj; map1[ii][jj][0] = 1; } } } } catch (Exception e) { // TODO: handle exception } } /** * 自定义内部游戏面板类 */ class MyPanel extends JPanel { @Override public void paint(Graphics g) { super.paint(g); for (int i = 0; i < MAP_HEIGHT / SOUREC_HEIGHT; i++) { for (int j = 0; j < MAP_WIDTH / SOUREC_WIDTH; j++) { g.drawImage(GetGameImage(map1[i][j][0]), getDrawX(j), getDrawY(i), SOUREC_WIDTH, SOUREC_HEIGHT, null); } } g.drawImage(icon106.getImage(), getDrawX(playery), getDrawY(playerx), SOUREC_WIDTH, SOUREC_HEIGHT, null); } // 将数组下标转化成对应的图片左上角坐标 public int getDrawX(int j) { int x = j * 50; return x; } //将数组下标转化成对应的图片左上角坐标 public int getDrawY(int i) { int y = i * 50; return y; } } /** * 设置游戏面板 */ public JPanel setpanel() { JPanel panel = new MyPanel(); panel.setPreferredSize(new Dimension(MAP_WIDTH, MAP_HEIGHT)); panel.setLayout(null); panel.setBackground(Color.white); return panel; } /** * 获取到数字对应的图片 * * @param i 数字 * @return */ // Image GetGameImage(int i) { // if (i > 5) { // i = 0; // } // return allicons[i].getImage(); // } /** * 内部游戏按键监听类 */ class PanelListenner extends KeyAdapter { //当按键按下 public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_UP: if (check(1)) { Move(1); } break; case KeyEvent.VK_DOWN: if (check(3)) { Move(3); } break; case KeyEvent.VK_LEFT: if (check(2)) { Move(2); } break; case KeyEvent.VK_RIGHT: if (check(4)) { Move(4); } break; // case 87:// W 键 // if (check(1)) { // Move(1); // } // break; // case 83:// S 键 // if (check(3)) { // Move(3); // } // break; // case 65:// A 键 // if (check(2)) { // Move(2); // } // break; // case 68:// D 键 // if (check(4)) { // Move(4); // } // break; default: break; } if (IsSuccess()) { GetNextMap(); } } } /** * 检查能不能走,前方有墙或者两个箱子超界等 * * @param direction 方向 1234wasd * @return */ boolean check(int direction) { switch (direction) { case 1: //判断1.超界 2.前面是墙 3.前面是箱子或者空箱子 再前面是箱子或者墙或者空箱子 if (playerx == 0) { return false; } else if (map1[playerx - 1][playery][0] == 0) { return false; } else if (map1[playerx - 1][playery][0] == 2 || map1[playerx - 1][playery][0] == 3) { if (map1[playerx - 2][playery][0] == 2 || map1[playerx - 2][playery][0] == 3 || map1[playerx - 2][playery][0] == 0) { return false; } } break; case 2: if (playery == 0) { return false; } else if (map1[playerx][playery - 1][0] == 0) { return false; } else if (map1[playerx][playery - 1][0] == 2 || map1[playerx][playery - 1][0] == 3) { if (map1[playerx][playery - 2][0] == 2 || map1[playerx][playery - 2][0] == 3 || map1[playerx][playery - 2][0] == 0) { return false; } } break; case 3: if (playerx == 17) { return false; } else if (map1[playerx + 1][playery][0] == 0) { return false; } else if (map1[playerx + 1][playery][0] == 2 || map1[playerx + 1][playery][0] == 3) { if (map1[playerx + 2][playery][0] == 2 || map1[playerx + 2][playery][0] == 3 || map1[playerx + 2][playery][0] == 0) { return false; } } break; case 4: if (playery == 17) { return false; } else if (map1[playerx][playery + 1][0] == 0) { return false; } else if (map1[playerx][playery + 1][0] == 2 || map1[playerx][playery + 1][0] == 3) { if (map1[playerx][playery + 2][0] == 2 || map1[playerx][playery + 2][0] == 3 || map1[playerx][playery + 2][0] == 0) { return false; } } break; default: break; } return true; } /** * 角色移动 * @param direction 方向 1234wasd */ private void Move(int direction) { switch (direction) { case 1: // 上 if (map1[playerx - 1][playery][0] == 2 || map1[playerx - 1][playery][0] == 3) { // 保存目标位置原始状态 int targetOriginal = map1[playerx - 2][playery][0]; // 移动箱子 if (targetOriginal == 4) { // 目标位置是点位 map1[playerx - 2][playery][0] = 3; // 变为已到位箱子 } else { map1[playerx - 2][playery][0] = 2; // 变为普通箱子 } // 恢复原来位置 if (map1[playerx - 1][playery][0] == 3) { // 如果移动的是已到位箱子 map1[playerx - 1][playery][0] = 4; // 恢复为点位 } else { map1[playerx - 1][playery][0] = 1; // 恢复为地板 } } playerx -= 1; break; case 2: // 左 if (map1[playerx][playery - 1][0] == 2 || map1[playerx][playery - 1][0] == 3) { int targetOriginal = map1[playerx][playery - 2][0]; if (targetOriginal == 4) { map1[playerx][playery - 2][0] = 3; } else { map1[playerx][playery - 2][0] = 2; } if (map1[playerx][playery - 1][0] == 3) { map1[playerx][playery - 1][0] = 4; } else { map1[playerx][playery - 1][0] = 1; } } playery -= 1; break; case 3: // 下 if (map1[playerx + 1][playery][0] == 2 || map1[playerx + 1][playery][0] == 3) { int targetOriginal = map1[playerx + 2][playery][0]; if (targetOriginal == 4) { map1[playerx + 2][playery][0] = 3; } else { map1[playerx + 2][playery][0] = 2; } if (map1[playerx + 1][playery][0] == 3) { map1[playerx + 1][playery][0] = 4; } else { map1[playerx + 1][playery][0] = 1; } } playerx += 1; break; case 4: // 右 if (map1[playerx][playery + 1][0] == 2 || map1[playerx][playery + 1][0] == 3) { int targetOriginal = map1[playerx][playery + 2][0]; if (targetOriginal == 4) { map1[playerx][playery + 2][0] = 3; } else { map1[playerx][playery + 2][0] = 2; } if (map1[playerx][playery + 1][0] == 3) { map1[playerx][playery + 1][0] = 4; } else { map1[playerx][playery + 1][0] = 1; } } playery += 1; break; } } /** * 检查是否成功,即地图上没有空箱子 * @return */ boolean IsSuccess() { for (int i = 0; i < MAP_WIDTH/SOUREC_WIDTH; i++) { for (int j = 0; j < MAP_HEIGHT/SOUREC_HEIGHT; j++) { if (map1[i][j][0] == 2) { // 只检查空箱子(2),不检查已到位箱子(3) return false; } } } return true; } /** *闯过本关,开启下一关 */ void GetNextMap() { if (diy) { if (Utils.IsExistence(PATH + "\\diy" + (level+1) + ".map")) { JOptionPane.showMessageDialog(null,"恭喜通关!即将进入下一关", "成功", JOptionPane.INFORMATION_MESSAGE); level++; GetMAP(level, diy); }else { Success(); } } else { if (Utils.IsExistence(PATH + "\\" + (level+1) + ".map")) { JOptionPane.showMessageDialog(null, "恭喜通关!即将进入下一关", "成功", JOptionPane.INFORMATION_MESSAGE); level++; GetMAP(level, diy); }else { Success(); } } } /** * 全部闯关成功,闯关成功即弹出提示且调到第一关或者其他操作 */ void Success() { JOptionPane.showMessageDialog(null, "恭喜你,全部闯关成功!", "全部通关", JOptionPane.PLAIN_MESSAGE); level=1; GetMAP(level, diy); } }