水一篇文章,献给需要过java课程设计的同学,这是我上学期学java的时候弄的,老师只给了3天时限,我主学语言也不是java,所以写的比较乱以及堆了很多⑩山代码,希望对你能有帮助!
游戏界面展示:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
public class MineSweeperGame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private static int SIZE = 12; // 格数
private static int MINES = 20; // 雷数
private static boolean ACC1 = false; // 初始化成就
private static boolean ACC2 = false;
private static boolean ACC3 = false;
private static boolean ACC4 = false;
private static boolean ACC5 = false;
private static boolean ACC6 = false;
private static boolean ACC7 = false;
private static boolean ACC8 = false;
private static boolean ACC9 = false;
private static int PASS = 0; // 通关次数
private static boolean DIFFICULTY = false; // 困难模式是否开启
private static int SUP = 1; // 倚天屠龙范围
private JButton[][] buttons; // 格子
private boolean[][] mines; // 地雷
private boolean[][] revealed; // 揭示
private boolean[][] flagged; // 标记
private int remainingCells; // 未揭示
private int secondsPassed; // 计时
private Timer timer; // 计时器
private JButton cheatButton; // 按钮
private JButton quickCheatButton;
private JButton superPowerButton;
private JButton changeButton;
private JButton buffButton;
private JButton moneyButton;
private JButton settingsButton;
private JButton achievementButton;
private boolean changeEnable = false; // 标识斗转星移是否被开启
private boolean cheatEnable = false; // 标识心眼通明是否被开启
private boolean superPowerActivated = false;// 标识倚天屠龙是否被开启
private boolean canary = false; // 标识是否作弊
private boolean firstClick = true; // 标识是否是第一次点击
private JLabel moneyLabel; // 用于显示金钱数量的标签
private int money = 0; // 用于存储金钱的变量
private int buff = 0; // 标识天赋
private JLabel backgroundLabel;
public MineSweeperGame() {
setResizable(false); // 禁止更改窗口大小
setTitle("千变扫雷"); // 窗口名称
setSize(1280, 720); // 窗口大小
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时结束进程,释放内存
setLayout(new BorderLayout()); // 使用BorderLayout作为总窗口布局管理器
int windowWidth = getWidth();
int windowHeight = getHeight();
backgroundLabel = new JLabel();
backgroundLabel.setBackground(Color.WHITE); //将背景设置为白色
backgroundLabel.setLayout(new BorderLayout()); // 使用BorderLayout作为背景图片布局管理器
JPanel gamePanel = new JPanel(); // 创建gamePanel对象作为游戏板
gamePanel.setLayout(new GridLayout(SIZE, SIZE)); // 使用GridLayout作为游戏板布局管理器,并且GridLayout会自动将组件均匀填充,因此无需手动设置buttons的大小
backgroundLabel.add(gamePanel, BorderLayout.CENTER); // 将游戏板添加至背景图片中心
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); // 使用Toolkit获取当前屏幕大小
int x = (int) ((screenSize.getWidth() - getWidth()) / 2); // 计算屏幕的中心
int y = (int) ((screenSize.getHeight() - getHeight()) / 2);
setLocation(x, y); // 设置窗口到屏幕中心
buttons = new JButton[SIZE][SIZE]; // 在构造方法中初始化各个参数
mines = new boolean[SIZE][SIZE];
revealed = new boolean[SIZE][SIZE];
flagged = new boolean[SIZE][SIZE];
remainingCells = SIZE * SIZE - MINES;
secondsPassed = 0;
initializeGameBoard(); // 初始化游戏板
placeMines(); // 初始化地雷
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
final int row = i;
final int col = j;
buttons[i][j] = new JButton(); // 在第i行,第j列创建一个按钮对象
buttons[i][j].addMouseListener(new MouseAdapter() { // 为每个按钮添加鼠标点击监听器,使用MouseAdapter适配器,这样就不需要实现MouseListener接口下所有的方法
@Override
public void mouseClicked(MouseEvent e) { // 重写鼠标点击的方法,参数为MouseEvent类型
if (firstClick) { // 判断是否是第一次点击
startGame(); // 第一次点击时开始计时
firstClick = false;
}
if (SwingUtilities.isLeftMouseButton(e)) { // 如果是左键点击
handleLeftClick(row, col);
} else if (SwingUtilities.isRightMouseButton(e)) { // 如果是右键点击
handleRightClick(row, col);
}
}
});
gamePanel.add(buttons[i][j]); // 添加完监听器后,将其放入游戏板,点击这个格子后,监听器就会根据收到的信息做出反馈
}
}
timer = new Timer(1000, new ActionListener() { // 创建ActionListener监听器,传给Timer构造函数,每1000毫秒向监听器发送动作事件
@Override
public void actionPerformed(ActionEvent e) { // 重写actionPerformed方法
secondsPassed++;
updateTimerLabel();
}
});
backgroundLabel.add(Box.createRigidArea(new Dimension((windowWidth - windowHeight) / 2, 0)), BorderLayout.WEST); // 为窗口左右两侧添加刚性区域,否则之前设置游戏板在窗口中心,BorderLayout会自动默认整个窗口都是窗口中心,因此整个窗口全部都填充为游戏板
backgroundLabel.add(Box.createRigidArea(new Dimension((windowWidth - windowHeight) / 2, 0)), BorderLayout.EAST);
add(backgroundLabel); // 将背景板添加至窗口
moneyLabel = new JLabel("金钱:" + money); // 初始化金钱标签
superPowerButton = new JButton("【天赋.倚天屠龙】"); // 创建按钮对象
superPowerButton.addActionListener(new ActionListener() { // 添加ActionListener监听器
@Override
public void actionPerformed(ActionEvent e) { // 重写actionPerformed方法
buff = 0; // 标记此buff
if (money >= 10) { // 若金钱大于等于10
buyBuff(); // 购买此buff
superPowerButton.setEnabled(false); // 禁止二次购买
superPowerActivated = true; // 开启此buff
} else {
buffNot(); // 金钱小于10,购买失败
}
}
});
cheatButton = new JButton("【天赋.心眼通明】");
cheatButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
buff = 1;
if (money >= 20) {
buyBuff();
cheatButton.setEnabled(false);
cheat();
cheatEnable = true;
} else {
buffNot();
}
}
});
changeButton = new JButton("【天赋.斗转星移】");
changeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
buff = 2;
if (money >= 15) {
buyBuff();
changeButton.setEnabled(false);
changeEnable = true;
} else {
buffNot();
}
}
});
quickCheatButton = new JButton("姐姐,我想。。。");
quickCheatButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canary = true;
gameWon();
}
});
buffButton = new JButton("天赋说明");
buffButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
buff();
}
});
moneyButton = new JButton("挖矿");
moneyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getMoney();
}
});
settingsButton = new JButton("设置");
settingsButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showSettingsDialog();
}
});
achievementButton = new JButton("成就");
achievementButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
achievement();
}
});
JPanel buttonPanel = new JPanel(); // 创建一个新容器,用于存放按钮
buttonPanel.add(moneyLabel);
buttonPanel.add(moneyButton);
buttonPanel.add(superPowerButton);
buttonPanel.add(changeButton);
buttonPanel.add(cheatButton);
buttonPanel.add(quickCheatButton);
buttonPanel.add(buffButton);
buttonPanel.add(achievementButton);
buttonPanel.add(settingsButton);
backgroundLabel.add(buttonPanel, BorderLayout.NORTH); // 将这个容器放到上方
}
private void startGame() {
timer.start(); // 开始计时
}
private void showDifficultyDialog() {
if (DIFFICULTY) { // 如果解锁了困难模式
Object[] options = {"简单", "普通", "困难"};
int result = JOptionPane.showOptionDialog(this, "请选择难度", "难度选择",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
switch (result) {
case 0: // 简单
reGame(8, 10);
break;
case 1: // 普通
reGame(12, 20);
break;
case 2: // 困难
reGame(14, 30);
break;
}
} else {
Object[] options = {"简单", "普通"};
int result = JOptionPane.showOptionDialog(this, "请选择难度", "难度选择",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
switch (result) {
case 0: // 简单
reGame(8, 10);
break;
case 1: // 普通
reGame(12, 20);
break;
}
}
}
private void reGame(int s, int m) {
SIZE = s;
MINES = m;
dispose(); // 关闭窗口
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
MineSweeperGame newGame = new MineSweeperGame();
newGame.setVisible(true);
}
});
}
private void showSettingsDialog() {
JDialog settingsDialog = new JDialog(this, "设置", true); // 创建设置窗口
settingsDialog.setSize(300, 200); // 窗口大小
settingsDialog.setLayout(new GridLayout(3, 1)); // 使用GridLayout布局管理器
JButton difficultyButton = new JButton("难度"); // 设置难度按钮
difficultyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showDifficultyDialog();
}
});
JButton soundEffectButton = new JButton("音效(暂未开放)");
difficultyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
JButton musicButton = new JButton("音乐(暂未开放)");
difficultyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
settingsDialog.add(difficultyButton); // 添加按钮
settingsDialog.add(musicButton); // 添加难度按钮
settingsDialog.add(soundEffectButton); // 添加难度按钮
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((screenSize.getWidth() - settingsDialog.getWidth()) / 2);
int y = (int) ((screenSize.getHeight() - settingsDialog.getHeight()) / 2);
settingsDialog.setLocation(x, y); // 设置居中
settingsDialog.setVisible(true); // 窗口显示
}
private void achievement() {
JOptionPane.showMessageDialog(this, "【初出茅庐】获得一次胜利。奖励:挖矿效率+1\n"
+ "【小有成就】获得十次胜利。奖励:挖矿效率+10\n"
+ "【作弊者】花费0秒获得胜利。无奖励\n"
+ "【至空至明】简单或普通难度下不依靠任何天赋获得胜利。奖励:开启困难模式\n"
+ "【荒】困难模式下不依靠任何天赋获得胜利。奖励:10元现金\n"
+ "【倒霉蛋】有【天赋.斗转星移】仍然被雷炸死。奖励:斗转星移概率提升至100%\n"
+ "【帝陨】有【天赋.倚天屠龙】仍然被雷炸死。奖励:倚天屠龙范围增加2圈\n"
+ "【傻子】有【天赋.心眼通明】仍然被雷炸死。无奖励\n"
+ "【灭道】解锁以上所有成就。奖励:获得装备【无尘剑】“上古神剑,威力无匹,指天天崩,划地地裂”\n",
"成就", JOptionPane.INFORMATION_MESSAGE);
}
private void getMoney() {
if (ACC1) { // 如果解锁了成就
if (ACC2) {
money += 10;
} else {
money += 2;
}
} else {
money += 1;
}
updateMoneyLabel(); // 更新金钱数量
}
private void buffNot() {
switch (buff) { // 判断是什么buff
case 0:
JOptionPane.showMessageDialog(this, "金钱≥10才能购买此天赋,少年快去努力挖矿吧!", "金钱不足", JOptionPane.INFORMATION_MESSAGE);
break;
case 1:
JOptionPane.showMessageDialog(this, "金钱≥20才能购买此天赋,少年快去努力挖矿吧!", "金钱不足", JOptionPane.INFORMATION_MESSAGE);
break;
case 2:
JOptionPane.showMessageDialog(this, "金钱≥15才能购买此天赋,少年快去努力挖矿吧!", "金钱不足", JOptionPane.INFORMATION_MESSAGE);
break;
}
}
private void buyBuff() {
switch (buff) {
case 0:
money -= 10;
updateMoneyLabel();
JOptionPane.showMessageDialog(this, "【天赋.倚天屠龙】购买成功!", "【天赋.倚天屠龙】", JOptionPane.INFORMATION_MESSAGE);
break;
case 1:
money -= 20;
updateMoneyLabel();
JOptionPane.showMessageDialog(this, "【天赋.心眼通明】购买成功!", "【天赋.心眼通明】", JOptionPane.INFORMATION_MESSAGE);
break;
case 2:
money -= 15;
updateMoneyLabel();
JOptionPane.showMessageDialog(this, "【天赋.斗转星移】购买成功!", "【天赋.斗转星移】", JOptionPane.INFORMATION_MESSAGE);
break;
}
}
private void updateMoneyLabel() {
moneyLabel.setText("金钱:" + money); // 更新金钱标签的显示文本
}
private void cheat() {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (mines[i][j]) { // 遍历地图,如果有雷则标记
flagged[i][j] = true;
updateCellText(i, j);
}
}
}
}
private void buff() {
JOptionPane.showMessageDialog(this, "【天赋.倚天屠龙】圣气在身,每次点击格子时,都会显示该格子周围8个格子中不是雷的格子\n\n"
+ "【天赋.心眼通明】能够用心眼视物,显示所有雷的格子\n\n"
+ "【天赋.斗转星移】武学奇才慕容龙城所领悟的借力打力的神奇招式,50%概率遇雷不死",
"天赋说明", JOptionPane.INFORMATION_MESSAGE);
}
private void initializeGameBoard() {
for (int i = 0; i < SIZE; i++) { // 遍历地图,将所有格子属性归零
for (int j = 0; j < SIZE; j++) {
mines[i][j] = false;
revealed[i][j] = false;
flagged[i][j] = false;
}
}
}
private void placeMines() {
Random random = new Random(); // 创建随机数生成器
int minesToPlace = MINES; // 获得雷的数量
while (minesToPlace > 0) { // 当雷没有被布置完的时候循环
int row = random.nextInt(SIZE); // 随机一行
int col = random.nextInt(SIZE); // 随机一列
if (!mines[row][col]) { // 如果这个位置没有雷,则布置,并将雷的数量-1
mines[row][col] = true;
minesToPlace--;
}
}
}
private void handleLeftClick(int row, int col) {
if (mines[row][col]) { // 如果点击的格子是雷
if (changeEnable) { // 如果开启buff
if (ACC6) { // 如果解锁成就,100%概率发动
JOptionPane.showMessageDialog(this, "【天赋.斗转星移】发动", "【天赋.斗转星移】", JOptionPane.INFORMATION_MESSAGE);
} else if (Math.random() < 0.5) { // 50%概率发动
JOptionPane.showMessageDialog(this, "【天赋.斗转星移】发动", "【天赋.斗转星移】", JOptionPane.INFORMATION_MESSAGE);
} else {
gameOver(row, col); // 游戏失败
}
} else {
gameOver(row, col);
}
} else {
if (superPowerActivated) { // 如果开启buff
activateSuperPower(row, col); // 执行buff效果
} else {
revealCell(row, col); // 否则揭示这个格子
}
if (remainingCells == 0) { // 如果剩余未揭露的非雷格数为0
gameWon(); // 游戏胜利
}
}
}
private void handleRightClick(int row, int col) {
if (!revealed[row][col]) { // 如果该格子未被揭示
flagged[row][col] = !flagged[row][col]; // 将标志位由0改1或是由1改0
updateCellText(row, col); // 更新标记
}
}
private void activateSuperPower(int row, int col) {
for (int i = Math.max(0, row - SUP); i <= Math.min(row + SUP, SIZE - 1); i++) { // 遍历包括此格子的周围9个格子
for (int j = Math.max(0, col - SUP); j <= Math.min(col + SUP, SIZE - 1); j++) { // 此格子不能超过地图边界
if (!mines[i][j]) { // 若该格子不是雷
revealCell(i, j); // 揭示此格子
}
}
}
}
private void revealCell(int row, int col) {
if (!revealed[row][col]) { // 如果该格子未被揭示
revealed[row][col] = true; // 揭示标志位改为1
buttons[row][col].setEnabled(false); // 揭示
remainingCells--; // 剩余未被揭示的非雷格-1
int minesNearby = countMinesNearby(row, col); // 检测附近包括自己的9个格子中有多少雷
if (minesNearby > 0) { // 如果有雷
buttons[row][col].setText(Integer.toString(minesNearby)); // 设置显示文本为雷的数量
} else {
for (int i = Math.max(0, row - 1); i <= Math.min(row + 1, SIZE - 1); i++) { // 否则则遍历周围包括自己的格子
for (int j = Math.max(0, col - 1); j <= Math.min(col + 1, SIZE - 1); j++) {
if (flagged[row][col]) { // 如果该格子被标记了
buttons[row][col].setText(""); // 设置文本为空
}
revealCell(i, j); // 迭代
}
}
}
}
}
private int countMinesNearby(int row, int col) {
int count = 0;
for (int i = Math.max(0, row - 1); i <= Math.min(row + 1, SIZE - 1); i++) {
for (int j = Math.max(0, col - 1); j <= Math.min(col + 1, SIZE - 1); j++) {
if (mines[i][j]) {
count++;
}
}
}
return count; // 返回雷的数量
}
private void updateCellText(int row, int col) {
if (flagged[row][col]) { // 如果标志位为1,在此格上贴一个“标”
buttons[row][col].setText("标");
} else { // 否则变为空
buttons[row][col].setText("");
}
}
private void updateTimerLabel() {
setTitle("千变扫雷 - 耗时: " + secondsPassed + " s"); // 更新计时器
}
private void gameOver(int row, int col) {
buttons[row][col].setText("雷");
buttons[row][col].setEnabled(false);
timer.stop();
JOptionPane.showMessageDialog(this, "失败乃兵家常事,少侠请重新来过", "身消道陨", JOptionPane.INFORMATION_MESSAGE);
if (changeEnable && !ACC6) {
JOptionPane.showMessageDialog(this, "获得成就【倒霉蛋】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC6 = true;
}
if (superPowerActivated && !ACC7) {
JOptionPane.showMessageDialog(this, "获得成就【帝陨】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC7 = true;
SUP = 3;
}
if (cheatEnable && !ACC8) {
JOptionPane.showMessageDialog(this, "获得成就【傻子】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC8 = true;
}
resetGame();
}
private void gameWon() {
timer.stop();
if (canary) {
JOptionPane.showMessageDialog(this, "你花了" + secondsPassed + " 秒就通关了?开了?", "菜就多练", JOptionPane.INFORMATION_MESSAGE);
if (!ACC3) {
JOptionPane.showMessageDialog(this, "获得成就【作弊者】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC3 = true;
}
} else if (ACC9){
JOptionPane.showMessageDialog(this, "一道剑光划过,斩穿了诸界", "指天天崩,划地地裂", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, "你镇压了一切。花费" + secondsPassed + " 秒", "大侠得胜", JOptionPane.INFORMATION_MESSAGE);
}
PASS++;
if (PASS == 1) {
JOptionPane.showMessageDialog(this, "获得成就【初出茅庐】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC1 = true;
} else if (PASS == 10) {
JOptionPane.showMessageDialog(this, "获得成就【小有成就】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC2 = true;
}
if (!changeEnable && !superPowerActivated && !canary && !ACC4) {
JOptionPane.showMessageDialog(this, "获得成就【至空至明】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC4 = true;
DIFFICULTY = true;
}
if (!changeEnable && !superPowerActivated && !canary && !ACC5 && SIZE == 14) {
JOptionPane.showMessageDialog(this, "获得成就【荒】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
ACC5 = true;
}
resetGame();
}
private void resetGame() {
if (ACC1 && ACC2 && ACC3 && ACC4 && ACC5 && ACC6 && ACC7 && ACC8 && !ACC9) {
JOptionPane.showMessageDialog(this, "获得成就【灭道】!", "成就解锁", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(this, "获得装备【无尘剑】!", "指天天崩,划地地裂", JOptionPane.INFORMATION_MESSAGE);
ACC9 = true;
}
firstClick = true; // 重置第一次点击标志
money = 0; // 重置金钱数量
initializeGameBoard(); // 重置游戏板
placeMines(); // 重置地雷
remainingCells = SIZE * SIZE - MINES; // 重置剩余地雷数量
secondsPassed = 0; // 重置计时
superPowerActivated = false; // 重置buff使用状态
canary = false;
changeEnable = false;
cheatEnable = false;
if (ACC9) {
SUP = 99;
superPowerActivated = true;
changeEnable = true;
}
for (int i = 0; i < SIZE; i++) { // 重置所有格子文本
for (int j = 0; j < SIZE; j++) {
buttons[i][j].setText("");
buttons[i][j].setEnabled(true);
}
}
superPowerButton.setEnabled(true); // 重置天赋购买按钮
cheatButton.setEnabled(true);
changeButton.setEnabled(true);
updateTimerLabel(); // 重置时间标签
updateMoneyLabel(); // 重置金钱标签
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() { // 调用invokeLater使得new Runnable()与run()并行,异步执行
@Override
public void run() {
MineSweeperGame game = new MineSweeperGame();
game.setVisible(true); // 窗口可见
}
});
}
}
本来想后续扩展成打怪(雷)升级爆装备的挂机类游戏(例如,可以给某些雷增加debuff,在这个雷附近的8个格子都不可见这种,或者是【死2】debuff,只有【不死2】能够抵抗。挖矿后面可以买挖掘机自动获得金币,还可以自动开格子,更强的挖掘机可以开更强的格子【坚硬2】,懂放置的自然明白。玩法除了我的这些天赋还是可以弄出很多的),但是没时间,也懒得搞啦,有能力的同学可以在我这基础上升级。
上面那个代码是我改过的,没有背景图片,因为一起传也比较麻烦,有的人可能也不会用背景图片,所以就删了只留了个源代码,以下是原游戏界面: