一文教你从零开始设计并实现一个Java扫雷游戏

游戏界面包括菜单栏,游戏数据显示区域以及雷区,当玩家点击雷区中的任意一格的时候游戏开始,雷区开始随机布雷,玩家需要在最短的时间内找出雷区中所有的地雷,并加以标识。

扫雷的基本操作包括鼠标左键单击和右键单击两种。其中左键用来点开玩家认为不是雷的格子,右键标记玩家认为是雷的格子。

左键单击:玩家在判断出该格子下没有雷时单击该格子,可以将该格子点开。如果该格子周围有雷就会显示周围雷的数目(由于周围最多只有8个格子,所以最多只能显示8);如果格子上什么也不显示(也就是为空),系统就会自动调用递归的方法打开附近的格子。如果点到了有地雷的格子,那么游戏结束,系统显示所有雷的位置。

右键单击:玩家可以通过使用鼠标右键单击来标记自己认为是雷的格子,通过标记可以有效的提高扫雷游戏的效率。再次右击该格子可以取消标记,且格子被标记的时候鼠标单击无效(防止玩家误操作导致游戏失败)。

(3)游戏计时

当点击雷区任意一个格子的时候雷区开始布雷同时计时开始,计时标准是一秒增加1。如果游戏失败时,则计时停止。如果玩家开始了新游戏,计时也会重新开始。

(4)标记地雷

当玩家认为格子下有雷时可以右击格子来标记该格子,被标记的格子显示小红旗。再次右击可以取消标记,且格子被标记的时候鼠标单击无效(防止玩家误操作导致游戏失败)。如果玩家标识的地雷的数量超过了该难度下规定的雷数,计数区会以负数来显示超过的雷数并且游戏不会结束。

(5)统计功能

当玩家游戏胜利后会弹框提示并可以输入玩家的名字,确认后本次游戏的记录会被保存。玩家可以点击菜单栏上的“游戏”菜单,再点击其中的“扫雷榜”即可查看游戏的最佳记录。

(6)退出

点击关闭按钮可以结束游戏。

2.4扫雷游戏界面需求

(1)游戏菜单

玩家有5项可以选择,玩家在点击初级时游戏界面的尺寸会变为初级的大小,雷区重新初始化,变为一共9*9的格子,其中有10颗是地雷;中级一共有16*16个格子,其中有40颗是地雷;高级一共有16*30个格子,其中有99颗是雷。除此之外,玩家还可以自定义难度,在弹框中填写雷数与尺寸。

玩家通过点击鼠标右键来标记自己认为是雷的格子,通过标记可以有效的提高扫雷游戏的效率,再次点击右键可以取消标记。

扫雷榜,记录玩家不同难度的最短时间。

(2)游戏区域

游戏区域由扫雷信息统计区和雷区组成,其中扫雷信息统计区又分为计数区、计时区、重新开始按钮。

雷区的雷数,每个难度对应的雷数都不同,初级、中级、高级分别对应10、40、99个雷。

计数区初始显示的雷数由难度而定,每次标记地雷雷数均减1,如果玩家标记的地雷的数量超过了该难度下规定的雷数,计数区会以负数显示超过的雷数。

当玩家点开第一个格子雷区开始布雷同时计时开始,一秒加1,直到游戏胜利或者游戏失败的时候停止计时。

2.5扫雷游戏功能模块

游戏在功能上分为6个模块:

(1) 游戏界面

(2) 布雷

(3) 鼠标事件

(4) 地雷判断

(5) 游戏胜利(结束)

3设计构想


如今世界上很多人都在使用Windows操作系统,所以人们也对系统自带的小游戏了如指掌。扫雷游戏的玩法简单,只要玩家进行一定的判断就可以轻松的游戏,所以玩扫雷的时候可以很轻松的玩。除了游戏本身带给人们的乐趣以外,游戏的玩法也在锻炼玩家的思维,如今大部分人都是依赖脑力劳动,这就可以通过在闲暇的时候玩玩扫雷来锻炼一下自己。所以就可以理解,为什么在各种电子产品上都搭载这个小游戏了。

虽然游戏比较简单,但是还是需要熟悉一下规则。

玩家需要在最短的时间内找出雷区中所有的地雷,并加以标识,其他没有雷的格子全部点开后游戏胜利。但是如果点到了地雷则游戏失败。

