JAVA版扫雷游戏,清晰易懂,注释多

article/2025/10/12 14:39:33

这是一篇关于JAVA的扫雷游戏,所有的图片均用文字代替,代码可直接运行。

文章目录

  • 开发环境
  • 一、下载方法
  • 二、运行效果展示
  • 三、代码部分
    • 1.代码如下
  • 总结


开发环境

开发工具:eclipse2021-12
JDK版本:JDK15.0.1


一、下载方法

链接:https://pan.baidu.com/s/1pw4WwztyfWrlSq_V2y6jfA
提取码:dhpm

二、运行效果展示

这张图是游戏刚开始的画面,重置以后也是这个画面
在这里插入图片描述
此图是写代码的过程调试用的画面,方便查找问题。
在这里插入图片描述

此图是运行过程中的图片
在这里插入图片描述
带有计时功能,游戏成功的条件是用完所有的旗,并且放在雷上面。
超时,或者用完旗以后,有旗子没在正确的位置上,或者踩到地雷,都会导致游戏失败。

三、代码部分

1.代码如下

代码如下(示例):

package com.first;import java.awt.Color;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;public class MineSweeper {static private GamePanel gPanel;/* 雷区 */static private int midtime = 3600, mineNum = 0;/* 倒计时时间以及可用旗子数量 */static private JLabel label1, label2;static CountDown cd;/*** 构造函数 用于初始化*/public MineSweeper() {JFrame jf = new JFrame("扫雷小游戏");jf.setDefaultCloseOperation(3);// EXIT_ON_CLOSE,直接关闭应用程序,System.exit(0)。一个main函数对应一整个程序。jf.setLayout(null);// 未设置Layout时,java默认为flowLayout布局的,设置为null即为清空布局管理器,之后添加组件,常常是设置组件左上角坐标相对于容器左上角(0,0)的x,y值来确定组件的位置jf.setBounds(600, 200, 700, 800);// 设置窗口的大小和位置label1 = new JLabel("剩余时间:" + (midtime / 60 / 60 % 60) + ":" + (midtime / 60 % 60) + ":" + (midtime % 60));label1.setBounds(10, 20, 120, 20);jf.add(label1);label2 = new JLabel("剩余旗子:" + mineNum);label2.setBounds(400, 20, 240, 20);// 设置label2的位置以及大小jf.add(label2);JButton resetButt = new JButton("重置");// 创建重置按钮resetButt.setMargin(new Insets(0, 0, 0, 0));// 设置边框resetButt.setBounds(230, 15, 60, 30);// 设置按钮在窗口中的位置和大小resetButt.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubjf.dispose();/* 销毁窗口 */new MineSweeper();midtime = 3600;}});jf.add(resetButt);// 把按钮添加到窗口中gPanel = new GamePanel(20, 20);// 设置按钮数量为20行*20列gPanel.setBounds(40, 100, 600, 600);// 设置雷区面板的位置以及大小jf.add(gPanel);// 雷区面板添加到窗口中jf.setVisible(true);// 设置窗口可见}static class CountDown extends Thread {@Overridepublic void run() {super.run();while (midtime > 0) {try {--midtime;label1.setText("剩余时间:" + (midtime / 60 / 60 % 60) + ":" + (midtime / 60 % 60) + ":" + (midtime % 60));sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}if (midtime == 0) {JOptionPane.showMessageDialog(null, "时间已到", "游戏结束", JOptionPane.PLAIN_MESSAGE);}}}public static void main(String[] args) {// 程序的入口new MineSweeper();// 进入构造函数cd = new CountDown();// 创建计时器cd.start();/* 启动计时器 */}public static void setMineNum(int minesCount2) {// TODO Auto-generated method stubmineNum = minesCount2;label2.setText("剩余旗子:" + mineNum);}
}class GamePanel extends JPanel {private int rows, cols, minesCount;// 创建行数、列数变量,地雷的数量private final int BLOCKWIDTH = 30;// 规定每个按钮的宽度private final int BLOCKHEIGHT = 30;// 规定每个按钮的高度private Buts[][] buts;// 雷区按钮private JLabel[][] jlabel;// 每个按钮下对应标签private boolean[][] state;// true:有雷;false:没有雷private int[][] click;// 0:未点击,1:已点击,2:未点击但周围有雷,3:插旗public GamePanel(int row, int col) {rows = row;// 行数cols = col;// 列数minesCount = rows * cols / 10;// 地雷的数量MineSweeper.setMineNum(minesCount);buts = new Buts[rows][cols];// 创建雷区按钮jlabel = new JLabel[rows][cols];// 创建标签state = new boolean[rows][cols];// true:有雷;false:没有雷click = new int[rows][cols];// 0:未点击,1:已点击,2:未点击但周围有雷,3:插旗setLayout(null);// 设置为null即为清空布局管理器,之后添加组件,常常是设置组件左上角坐标相对于容器左上角(0,0)的x,y值来确定组件的位置initButtons();// 初始化按钮,设置每个按钮的基本参数initLable();// 初始化标签方格,设置每个标签的基本参数buryMines();// 埋雷,随机生成地雷writerNumber();// 计算每个方格周围8个方格中有几个地雷}/* 用于统计每个方格周围有多少地雷 */private void writerNumber() {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if (!state[i][j]) {// 没有雷的地方才探测周围的情况int numbers = 0;// 用于记录每个方格四周有多少地雷for (int r = -1; r < 2; r++) {// 探测每个方格行坐标-1,0,+1后的情况for (int c = -1; c < 2; c++) {// 探测每个方格列坐标-1,0,+1后的情况if ((i + r > -1) && (i + r < cols) && (j + c > -1) && (j + c < rows)) {// 判断有没有超过数组的边界if (state[i + r][j + c] == true) {// 探测的位置上有地雷则numbers加1numbers++;}}}}if (numbers > 0) {click[i][j] = 2;// 设置为:未点击但周围有雷}jlabel[i][j].setText(String.valueOf(numbers));// 给每个单元赋值,周围8个方格中有几个地雷
//					buts[i][j].setText(String.valueOf(numbers));// 调试代码用}}}}private void initButtons() {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {Buts but = new Buts();but.i = i;// 给按钮的行信息赋值but.j = j;// 给按钮的列信息赋值but.setBounds(BLOCKWIDTH * j, BLOCKHEIGHT * i, BLOCKWIDTH, BLOCKHEIGHT);// 设置每一个按钮的位置和大小but.setMargin(new Insets(0, 0, 0, 0));// 设置按钮边框/* 给按钮添加鼠标监听器,检测是否点击 */but.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {/* 左击 */if (e.getButton() == MouseEvent.BUTTON1) {
//							but.setVisible(false);//调试代码用
//							jlabel[but.i][but.j].setVisible(true);//调试代码用openButtons(but);}/* 右击 */if (e.getButton() == MouseEvent.BUTTON3) {
//							but.setText("旗");// 调试代码用placeFlag(but);}}});buts[i][j] = but;// 赋值给公共变量,方便调用this.add(buts[i][j]);// 添加到面板中jpanel}}}protected void placeFlag(Buts but) {if (click[but.i][but.j] != 3) {buts[but.i][but.j].setText("旗");
//			System.out.println("click[but.i][but.j] =" + click[but.i][but.j]);// 调试代码用click[but.i][but.j] = 3;// 0:未点击,1:已点击,2:未点击但周围有雷,3:插旗minesCount--;MineSweeper.setMineNum(minesCount);} else {buts[but.i][but.j].setText("");if (!state[but.i][but.j]) {if (Integer.valueOf(jlabel[but.i][but.j].getText()) > 0) {click[but.i][but.j] = 2;// 周围有地雷
//					System.out.println("click[but.i][but.j] =" + click[but.i][but.j]);// 调试代码用} else {click[but.i][but.j] = 0;// 未点击
//					System.out.println("click[but.i][but.j] =" + click[but.i][but.j]);// 调试代码用}minesCount++;MineSweeper.setMineNum(minesCount);} else {click[but.i][but.j] = 0;// 未点击}}if (minesCount == 0) {// 当旗子用完后,判断是否全部标记正确boolean flag = true;for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {if ((click[i][j] != 3) && (state[i][j])) {// 对所有没有插旗的方格进行判断,如果没有插旗,但是state的状态又未true,则令flag未falseflag = false;}}}if (flag) {MineSweeper.cd.stop();// 停止计时JOptionPane.showMessageDialog(null, "您成功了", "游戏结束", JOptionPane.PLAIN_MESSAGE);} else {MineSweeper.cd.stop();// 停止计时JOptionPane.showMessageDialog(null, "旗子已经用完", "游戏失败", JOptionPane.PLAIN_MESSAGE);}}}protected void openButtons(Buts but) {int i = but.i;int j = but.j;if (state[i][j] && (click[i][j] != 3)) {openAllCell();MineSweeper.cd.stop();JOptionPane.showMessageDialog(null, "您踩到地雷了", "游戏结束", JOptionPane.PLAIN_MESSAGE);}if (click[i][j] == 2) {buts[i][j].setVisible(false);jlabel[i][j].setVisible(true);}if ((click[i][j] == 0) || (click[i][j] == 1)) {// 0的周围是要判断的,1的周围也有可能所以也要判断for (int r = -1; r < 2; r++) {for (int c = -1; c < 2; c++) {if ((i + r > -1) && (i + r < cols) && (j + c > -1) && (j + c < rows) && (!state[i + r][j + c])) {// 判断有没有超过数组的边界if (click[i + r][j + c] == 0) {// 0:未点击,1:已点击,2:未点击但周围有雷,3:插旗buts[i + r][j + c].setVisible(false);jlabel[i + r][j + c].setVisible(true);click[i + r][j + c] = 1;openButtons(buts[i + r][j + c]);}if (click[i + r][j + c] == 2) {buts[i + r][j + c].setVisible(false);jlabel[i + r][j + c].setVisible(true);}}}}}}private void openAllCell() {// TODO Auto-generated method stubfor (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {buts[i][j].setVisible(false);jlabel[i][j].setVisible(true);click[i][j] = 1;}}}private void initLable() {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {JLabel l = new JLabel("", JLabel.CENTER);l.setBounds(j * BLOCKWIDTH, i * BLOCKHEIGHT, BLOCKWIDTH, BLOCKHEIGHT);// 设置每个小方格的位置大小l.setBorder(BorderFactory.createLineBorder(Color.gray));// 绘制方格边框为灰色l.setOpaque(true);// 设置方格为透明,方便我们填充l.setBackground(Color.lightGray);// 背景填充为浅灰色this.add(l);// 添加到面板中jlabel[i][j] = l;// 将方格加到类变量中,方便公用l.setVisible(false);// 设置不可见}}}private void buryMines() {// 生成雷区for (int i = 0; i < minesCount; i++) {int x = (int) (Math.random() * rows);// 生成随机行数int y = (int) (Math.random() * cols);// 生成随机列数/* 判断随机生成的位置是不是有地雷 */if (state[x][y] == true) {// 如果随机生成的位置上已经有雷了,则i--i--;} else {// 位置上没有雷,则state为true,标签设置为雷state[x][y] = true;jlabel[x][y].setText("雷");
//				buts[x][y].setText("雷");// 调式代码用
//				System.out.println(x + "," + y + ":位置有地雷");//调式代码用}}}
}class Buts extends JButton {public int i, j;
}

总结

不到300行代码实现了扫雷游戏,效果也不错。整个游戏经过几轮的优化,整体性能不错,方便理解。是上手实战的好项目。
附上下载连接地址:
链接:https://pan.baidu.com/s/1pw4WwztyfWrlSq_V2y6jfA
提取码:dhpm
欢迎交流,共同进步。


http://chatgpt.dhexx.cn/article/3QR5Ma9B.shtml

相关文章

猜数字游戏(Java源代码)

游戏后台随机生成1-20之间的5个数&#xff0c;未猜中提示“未命中”&#xff0c;继续猜测&#xff0c;猜中提示“运气不错&#xff0c;猜中了”&#xff0c;并输出数据出现的第一次位置源代码&#xff1a; import java.util.Random; import java.util.Scanner;//游戏后台随机…

JAVA实现扫雷游戏

后记&#xff1a;经评论区提醒&#xff0c;发现有两个bug没考虑到&#xff0c;感谢大家的提醒 bug1&#xff1a;绘制雷的时候有可能把两个雷随机到同样的位置。解决方法是在绘制雷的for循环内&#xff0c;rRow和rCol生成后做一个检测即可&#xff1a; /* 绘制地雷 */private v…

Java抽奖小游戏(包含代码)

情景&#xff1a; 假如从50个数字中确定10个中奖号码。 中奖号码要从50个数字中随机产生&#xff0c;中奖号码不可以重复&#xff0c;并对中奖号码进行排序。 解题思路&#xff1a; 首先建立一个长度为n号码的号码库&#xff1a;建立一个数组存放k个中奖号码抽取k个中奖号码。…

贪吃蛇java游戏代码_java实现贪吃蛇游戏代码(附完整源码)

先给大家分享源码&#xff0c;喜欢的朋友点此处下载。 游戏界面 GUI界面 java实现贪吃蛇游戏需要创建一个桌面窗口出来&#xff0c;此时就需要使用java中的swing控件 创建一个新窗口 JFrame frame new JFrame("贪吃蛇游戏"); //设置大小 frame.setBounds(10, 10, 90…

JAVA 实现生命游戏

生命游戏的规则: 生命游戏中&#xff0c;对于任意细胞&#xff1a;每个细胞有两种状态&#xff1a;存活或死亡。每个细胞与以自身为中心的周围八格细胞产生互动。    1.当前细胞为存活状态时&#xff0c;当周围的活细胞低于2个时&#xff0c; 该细胞因孤独而死亡;    2.当…

Java五子棋全代码

用Java编写简单的五子棋 前言 这两天在空闲时间做了个五子棋项目&#xff0c;分享给大家看一下&#xff0c;界面是这样的&#xff1a;        呜呜呜&#xff0c;界面很丑我知道&#xff0c;本人虽有几年PS基础&#xff0c;但知识浅薄&#xff0c;审美观不尽人意&#xff…

五子棋小游戏 java版(代码+详细注释)

游戏展示 这周闲来无事&#xff0c;再来写个五子棋小游戏。基本功能都实现了&#xff0c;包括人人对战、人机对战。界面布局和功能都写的还行&#xff0c;没做到很优秀&#xff0c;但也不算差。如有需要&#xff0c;做个java初学者的课程设计或者自己写着玩玩也都是不错的&…

【Java实现小游戏】飞翔的小鸟(源码)

游戏玩法&#xff1a;通过鼠标点击使小鸟上下移动穿过柱子并完成得分&#xff0c;小鸟碰到柱子或掉落到地面上都会结束游戏。 &#xff08;游戏内图片&#xff09; 下面是实现这个游戏的代码&#xff1a; Brid类&#xff1a; package bird;import org.omg.CORBA.IMP_LIMIT;im…

用简单Java代码尝试在控制台写游戏(附源码)

尝试写了一个在Java控制台运行的代码游戏&#xff0c;由于写这个的时候&#xff0c;博主还没学到可视化界面&#xff0c;也没有学到面向对象&#xff0c;甚至没有集合&#xff0c;运用的全是之前C语言的语法&#xff0c;因此应该很容易看懂吧。末尾附上源码。 以下是效果展示 …

Java小游戏练习---超级玛丽代码实现

B站教学视频&#xff1a; 01_超级玛丽_创建窗口_哔哩哔哩_bilibili 素材提取&#xff1a; 【超级会员V2】我通过百度网盘分享的文件&#xff1a;Java游戏项目… 链接:百度网盘 请输入提取码 提取码:k6j1 复制这段内容打开「百度网盘APP 即可获取」 百度网盘 请输入提取码 百度…

java 300行代码 冒险闯关小游戏(代码+讲解)

作为一个男孩子&#xff0c;从小就喜欢晚一些游戏。今天就用java写一个类似马里奥的冒险闯关小游戏&#xff0c;但这也不是一两天能完成的事情&#xff0c;我将会持续更新这个游戏&#xff08;有什么好的介意也非常欢迎大家提出来&#xff0c;也能在我的基础上自己接着写&#…

宝塔php防盗链,[宝塔面板]如何开启防盗链?

为了节省建站成本&#xff0c;大多数站长都会选择一些小服务器&#xff0c;在另加CDN、云存储之类的来减轻服务器的压力&#xff0c;但是这类功能大多收费。 如果自己网站的图片都让别人复制图片链接地址&#xff0c;那么自己CDN流量就跑得贼快&#xff0c;花了钱得不到好处。 …

HTTP防盗链(Referer)

HTTP请求防盗链&#xff1a;只允许某些域名请求来源才可以访问。比如A网站有一张图片或音频等资源被B网站直接通过img等标签属性引入使用&#xff0c;这样就是B网站盗用了A网站的资源。那么对于A网站来说&#xff0c;流量怎么被消耗的都不知道。 解决思路&#xff1a; 判断http…

Nginx防盗链的配置

Nginx防盗链的配置 通常站点&#xff0c;都会想让自己网站的视频和图片&#xff0c;免被盗用&#xff0c;毕竟视频流量&#xff0c;花的都是白花花银子   首先我们没有配置防盗链的情况下&#xff0c;放开静态资源你的访问。我们来看看效果 location ~* .*\.(gif|jpg|ico|pn…

python爬虫的防盗链

文章目录 前言一、防盗链是什么&#xff1f;二、 防盗链如何实现三、分析四、 对有防盗链的网站进行爬取对有视频连接的网站发出请求并且获取源码信息提取出我们的视频网站对我们提取的网址进行修改&#xff0c;和拼凑下载视频结束爬取 完整代码 前言 随着python的发展网页的反…

Nginx静态资源防盗链

1.什么是资源盗链 简单地说&#xff0c;就是将别人的资源用到自己的页面展示给用户。 2.效果演示 1&#xff09;准备图片 这两张图片直接在浏览器中访问都是可以打开的。 github图片地址&#xff1a;https://github.githubassets.com/images/modules/site/home-campaign/her…

取消文件服务器防盗链,如何取消防盗链保护

http标准协议中有专门的字段记录referer 一来可以追溯上一个入站地址是什么 二来对于资源文件&#xff0c;可以跟踪到包含显示他的网页地址是什么。 因此所有防盗链方法都是基于这个Referer字段 网上比较多的2种 一种是使用apache文件FileMatch限制&#xff0c;在httpd.conf中增…

视频防盗链

解析器链接&#xff1a; https://www.administratorw.com/index/qqvod.php?url 清晰度高url后面支持mp4、m3u8地址 https://z1.m1907.cn?jx 清晰度底&#xff0c;链接后面只支持电影名 此接口解析出来的m3u8地址为&#xff1a;&#xff08;雄狮少年&#xff09; https…

html 图片防盗链,【反防盗链】介绍一个对付图片防盗链的方法

悲催的声明: 由于腾讯也采用了防盗链技术,本文方法已经失效了! 当我们想在文章里引用某张图片时,如果对方设置了防盗链,我们看到的将是404或forbidden或其他图片,而不是想要的那张图片,为此,我们有无方法进行“反防盗链”呢?答案是有的,本文将介绍一个对付图片防盗链…

简单的视频防盗链

1.使用hls.js播放视频&#xff0c;页面中无法获得视频的src hls.js是视频播放的工具文件&#xff0c;在官网上有播放方式&#xff0c;可以产生如上图所示的效果&#xff0c;没有source标签&#xff0c;也就是说&#xff0c;在页面上隐藏掉了视频的url hls.js文件地址&#xff…