好多年前写过简略的扫雷游戏,模拟windows的。
后来由于多次搬迁环境,弄丢了,遗憾不已啊。
于是趁着这两年还在编程的道路上,趁热再次编写了一次,同时也扩展了功能,更接近windows的扫雷。
此次重写是用java swing实现的(eclipse开发),考虑到各位看客可能大部分是android岗位,于是我着重注意了功能结构化的处理,使游戏核心算法与UI分离,使用回调交互,便于迁移到android环境。

本人对swing不是很熟练,一直以来用swing做项目的人很少,学习资料也少,所有的这些都是在网上现查现用的。各位看客不会没关系,都是jdk里面的api,跟android、winform都很像。

本文思路分以下几步骤讲解:
1、效果图和基本原理。
2、核心算法。
3、程序结构和部分重要函数。
4、demo源码下载。

一、效果图:

瞧瞧效果图,顶部是一个图片按钮,使用鼠标事件处理了按下、释放、点击时的图片效果。
中间部分用的是swing的GridLayout布局,跟android的GridLayout一样,除了部分用法不一样。

在某个格子上点击左键时,如果是雷,则输了。同时翻开所有的格子。
在某个格子上点击右键时,会标记为旗子;再点右键,变成问号,再点又还原。
已经点开了的格子上,点击右键无效。
如果点击的某个格子是空白的,则会递归摊开他周边所有不是雷的格子。
游戏结束时,点击顶部的小黄脸按钮,重新开始游戏。
以上部分,是主要功能描述。

二、核心算法:

其实啊,就是两个二维数组的对应关系,界面格子二维数组 <==> 程序后台格子状态二维数组。
1、先制造二维数组,然后随机生成一定数量的随机数(认为是雷,赋给对应的数组位置),要求在二维数组范围内。后台数据二维数组的每个元素,使用了一个对象,需要保存当前格子的好几种状态。

private void initButtons() {isClickComplete = true;if (buttonArr == null) {buttonArr = new JButton[mRowNums][mColumnNums];}for (int i = 0; i < mRowNums; i++) {for (int j = 0; j < mColumnNums; j++) {if (buttonArr[i][j] == null) {buttonArr[i][j] = new JButton();}setButtonImage(buttonArr[i][j], MineType.MINE_STATUS_BLANK);}}
}

JButton的二维数组,添加到GridLayout布局中。

// 初始化所有格子
private void resetOrCreateGrids(int rowNums, int columnNums) {if (beanArr == null) {beanArr = new MineBean[rowNums][columnNums];}for (int i = 0; i < beanArr.length; i++) {for (int j = 0; j < beanArr[i].length; j++) {if (beanArr[i][j] == null) {beanArr[i][j] = new MineBean();}beanArr[i][j].reset();}}
}
public class MineBean {public static int MINE_VALUE = 9;// 是雷子的格子值private boolean isClickOpen = false;// 是否左键点开了格子private int mineCount = 0;// 周围雷的个数标记值(如果是9,则为雷)private int imageStatus = MineType.MINE_STATUS_BLANK;// 未点开图片状态...
}

后台数据服务二维数组,每个元素使用一个类来存储数据。

public class MineType {public static final int MINE_STATUS_OPEN_0 = 0;// 周围8个格子中没有雷public static final int MINE_STATUS_OPEN_1 = 1;// 周围8个格子中有1个雷public static final int MINE_STATUS_OPEN_2 = 2;// 周围8个格子中有2个雷public static final int MINE_STATUS_OPEN_3 = 3;// 周围8个格子中有3个雷public static final int MINE_STATUS_OPEN_4 = 4;// 周围8个格子中有4个雷public static final int MINE_STATUS_OPEN_5 = 5;// 周围8个格子中有5个雷public static final int MINE_STATUS_OPEN_6 = 6;// 周围8个格子中有6个雷public static final int MINE_STATUS_OPEN_7 = 7;// 周围8个格子中有7个雷public static final int MINE_STATUS_OPEN_8 = 8;// 周围8个格子中有8个雷public static final int MINE_STATUS_OPEN_9 = 9;// 周围8个格子中有9个雷public static final int MINE_STATUS_BLANK = 10;// 默认格子图片public static final int MINE_STATUS_FLAG = 11;// 格子标记为旗子public static final int MINE_STATUS_UNKNOW = 12;// 格子标记为问号public static final int MINE_STATUS_MINE_CLICK = 13;// 点击了雷子时的图片public static final int MINE_STATUS_DEAD = 14;// 失败时,顶部按钮图片public static final int MINE_STATUS_MILE = 15;// 开始时,顶部按钮图片public static final int MINE_STATUS_WAIT = 16;// 等待时,顶部按钮图片public static final int MINE_STATUS_WIN = 17;// 胜利时,顶部按钮图片public static final int MINE_STATUS_LOGO = 18;// logo标记
}

格子需要显示的图片状态。有左键点击后需要显示的状态,有右键点击有需要显示的状态。

private ArrayList<Point> getAroundGrids(int i, int j) {if (beanArr == null) {return null;}// 取当前格子周围的8个点Point point1 = new Point((i - 1), (j - 1));Point point2 = new Point((i - 1), (j));Point point3 = new Point((i - 1), (j + 1));Point point4 = new Point((i), (j - 1));Point point5 = new Point((i), (j + 1));Point point6 = new Point((i + 1), (j - 1));Point point7 = new Point((i + 1), (j));Point point8 = new Point((i + 1), (j + 1));ArrayList<Point> aroundList = new ArrayList<>();aroundList.add(point1);aroundList.add(point2);aroundList.add(point3);aroundList.add(point4);aroundList.add(point5);aroundList.add(point6);aroundList.add(point7);aroundList.add(point8);for (int k = 0; k < aroundList.size(); k++) {Point pointTemp = aroundList.get(k);if (pointTemp.x < 0 || pointTemp.x >= beanArr.length || pointTemp.y < 0|| pointTemp.y >= beanArr[0].length) {// 越界aroundList.remove(k);k--;}}return aroundList;
}

这个方法是获取当前位置的周围8个格子算法。需要注意的是,靠边的格子再获取周围8个格子时,会包含越界的。在加入到集合中时,需要过滤越界的数据。
然后就不用再考虑[左上角、右上角、左下角、右下角,左边、上边、右边、下边、内部]等多种情况了。

2、循环后台数据二维数组,每循环一步,找到它周围的8个格子(过滤掉不在UI范围内的),统计雷子个数,然后给当前这个格子赋值(周围雷子数量值)。

3、最核心的算法:点一个空白格子时,会摊开一大片。这个其实很简单,每次点击一个格子时,显示对应的UI的同时,继续找到它周边的8个格子,然后循环递归调用当前函数。

public void leftClick(int i, int j) {if (beanArr == null || this.callBack == null || this.isGameOver) {return;}MineBean mineBean = getMineBean(i, j);if (mineBean == null) {return;}if (mineBean.isClickOpen()) {return;}mineBean.setClickOpen(true);if (unOpenMines < 0) {unOpenMines = 0;}unOpenMines--;if (mineBean.isMineNow()) {isGameOver = true;gameOver(i, j);return;}if (gameStartTime <= 0) {gameStartTime = System.currentTimeMillis();}if (this.callBack != null) {this.callBack.onLeftClick(mineBean, i, j);}checkWin();if (mineBean.getMineCount() == MineType.MINE_STATUS_OPEN_0) {// 递归摊开一片recursionAround(i, j);}
}private void recursionAround(int i, int j) {ArrayList<Point> list = getAroundGrids(i, j);for (int k = 0; k < list.size(); k++) {Point tempPoint = list.get(k);if (tempPoint == null) {continue;}MineBean mineBean = getMineBean(tempPoint.x, tempPoint.y);if (mineBean == null) {continue;}if (mineBean.isMineNow()) {continue;}if (mineBean.isClickOpen()) {continue;}leftClick(tempPoint.x, tempPoint.y);}
}

上面代码就是点击某个格子后,显示UI,同时处理递归摊开一片的算法。

4、UI点击格子时,提供横竖坐标,传递给算法工具类对象处理。算法函数中找到对应的数据位置,判断情况再回调给UI显示。避免UI与算法函数耦合度太高,难以移植。

public interface CallBack {void onInit();void onWin(long time);// 胜利void onGameOver();// 失败void onLeftClick(MineBean mineBean, int i, int j);void onRightClick(MineBean mineBean, int i, int j);
}

以上部分是核心算法描述。

三、程序结构和部分重要函数。

// 初始化随机雷子
private void makeRandomMines() {if (beanArr == null) {return;}int nowMines = 0;while (nowMines < mMineCount) {int i = random.nextInt(beanArr.length);int j = random.nextInt(beanArr[0].length);MineBean mineBean = beanArr[i][j];if (!mineBean.isMineNow()) {mineBean.setMineNow();nowMines++;}}
}// 计算格子周围雷子状态
private void initGridAroundStatus() {if (beanArr == null) {return;}for (int i = 0; i < beanArr.length; i++) {for (int j = 0; j < beanArr[i].length; j++) {MineBean mineBean = beanArr[i][j];if (mineBean.isMineNow()) {// 当前格子是雷continue;}// 取当前格子周围有效的格子集合ArrayList<Point> list = getAroundGrids(i, j);int mineCount = 0;Point tempPoint = null;MineBean tempBean = null;// 统计这些点是否是雷子for (int k = 0; k < list.size(); k++) {tempPoint = list.get(k);if (tempPoint == null) {continue;}tempBean = getMineBean(tempPoint.x, tempPoint.y);if (tempBean == null) {continue;}if (tempBean.isMineNow()) {mineCount++;}}mineBean.setMineCount(mineCount);}}
}

怎么判断输赢呢?

private void checkWin() {if (flagMines != unOpenMines) {return;}isGameOver = true;if (this.callBack != null) {this.callBack.onWin(System.currentTimeMillis() - gameStartTime);}
}

我弄了两个变量,flagMines被标记的旗子,unOpenMines未被点开的格子个数。如果两者相等,就是胜利了。如果点到了雷,就输了

核心算法和逻辑都已描述,可能说的不直观,如果没进入状态还是很难看明白的,慢慢领悟吧。

还好后面提供源码下载。欢迎留言批评。

http://download.csdn.net/detail/fesdgasdgasdg/9867460

Guthub:https://github.com/mengzhinan/MineGame

Java Swing扫雷游戏demo分享相关推荐

  1. 基于java的扫雷论文_毕业论文基于JAVA的扫雷游戏设计

    毕业论文基于JAVA的扫雷游戏设计 课 程 设 计 报 告 课程名称: 计算机技术综合课程设计 题 目: 基于JAVA语言的扫雷游戏设计 学 院: 信息工程 系: 计算机 专 业: 计算机科学与技术 ...

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

    这是一篇关于JAVA的扫雷游戏,所有的图片均用文字代替,代码可直接运行. 文章目录 开发环境 一.下载方法 二.运行效果展示 三.代码部分 1.代码如下 总结 开发环境 开发工具:eclipse202 ...

  3. 基于java的扫雷论文_毕业论文基于java的扫雷游戏的设计与实现.doc

    毕业论文基于java的扫雷游戏的设计与实现 JAVA程序设计A课程设计 题 目 基于JAVA的扫雷游戏的设计与实现 院 (系) 信息工程学院 专 业 班 级 计算机科学与技术(2)班 学 生 姓 名 ...

  4. JAVA实现扫雷游戏

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

  5. java制作扫雷游戏中埋雷的难点_Java 实现经典扫雷游戏

    最后一次更新于 2019/07/08 效果演示图 Java 实现经典扫雷游戏 本扫雷游戏有以下功能: 如果点中炸弹会显示炸弹. 玩家左键点击方块能显示该方块周围会出现几个炸弹,如果不存在炸弹的话扫描范 ...

  6. java swing实现图文混排_跟我学Java Swing之游戏设计(4)

    你有没有经历过装修?尽管它是件劳神费力的事,可现代人还是不遗余力地在装修上花尽心思.毕竟,在这个视觉支配感观的时代里,谁会嫌自己家太漂亮呢?今天,就让我们秉着精益求精的完美主义精神,在上次已经完成的游 ...

  7. java swing 小游戏 炸弹人

    java 炸弹人小游戏 用java swing写的炸弹人小游戏,学了一会java后写来练代码的,游戏资源为网上找的以及合作者画制 截图: 主界面: 地图编辑器: 一些说明: 机器人写了个状态机来控制, ...

  8. 基于java的扫雷游戏的设计

    扫雷游戏的基本功能:点击鼠标左键于未知区域,如果未知区域有雷,游戏停止,显示所有的地雷.如果没雷,则显示周围雷数,如果周围没雷,则再查看周围八个区域是否有雷直到有雷为止并显示,玩家需要尽快找出雷区中的 ...

  9. 基于java的扫雷游戏设计01

    开发工具eclipse,jdk1.7 扫雷:游戏说明 扫雷是一种具有迷惑性的对记忆和推理能力的简单测试,它是长久以来最受欢迎的 Windows 游戏之一. 游戏目标:找出空方块,同时避免触雷. 启动游 ...

最新文章

  1. ARCGIS中某字段递增赋值
  2. css-padding
  3. python pandas dataframe 转json_python-将嵌套的json转换为pandas dataframe
  4. 【MFC系列2】Win32项目转换为MFC项目
  5. Keep-Alive功能使客户端到服务器端的连接持续有效
  6. The Falling Leaves UVA - 699
  7. string.Empty和null三者的区别
  8. docker--删除container和image
  9. OpenLayers 3加载矢量地图源
  10. 四方位陈述RV系列蜗轮蜗杆减速机产品
  11. Node.js 静态web服务
  12. 计算机中year函数怎么使用,excel2010中YEAR函数的使用方法
  13. android电脑局域网传输方案,通过WiFi文件传输在Android和PC之间传输文件 | MOS86
  14. android 替换类
  15. 【Vegas原创】HP惠普笔记本重装系统无法引导无法进操作系统的终极解决方法
  16. 一键制作三维真实地形DEM
  17. ubuntu 登录界面卡死解决方法
  18. puppy linux安装到u盘分区,puppy linux如何安装?puppy linux安装到u盘方法
  19. 未配置appkey或配置错误,uniapp原生安卓插件开发
  20. 首届全球 Pulsar Hackathon 2021 结果宣布,全球 Top5 团队出炉!

热门文章

  1. Facebook联手纽约大学,要把核磁共振成像时间缩短10倍
  2. 油菜花王国(并查集)
  3. 画出计算机硬件系统结构图,一、计算机的硬件结构.ppt
  4. pandas计算excel两列的日期差
  5. 华为p10测试软件,华为p10内存测试软件
  6. 红色彼岸花计算机谱子,ceecceec
  7. To https://gitee.com/xxxx/gittest.git解决方案
  8. 计算机知识小口诀,字根表口诀怎么快速背-小学数学:一年级20以内加减法口诀表,附背诵技巧!...
  9. 微信小程序实战--仿知识星球(一)
  10. pdfjs转图片_Vue项目pdf(base64)转图片