游戏的操作很简单,当玩家用鼠标左键点击自己认为不是地雷的格子会点开该格子,用鼠标右键点击格子会标记该格子,再次右击可以取消标记。玩家可以通过雷区中被点开的格子上显示的数字来判断该格子周围8个格子所隐藏的地雷,例如:点开的格子显示数字“2”,则表示该格子周边的8个格子里隐藏着2颗地雷。

如果点开的格子下没有雷且周围8个格子里也没有雷,则系统会自动点开那8个格子,然后递归判断这些格子周围有没有雷。

本次的扫雷游戏设计,需要编写7个Java类:MineaGamae.java类、MineAra.java类、Block.jaav类、BlockVaiw.java类、LayMinas.java类、Record.java类和ShowRecrd.java类。

(1)  MineGame.java

MineGame类是游戏的入口,用来初始化游戏资源,比如界面尺寸和雷数等。同时也负责难度的转换。

(2)  MineArea.java

MineArea类是布置雷区的雷,除了初始化雷区以外还可以响应玩家的鼠标操作。

(3)  Block.java

Block类是一个POJO类,主要记录了雷区一个个格子的属性,比如名字,周围雷的数目等等。

(4)  BlockView.java

BlockView类用来显示块的属性,并且使用卡片布局来使格子分为了上下两层,当玩家点击格子后,会使下面的属性浮现出来。

(5)  LayMines.java

LayMines类是计算不是雷的格周围雷个数的类,以及设置点选之后的图片样式。创建的对象lay是MineArea中最重要的成员。

(6)  Record.java

Record类是通过IO流将游戏记录储存在本地的文件中,主要实现通关后弹窗提示通关的窗口,以及记录成绩。

(7)  ShowRecord.java

ShowRecord类是显示扫雷记录的类。

3.1流程规划

有三个部分,分别是游戏选择难度后、玩家第一次点击格子和为不是地雷的格子自动点开。

游戏选择难度后,获取该难度设定的雷数与界面尺寸显示界面,但是还没有布雷。当玩家第一次点开格子的时候系统随机布雷并启动定时器,为什么要在点过一次格子之后才布雷呢?这就是要让玩家第一次不会点到地雷,要不然玩家该多郁闷,这样才能提高玩家的游戏欲。之后是最重要的一步,就是如何将格子周围没有雷的格子自动点开,我们可以使用递归的方法来巧妙的判断并点开周围的格子。

3.2界面规划

说明如下:

①:游戏主界面(Interface)。

②:菜单(Menu)。

③:地雷数显示区(MineNumberArea)

④:重新开始(Restart)。

⑤:扫雷用时显示区(TimeArea)。

⑥:地雷区(MineArea)。

3.3算法思想

(1)随机布雷

扫雷游戏要求在雷区随机布雷,雷数不能太多,这样就没法很好的判断周围是否有雷了;但也不能太少,这样会出现点一下就会点开一大片的空白区域。使用java自带的Math.random()方法产生随机数,经过计算后得到将随机数转换成一个整数,这个整数就是雷的位置的角标。游戏的目标是在将所有的地雷标记出来,并将其它不是雷的格子点开。

(2)计算方格周围雷数

当没有雷的格子被点击后,会显示该格子周围8个格子里所有的雷数,玩家通过这个数字就可以判断出雷的位置,所以周围雷数的计算也很重要。

4游戏的详细设计


4.1游戏初始化

玩家点开游戏,此时系统自动加载界面,分别是雷区、菜单区、扫雷数据显示区,

游戏界面相对计算机自带的扫雷游戏比较简洁,主要由游戏数据显示区域以及雷区构成。

我们使用ImageIcon对象来存放地雷的图标,可以图标大小最好要小一些,否则会在格子上显示不全。

对地雷区的初始化是很重要的,我们使用一个循环即可实现初始化。玩家点开游戏之后可以点击菜单栏选择扫雷游戏的难度,不同的难度就代表了不同的地雷总数和尺寸,自定义的难度也会设置雷数和尺寸,设置的这些数据全部存放在几个变量之中,当雷区要初始化的时候程序会调用这么变量属性,然后通过一个循环来完成初始化。主要代码如下:

