You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package cn.edu.caztc.sokobangame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class DualGame extends JFrame implements MapConfig {
private int[][][] map1;
private int player1x = -1, player1y = -1;
private int player2x = -1, player2y = -1;
private int level = 1;
private boolean diy = false;
private JPanel panel;
private static DualGame instance;
private ImageIcon[] currentIcons;
private UpdateThread updateThread;
public static DualGame getInstance() {
return instance;
}
public DualGame() {
instance = this;
currentIcons = ThemeSwitcher.getCurrentThemeIcons().clone();
initUI();
loadInitialMap();
setVisible(true);
}
public void updateTheme(ImageIcon[] newIcons) {
currentIcons = newIcons.clone();
panel.repaint();
}
private void initUI() {
setTitle("推箱子-双人模式");
setSize(900, 950);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
initMenu();
initGamePanel();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
cleanupResources();
System.out.println("双人模式程序终止"); // 添加终止信息
}
});
}
private void initMenu() {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("菜单");
JMenuItem levelItem = new JMenuItem("选关");
levelItem.addActionListener(e -> selectLevel());
menu.add(levelItem);
JMenuItem restartItem = new JMenuItem("重新开始");
restartItem.addActionListener(e -> GetMAP(level, diy));
menu.add(restartItem);
JMenuItem singleModeItem = new JMenuItem("切换到单人模式");
singleModeItem.addActionListener(e -> switchToSingleMode());
menu.add(singleModeItem);
menuBar.add(menu);
setJMenuBar(menuBar);
}
private void initGamePanel() {
panel = new DualPanel();
panel.setPreferredSize(new Dimension(MAP_WIDTH, MAP_HEIGHT));
panel.setBackground(Color.BLACK);
add(panel);
panel.setFocusable(true);
panel.requestFocusInWindow();
panel.addKeyListener(new DualKeyListener());
}
private void loadInitialMap() {
GetMAP(1, false);
updateThread = new UpdateThread(panel);
updateThread.start();
}
private void cleanupResources() {
MusicPlayer.getInstance().stopMusic();
if (updateThread != null) {
updateThread.stopRunning();
}
}
void GetMAP(int level, boolean diy) {
String prefix = diy ? "双人diy" : "双人";
String filePath = PATH + "\\" + prefix + level + ".map";
try {
File mapFile = new File(filePath);
loadMapData(filePath);
validateSpawnPoints();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"地图加载失败: " + e.getMessage() + "\n文件路径: " + filePath,
"错误", JOptionPane.ERROR_MESSAGE);
}
refreshGameDisplay();
}
private void loadMapData(String filePath) throws IOException {
try (DataInputStream in = new DataInputStream(
new BufferedInputStream(new FileInputStream(filePath)))) {
resetPlayerPositions();
int rows = in.readInt();
int cols = in.readInt();
map1 = new int[rows][cols][1];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int cellValue = in.readInt();
map1[i][j][0] = cellValue;
if (cellValue == 5) { // 玩家一出生点
player1x = i;
player1y = j;
map1[i][j][0] = 1; // 出生点变为空地
} else if (cellValue == 6) { // 玩家二出生点
player2x = i;
player2y = j;
map1[i][j][0] = 1; // 出生点变为空地
}
}
}
}
}
private void validateSpawnPoints() {
if (player1x == -1 || player2x == -1) {
JOptionPane.showMessageDialog(null,
"地图必须包含两个出生点(5-玩家一,6-玩家二)", "错误", JOptionPane.ERROR_MESSAGE);
}
}
class DualPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
if (map1 != null) {
for (int i = 0; i < map1.length; i++) {
for (int j = 0; j < map1[0].length; j++) {
int cellValue = map1[i][j][0];
if (cellValue >= 0 && cellValue < currentIcons.length) { // 使用currentIcons
Image img = currentIcons[cellValue].getImage();
if (img != null) {
g.drawImage(img, j*SOUREC_WIDTH, i*SOUREC_HEIGHT,
SOUREC_WIDTH, SOUREC_HEIGHT, this);
}
}
}
}
}
// 绘制玩家同样使用currentIcons
if (player1x >= 0 && player1y >= 0) {
g.drawImage(currentIcons[5].getImage(), player1y*SOUREC_WIDTH, player1x*SOUREC_HEIGHT,
SOUREC_WIDTH, SOUREC_HEIGHT, this);
}
if (player2x >= 0 && player2y >= 0) {
g.drawImage(currentIcons[6].getImage(), player2y*SOUREC_WIDTH, player2x*SOUREC_HEIGHT,
SOUREC_WIDTH, SOUREC_HEIGHT, this);
}
}
}
class DualKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP: tryMove(1, 1); break;
case KeyEvent.VK_DOWN: tryMove(1, 3); break;
case KeyEvent.VK_LEFT: tryMove(1, 2); break;
case KeyEvent.VK_RIGHT: tryMove(1, 4); break;
case KeyEvent.VK_W: tryMove(2, 1); break;
case KeyEvent.VK_S: tryMove(2, 3); break;
case KeyEvent.VK_A: tryMove(2, 2); break;
case KeyEvent.VK_D: tryMove(2, 4); break;
}
panel.repaint();
}
private void tryMove(int playerNum, int direction) {
if (canMove(playerNum, direction)) {
if (isPushingBox(playerNum, direction)) {
if (canPushBox(playerNum, direction)) {
movePlayer(playerNum, direction);
}
} else {
movePlayer(playerNum, direction);
}
if (IsSuccess()) {
Success();
}
}
}
}
// 其他辅助方法...
private void movePlayer(int playerNum, int direction) {
int x = playerNum == 1 ? player1x : player2x;
int y = playerNum == 1 ? player1y : player2y;
int newX = x, newY = y;
int frontX = x, frontY = y;
int beyondX = x, beyondY = y;
switch (direction) {
case 1: newX--; frontX--; beyondX -= 2; break;
case 2: newY--; frontY--; beyondY -= 2; break;
case 3: newX++; frontX++; beyondX += 2; break;
case 4: newY++; frontY++; beyondY += 2; break;
}
if ((playerNum == 1 && newX == player2x && newY == player2y) ||
(playerNum == 2 && newX == player1x && newY == player1y)) {
return;
}
if (map1[frontX][frontY][0] == 2 || map1[frontX][frontY][0] == 3) {
if ((beyondX == player1x && beyondY == player1y) ||
(beyondX == player2x && beyondY == player2y)) {
return;
}
map1[beyondX][beyondY][0] = (map1[beyondX][beyondY][0] == 4) ? 3 : 2;
map1[frontX][frontY][0] = (map1[frontX][frontY][0] == 3) ? 4 : 1;
}
if (playerNum == 1) {
player1x = newX;
player1y = newY;
} else {
player2x = newX;
player2y = newY;
}
}
boolean IsSuccess() {
for (int i = 0; i < map1.length; i++) {
for (int j = 0; j < map1[0].length; j++) {
if (map1[i][j][0] == 2) {
return false;
}
}
}
return true;
}
void Success() {
String prefix = diy ? "双人diy" : "双人";
// 先检查是否是最后一关
if (!new File(PATH + "\\" + prefix + (level+1) + ".map").exists()) {
// 是最后一关
JOptionPane.showMessageDialog(null,
"恭喜您已通关所有关卡!",
"全部通关", JOptionPane.INFORMATION_MESSAGE);
level = 1;
GetMAP(level, diy);
} else {
// 不是最后一关
JOptionPane.showMessageDialog(null,
"恭喜通关!即将进入下一关",
"成功", JOptionPane.INFORMATION_MESSAGE);
GetNextMap();
}
}
void GetNextMap() {
String prefix = diy ? "双人diy" : "双人";
level++;
GetMAP(level, diy);
}
private void refreshGameDisplay() {
panel.repaint();
panel.requestFocusInWindow();
}
private void selectLevel() {
GetLevelDialog dialog = new GetLevelDialog(true);
if (dialog.getValue() != 0) {
diy = dialog.isdiy();
level = dialog.getValue();
GetMAP(level, diy);
}
}
private void switchToSingleMode() {
new MainGame().setVisible(true);
dispose();
}
private void resetPlayerPositions() {
player1x = player1y = player2x = player2y = -1;
}
private boolean canMove(int playerNum, int direction) {
int x = playerNum == 1 ? player1x : player2x;
int y = playerNum == 1 ? player1y : player2y;
switch (direction) {
case 1: return x > 0 && map1[x-1][y][0] != 0;
case 2: return y > 0 && map1[x][y-1][0] != 0;
case 3: return x < map1.length-1 && map1[x+1][y][0] != 0;
case 4: return y < map1[0].length-1 && map1[x][y+1][0] != 0;
}
return false;
}
private boolean isPushingBox(int playerNum, int direction) {
int x = playerNum == 1 ? player1x : player2x;
int y = playerNum == 1 ? player1y : player2y;
switch (direction) {
case 1: return x > 0 && (map1[x-1][y][0] == 2 || map1[x-1][y][0] == 3);
case 2: return y > 0 && (map1[x][y-1][0] == 2 || map1[x][y-1][0] == 3);
case 3: return x < map1.length-1 && (map1[x+1][y][0] == 2 || map1[x+1][y][0] == 3);
case 4: return y < map1[0].length-1 && (map1[x][y+1][0] == 2 || map1[x][y+1][0] == 3);
}
return false;
}
private boolean canPushBox(int playerNum, int direction) {
int x = playerNum == 1 ? player1x : player2x;
int y = playerNum == 1 ? player1y : player2y;
int frontX = x, frontY = y;
int beyondX = x, beyondY = y;
switch (direction) {
case 1: frontX--; beyondX -= 2; break;
case 2: frontY--; beyondY -= 2; break;
case 3: frontX++; beyondX += 2; break;
case 4: frontY++; beyondY += 2; break;
}
if (frontX < 0 || frontY < 0 ||
frontX >= map1.length || frontY >= map1[0].length ||
(map1[frontX][frontY][0] != 2 && map1[frontX][frontY][0] != 3)) {
return false;
}
if (beyondX < 0 || beyondY < 0 ||
beyondX >= map1.length || beyondY >= map1[0].length ||
map1[beyondX][beyondY][0] == 0 ||
map1[beyondX][beyondY][0] == 2 ||
map1[beyondX][beyondY][0] == 3) {
return false;
}
return true;
}
}