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

这篇具有很好参考价值的文章主要介绍了JAVA版扫雷游戏,清晰易懂,注释多。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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


开发环境

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


一、下载方法

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

二、运行效果展示

这张图是游戏刚开始的画面,重置以后也是这个画面
JAVA版扫雷游戏,清晰易懂,注释多
此图是写代码的过程调试用的画面,方便查找问题。
JAVA版扫雷游戏,清晰易懂,注释多

此图是运行过程中的图片
JAVA版扫雷游戏,清晰易懂,注释多
带有计时功能,游戏成功的条件是用完所有的旗,并且放在雷上面。
超时,或者用完旗以后,有旗子没在正确的位置上,或者踩到地雷,都会导致游戏失败。

三、代码部分

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() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				jf.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 {
		@Override
		public 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 stub
		mineNum = 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加1
									numbers++;
								}
							}
						}
					}
					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() {
					@Override
					public 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未false
						flag = 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 stub
		for (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
欢迎交流,共同进步。文章来源地址https://www.toymoban.com/news/detail-482942.html

到了这里,关于JAVA版扫雷游戏,清晰易懂,注释多的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 教你使用Java开发一款简单的扫雷小游戏 附实例代码

    相信很多小伙伴都知道也玩过扫雷游戏,本篇文章将和大家分享一篇关于如何使用Java来实现一款简单的扫雷小游戏,这有助于大家对于Java相关知识的学习有一定的参考价值,下面是详情内容。 学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识。 编写这个

    2024年02月08日
    浏览(31)
  • 详解 Modbus 通信协议(清晰易懂)

    已剪辑自: https://mp.weixin.qq.com/s/dvo1l1GgJ2DtIHnPK5E1tA 本文总结关于 Modbus 相关的知识,浅显易懂,旨在对 Modbus 有一个很直观的了解。如有错误,欢迎修改意见和建议。 什么是协议 在了解什么是Modbus之前,我们先来看下什么是协议。 协议是一个汉语词汇,读音为xié yì,意思是共

    2024年02月02日
    浏览(50)
  • 详解Modbus通信协议---清晰易懂

    本文旨在让您对Modbus有一个很直观的了解,总结关于Modbus相关的知识,非常适合初学的同学,同时如有错误,欢迎修改意见和建议,将在第一时间修改 什么是协议 在了解什么是Modbus之前,我们先来看下 什么是 协议 协议是一个汉语词汇,读音为xié yì,意思是 共同计议,协

    2024年02月03日
    浏览(29)
  • 2048小游戏 java版(代码+注释)

            一个纯纯小白,想写点什么,也想学习一下怎么在这里写东西,就简单的写个2048小游戏。写的不好,大佬就不用看了,希望和大家交流学习,有写的不好或有更好的建议也欢迎提出来。(需要用的可直接粘贴复制)(轻喷) 目录 游戏展示 讲解  代码        

    2024年02月09日
    浏览(34)
  • Android WebView:这是一份 详细 & 易懂的WebView学习攻略(含与JS交互

    Webview 的使用主要包括: Webview 类 及其 工具类( WebSettings 类、 WebViewClient 类、 WebChromeClient 类) 下面我将详细介绍上述4个使用类 使用方法 具体请看文章:Android开发:最全面、最易懂的Webview详解 在 Android WebView 的使用中,与前端 h5 页面交互的需求十分常见 Android 与 JS 通过

    2024年04月10日
    浏览(35)
  • 图论详解——Bellman-Ford(清晰易懂)

    开学第一周,晚上属实作业有点乱 于是就拖更了一周 今天我们来讲解一下图论最短路径算法中 最简单 最清晰易懂 同时时间复杂度最高的算法 它的时间复杂度能达到O(VE)(点的数量*边的数量) 在学习Bellman-Ford之前,你需要先学会链式前向星 大家可以上网或者其他途径自行

    2024年02月06日
    浏览(31)
  • 这是一篇入职3周.NET 实习开发的感悟

    开篇先吐槽一下吧! 首先吐槽的就是加班费的问题,公司加班费挺多,但是我是试用期(3个月)没有加班费,但是公司带我的组长特喜欢加班,老是问我加不加班,懂点人情的都会一起加班,虽然公司规定17.30下班,但是基本都是18.00才开始走人,然后加班一般都是8.00走,所

    2024年02月08日
    浏览(30)
  • 五子棋小游戏 java版(代码+详细注释)

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

    2024年02月07日
    浏览(37)
  • 详解Java实现2048小游戏(JavaFX,完整源码+注释说明)

    刚刚完成的一个小游戏,写文章记录一下,如果有任何错误或者可以改进的代码请提出 另一方面也是方便自己几个月或几年后忘记时,来这里翻一翻回顾思路 目录 基本界面: 类的组织: _CardPane: _CardMatrixPane: _CardColor: _GameMenuBar: _2048Demo: 基本思路: 卡片: 卡片矩阵:

    2024年02月03日
    浏览(39)
  • C++实现单链表【每一步详细深入讲解,代码清晰、简单、易懂】

    0、overview 链表元素由数据和指针构成,因此链表的节点可以由一个包含这两种元素的结构体代表: 链表包含插入、删除操作,而插入、删除又必须先查找元素是否存在,因此查找方法也必不可少。 1、插入操作 例如:我们需要在伪头节点(不包含数据)和含有1的节点之间插

    2024年02月08日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包