而之前所说的循环初始化其实就是循环的加载组件,雷区就是由一个个组件构成的,通过循环将所有的格子都布置到雷区,然后再随机产生地雷并布置到雷区上。

组件位置的摆放是按照其在数组中的位置来摆放的,所有的格子组件都存放在一个二维数组之中,组件在这个数组中的下标就是他在布局中的位置。

菜单栏是由菜单组件构成的,也就是JMenu组件,这个是菜单组件,用来定义未点击时的菜单样式,这个组件有可以设置JMenauItem组件,这是菜单项的意思,是当玩家点击了菜单后展示出来的子菜单栏。

扫雷游戏的计时区以及计数区又是使用另一种组件完成的,叫做JTextField

,这个组件是文本显示的组件,在设置了不可编辑的属性后,该组件在显示的外观上会有变化,边框会变灰一些,意味着该组件不能够点击或者输入。然后使用一个方法随着时间动态的在时间区以一秒为单位增加,计数区则会随着用户标记雷而减一,可以减到负数。

在设置界面的时候还需要进行一些设置,比如设置属性来让玩家在关闭游戏窗口时,系统会自动释放资源,并关闭窗口。

4.2雷区的布置

当玩家第一次点开格子的时候系统随机布雷并启动定时器,但是为什么要在点过一次格子之后才布雷呢?原来这就是要让玩家第一次不会点到地雷,要不然玩家该多郁闷,这样才能提高玩家的游戏欲。具体实现如下所示:

判断地雷区是否处于可动作状态:

判断为左键且该格子为未探测状态:

布置地雷:

判断地雷应该被布置的位置:

4.3游戏中主要模块的介绍与使用

4.3.1鼠标事件

我们通过点击鼠标左键或者鼠标右键来完成游戏,使用系统自带的MouseDown和MouseUp事件来响应玩家的操作。

函数原型如下:

组件名称:

组件名称:

这两个原型中的参数,Button参数值分别表示玩家用鼠标的左键或者右键进行点击的。其意义如下:

1:左键      2:右键

如果同时按两个按键,那么系统就会传回3,因为点左键是1,点右键是2,一起点就是两个值相加了。

在本次的扫雷设计中,我们会用鼠标的MouseUp事件来响应玩家的操作,其中鼠标左键用来点开玩家认为没有雷的格子,鼠标右键用来标记玩家认为下面藏有雷的格子。使用MouseaUp事件而不用MouseaDown事件的原因是,前者是在当鼠标按键抬起是触发,而后者是当按键按下就触发。假如玩家在点击某一个格子的时候突然发现好像点错了,此时玩家只要继续按下鼠标右键,再抬起的时候就会发现格子被标记成地雷了,现在的游戏一般都有这个功能,这可以有效的提升玩家的游戏体验。

在人机交互的界面上,鼠标的操作是很重要的,但是程序的设计不合理会使鼠标无法发挥应有的功能。在鼠标点击事件中使用MouseUp来响应事件在上面也进行了解释,这样就可以很巧妙的让玩家体会到游戏的贴心之处,可以有效的提升玩家的游戏体验。

当鼠标左键点击格子时:

当鼠标右击标识有雷的格子时:

4.4地雷及雷区表面探测情况

在雷区的设计上,我使用循环加载组件的方法让雷区布满格子,如果玩家点击了格子就会让该格子下面隐藏的组件显示出来

玩家通过单击格子来点开格子,右击格子标记地雷。由于使用了两个数组记录地雷的位置以及被点开的信息,所以可以通过两层嵌套循环来判断该格子周围雷的数目,而且系统会点开该格子周围8个格子中没有雷的格子,这又需要用到递归调用来一直进行这个点开格子并验证的过程,直到不符合条件为止。利用这种嵌套循环以及递归调用,都会使一个耗时耗力的问题变得容易解决起来,使得代码结构也变得清晰明了,并且会提高系统的计算速度。

4.5清除未靠近地雷的格子

开始之前需要介绍并学习一下“递归”,递归的狭义解释就是一个方法调用自己本身,通过一个判断语句决定是否结束调用。在代码的设计上也是一种非常重要的代码结构,通过这种方法编写代码,会使得代码结构看起来相当简单明了。但是需要注意的是,如果操作不当会是系统无限循环调用,使得游戏崩溃,所以在编写代码时必须使用判断的语句来控制循环调用的结束,以停止该方法的递归调用。

