周末无聊,用Java写了一个扫雷程序。说起来,这应该是我上学的时候写的。写起来会更有趣。毕竟自己实现一个小游戏还是比较好玩的。说实话,扫雷程序里面最核心的东西只是在点击的时候触发更新数据的步骤。Swing已经过时了,但是很好玩,不会过时。不喜勿喷源码地址:https://github.com/Damaer/Gam...说说里面的设计:数据结构设计View和datashouldbeseparatedas尽可能多的点击在使用BFS扫描判断成功或失败时,在这个程序中设计了数据结构。为了方便,使用全局数据类Data来维护整个游戏的数据,直接设置为静态变量,即一次只能运行一个游戏窗口。否则会出现数据安全问题。(只是为了方便)有以下数据(部分代码):publicclassData{//游戏状态publicstaticStatusstatus=Status.LOADING;//雷区大小publicstaticintsize=16;//地雷数量publicstaticintnumOfMine=0;//表示是否有地雷,1:有,0没有publicstaticint[][]maps=null;//是否访问过publicstaticboolean[][]visited=null;//周围的地雷publicstaticint[][]nums=null;//是否标记publicstaticboolean[][]flags=null;//最后访问的块坐标publicstaticPointlastVisitedPoint=null;//困难模式privatestaticDifficultModeEnummode;...}需要维护的数据如下:游戏状态:是否开始、结束、成功、失败等。模式:简单、中等或困难,会影响自动生成地雷的数量。*16小方块地雷数量:与模式选择有关,是一个随机数,用于标识每个方块是否有地雷:最基础的数据,生成后需要同步更新此数据,以表明每个方块是否有地雷扫过:默认不扫每个方块周围的地雷数量:生成时同步计算结果。我不想每次点击都计算它。毕竟是不会更新的数据。一劳永逸,标记块是否被标记:我们在扫雷的时候用一个小旗子来标记块。表示这是一道雷。标记完所有地雷后,最后一次成功访问的方块坐标:这个可以不记录,但是为了展示爆炸效果,和其他地雷不一样,所以分别记录下视图和数据,尽量按照可能的一个原则是视图与数据或数据更改分离,以便于维护。我们知道Java是使用Swing来绘制图形界面的。这东西真的很难画。视图写起来比较复杂,但什么也画不出来。视图和数据的分离也是几乎所有框架的一个优秀特性。主要是方便维修。如果视图和数据混在一起,更新数据,还要操作视图,会很乱。(当然,我写的是粗略的版本,只是简单的区分。)在这个扫雷程序中,基本都是点击事件,触发数据变化。数据变化后调用视图刷新,视图渲染逻辑和数据变化逻辑分开维护。.每个小方块都添加了一个点击事件,Data.visit(x,y)是数据刷新,repaintBlocks()是刷新视图,具体代码就不放了,感兴趣的可以去Github上查看源码:newMouseListener(){@OverridepublicvoidmouseClicked(MouseEvente){if(Data.status==Status.GOING){intc=e.getButton();//获取按下的鼠标按钮Blockblock=(Block)e.getComponent();intx=block.getPoint_x();inty=block.getPoint_y();如果(c==MouseEvent.BUTTON1){Data.visit(x,y);}elseif(c==MouseEvent.BUTTON3){//推断是鼠标右键被按下if(!Data.visited[x][y]){Data.flags[x][y]=!Data.flags[x][y];}}}重新绘制块();}}对不起最重要的一点是,每个块中都有一个后台url没有被提取出来。这是变化的数据,不应该放在视图中:publicclassBlockextendsJPanel{privateintpoint_x;私人intpoint_y;privateStringbackgroundPath=ImgPath.DEFAULT;publicBlock(intx,inty){this.point_x=x;this.point_y=y;setBorder(BorderFactory.createEtchedBorder());}}重置块背景,需要居中,重绘,重写voidpaintComponent(Graphicsg)方法就够了:@OverrideprotectedvoidpaintComponent(Graphicsg){refreshBackground();网址url=getClass().getClassLoader().getResource(backgroundPath);ImageIconicon=newImageIcon(url);如果(backgroundPath.equals(ImgPath.DEFAULT)||backgroundPath.equals(ImgPath.FLAG)||backgroundPath.equals(String.format(ImgPath.NUM,0))){g.drawImage(icon.getImage(),0,0,getWidth(),getHeight(),这个);}else{intx=(int)(getWidth()*0.1);inty=(int)(getHeight()*0.15);G。画图e(icon.getImage(),x,y,getWidth()-2*x,getHeight()-2*y,这个);}}BFS扫描BFS,又称广度优先搜索,是扫雷的核心知识点,就是当你点击的时候,如果当前块为空,那么就会触发扫描周围的块,如果周围有块也为空,它会继续递归。我用的是广度优先搜索,意思是先放入队列,取出,然后判断是否为空,然后将周围的匹配块加入其中,逐一处理。重点,这就是为什么我们需要一个队列,我们??需要一个队列来保存遍历的顺序。publicstaticvoidvisit(intx,inty){lastVisitedPoint.x=x;lastVisitedPoint.y=y;if(maps[x][y]==1){status=Status.FAILED;//游戏绑定,暴露所有的雷}else{//点击的不是雷Queue