当玩家在进行游戏时点击了任意一个格子,系统会检测周围8个格子下是否藏雷,如果雷都被标记或者没有雷就会被点开并循环调用继续判断被点开格子周围的雷数。

设计的时候需要考虑的判断条件:玩家点击了某一个格子后判断该格子下是否藏雷;如果没有雷则判断周围8个格的雷数并显示;若雷都被标记出来或者本来就没有雷则点开周围的格子递归判断被点开格子周围的雷。

由于递归是循环调用方法本身,所以需要一个判断语句来结束调用,当被点开的格子周围有雷时在格子上显示雷数并结束递归调用。

递归方法虽然很好但也有一些的缺点,除了结束条件的选取很重要外,如果在扫雷设计中将雷区的尺寸设置过大,而地雷数却很少的话会使的循环调用变慢。所以在游戏的玩法设计上也要小心谨慎,不可以胡乱定义,以免造成系统负担,使得游戏无法顺利进行下去。

代码部分如下所示

4.6游戏难度的选择

我设计的扫雷有在难度的选择上有三种难度,分别是初、中、高级,这三种难度定义的雷数和雷区的尺寸是固定的,假如玩家想要自己定义扫雷的难度可以自己设置雷数和尺寸,只要打开“自定义”配置弹窗,在之后的弹框里按提示输入雷数和尺寸,行数最大为24,列数最大为30,如果玩家设置的雷数超过了范围(比如雷数大于格子的总数或小于零),系统会默认雷数为行数减一与列数减一的乘积。

4.7菜单栏的功能

初级:设置格子总数为9*9,地雷总数为10颗雷,尺寸为300*380然后重新开始游戏。

中级:设置格子总数为16*16,地雷总数为40颗雷,尺寸为480*580然后重新开始游戏。

高级:设置格子总数为16*30,地雷总数为99颗雷,尺寸为800*500然后重新开始游戏。

自定义:设置格子总数为最大24*30,最多雷数为24*30的难度,然后重新开始游戏。

扫雷榜: 打开并显示时间最短的扫雷记录,可以进行更新和重新记分。

4.8游戏的判断

4.9游戏成功完成

游戏要求玩家在最短的时间内完成游戏,当玩家将所有的雷标记出来并且其它格子都点开以后游戏胜利,系统会弹出提示框告诉玩家“您真厉害,请输入您的名字,记录上榜!”,系统会记录玩家最短完成游戏的时间。

4.10游戏失败

如果玩家不幸点击到了有雷的格子,该格子的地雷会引爆其他的地雷,游戏失败,系统会将剩下的地雷全部显示出来,并弹框提示“你输了,请继续努力!”,玩家可以选择弹框上的重新开始游戏选项来开始一局新的游戏。

格子类的对象有一个标识该格子是否是雷的属性,通过该属性来判断玩家点到的是不是地雷。在游戏结束时也是通过该属性来判断哪些格子下有雷并显示出来。

具体代码如下所示:

5.类设计


5.1MineGame

MineGame类主要负责开始游戏,菜单的设计,以及难度的转换。展示该类的UML图

(1)成员变量

bar 是窗体的菜单栏变量。

fileMenu1 是扫雷游戏的菜单,叫做“游戏”。

fileMenu2 是扫雷的另一个菜单,叫做“帮助”。

初级 是扫雷游戏的难度变量。

中级 是扫雷游戏的难度变量。

高级 是扫雷游戏的难度变量。

扫雷榜 是扫雷的统计信息变量。

mineArea 是MineArea雷的对象,是设计雷区的变量。

file 是文件变量,用来读取扫雷记录。

hashtable 是用来临时存放扫雷记录。

showHeroRecord 是用来显示扫雷记录的变量。

(2)成员方法

MiwneGaame()通过该方法设置了游戏整体的位置和布局,并实现菜单栏功能,初始化统计信息。

actionPerformed(ActionEvent e)是响应点击菜单项的方法,通过该方法可以实现选择不同难度调整游戏的雷数和尺寸。玩家点选不同的菜单项会让该方法执行不同的操作。

main()方法是游戏开始的方法,通过new了一个MineGame的对象来实现游戏的开始。

5.2Block

Block类是一个POJO类,主要记录了雷区一个个格子的属性,比如名字,周围雷的数目等等。展示该类的UML图

(1)成员变量

Name是记录格子名字的变量。

isMine是标记格子下有无地雷的变量。

isMark是标记格子被标记状态的变量。

mineIcon记录了块的图标的变量。

isOpen是标记格子的点开状态的变量。

arounfdMinqeNmber是记录格子周围8个格子中雷的数量的变量。

(2)成员方法。

Block()无参构造方法,以防止创建错误参数的对象。

Block(String name,int aroundMineNumber,ImageIcon mineIcon,boolean isMine,boolean isMark,boolean isOpen)全参构造方法,可以为变量赋值。

setNamqe()方法可以设置块的名字。

getName()获取块的名字。

setAounMineNuber()方法可以设置块周围雷的数目。

setMineIicon()方法可以设置块的图标。

getMineIcon()获取块的图标。

setIsMinae()方法可以设置块是否是雷。

getAroundMineNumber()获取块周围雷的数目。

getIsMine()获取块是否是雷。

setIsMarek()方法可以设置块是否被标记。

getIsMark()获取块是否被标记。

setIsOpen(boolean p)设置块是否被挖开。

getIsOpen()获取块是否被挖开。

toString()以字符串的格式输出该对象。

5.3BlockView

BlockView类继承了JPanel类,主要布置每一个格子的布局,用来定义每个格子的属性。显示该类的UML图如图4-6所示。

(1)成员变量

blockeNameOrIcona 该变量用来显示格子的名字和图标属性。

blockeCoverq 是一个标记变量。

card 卡片式布局,显示第一次添加的组件。

(2)成员方法

BlockView()构造方法,初始化变量,设置块上属性显示的位置为居中,并添加组件。

giveView()方法,给每一个格子提供视图,如果该格子下有雷,会调用方法赋予该格子“地雷”的图标,但被覆盖在下面。如果下面没有雷,会显示该格子周围地雷的数目,同样会被覆盖住。该方法被调用时显示雷或者数字。

seeBlouckNamerOrIcon()方法是用来让块的属性显示出来。

seeBlouckCovear()方法是让cover遮盖块的属性。

getBlouckCovear()方法是得到用来遮盖的按钮。

5.4Record

Record类主要实现通关后弹窗提示通关的窗口,以及记录成绩。当玩家扫雷成功时,该对象提供了保存成绩到文件的界面。展示该类的UML图如图4-7所示。

(1)成员变量

time  用来给游戏计时。

grade  记录难度的变量。

key  表示一个判断的变量。

message  记录成绩的数据变量。

textName  一个文本显示组件。

label  一个可输入文本输入框组件。

确定,取消  两个按钮组件,一个代表确定,一个代表取消。

(2)成员方法

Record() 构造方法,初始化变量,设置窗口是否可以调整大小。

setGrade() 方法可以设置成绩。

writeRecord() 方法可以读写记录,如果没有记录会先创建一个新的文档来保存记录,下次直接修改覆盖记录。

setTime() 方法是用来设置时间的。

actionPerformed(ActionEvent e) 方法是响应鼠标的点击事件的方法,当玩家点击弹窗上的任意位置都会触发,但是只有点到正确的位置才会执行操作。比如点击确认,就可以把玩家的游戏记录存放到本地的文件中。

5.5ShowRecord

ShowRecord类是显示扫雷记录的类。展示该类的UML图如图4-8所示。

  1. 成员变量

file 记录成绩的文档。

name 名字。

hashtable 是记录成绩的变量。

show 是一个显示成绩的按钮组件变量。

Rescore 是一个初始分数的按钮组件变量。

Label1[] 显示成绩的组件。

Label2[] 显示成绩的组件。

Label3[] 显示成绩的组件。

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

  1. 成员变量

file 记录成绩的文档。

name 名字。

hashtable 是记录成绩的变量。

show 是一个显示成绩的按钮组件变量。

Rescore 是一个初始分数的按钮组件变量。

Label1[] 显示成绩的组件。

Label2[] 显示成绩的组件。

Label3[] 显示成绩的组件。

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-0wgKhMSO-1710854034114)]
[外链图片转存中…(img-ezIAWjAb-1710854034115)]
[外链图片转存中…(img-rGoU5AFw-1710854034115)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-7Nwm8p31-1710854034116)]

  • 17
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值