0


java实现扫雷小游戏【完整版】

大家好,我是orangemilk_,哈哈,学习Java已经到一个阶段啦,今天我们使用GUI来写一个扫雷小游戏吧!


🌎文章目录

效果展示

在这里插入图片描述


主类:GameWin类

packagecom.sxt;importjavax.swing.*;importjava.awt.*;importjava.awt.event.MouseAdapter;importjava.awt.event.MouseEvent;publicclassGameWinextendsJFrame{int width =2*GameUtil.OFFSET +GameUtil.MAP_W *GameUtil.SQUARE_LENGTH;int height =4*GameUtil.OFFSET +GameUtil.MAP_H *GameUtil.SQUARE_LENGTH;Image offScreenImage =null;MapBottom mapBottom =newMapBottom();MapTop mapTop =newMapTop();voidlaunch(){GameUtil.START_TIME=System.currentTimeMillis();this.setVisible(true);this.setSize(width,height);this.setLocationRelativeTo(null);this.setTitle("Java扫雷小游戏");this.setDefaultCloseOperation(EXIT_ON_CLOSE);//鼠标事件this.addMouseListener(newMouseAdapter(){@OverridepublicvoidmouseClicked(MouseEvent e){super.mouseClicked(e);switch(GameUtil.state){case0:if(e.getButton()==1){GameUtil.MOUSE_X = e.getX();GameUtil.MOUSE_Y = e.getY();GameUtil.LEFT =true;}if(e.getButton()==3){GameUtil.MOUSE_X = e.getX();GameUtil.MOUSE_Y = e.getY();GameUtil.RIGHT =true;}//去掉break,任何时候都监听鼠标事件case1:case2:if(e.getButton()==1){if(e.getX()>GameUtil.OFFSET +GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2)&& e.getX()<GameUtil.OFFSET +GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2)+GameUtil.SQUARE_LENGTH
                                    && e.getY()>GameUtil.OFFSET
                                    && e.getY()<GameUtil.OFFSET+GameUtil.SQUARE_LENGTH){
                                mapBottom.reGame();
                                mapTop.reGame();GameUtil.FLAG_NUM=0;GameUtil.START_TIME=System.currentTimeMillis();GameUtil.state=0;}}break;default:}}});while(true){repaint();try{Thread.sleep(40);}catch(InterruptedException e){
                e.printStackTrace();}}}@Overridepublicvoidpaint(Graphics g){
        offScreenImage =this.createImage(width,height);Graphics gImage = offScreenImage.getGraphics();//设置背景颜色
        gImage.setColor(Color.lightGray);
        gImage.fillRect(0,0,width,height);

        mapBottom.paintSelf(gImage);
        mapTop.paintSelf(gImage);
        g.drawImage(offScreenImage,0,0,null);}publicstaticvoidmain(String[] args){GameWin gameWin =newGameWin();
        gameWin.launch();}}

底层地图MapBottom类

//底层地图:绘制游戏相关组件packagecom.sxt;importjava.awt.*;publicclassMapBottom{BottomRay bottomRay =newBottomRay();BottomNum bottomNum =newBottomNum();{
        bottomRay.newRay();
        bottomNum.newNum();}//重置游戏voidreGame(){for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){GameUtil.DATA_BOTTOM[i][j]=0;}}
        bottomRay.newRay();
        bottomNum.newNum();}//绘制方法voidpaintSelf(Graphics g){
        g.setColor(Color.BLACK);//画竖线for(int i =0; i <=GameUtil.MAP_W; i++){
            g.drawLine(GameUtil.OFFSET + i *GameUtil.SQUARE_LENGTH,3*GameUtil.OFFSET,GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH,3*GameUtil.OFFSET+GameUtil.MAP_H*GameUtil.SQUARE_LENGTH);}//画横线for(int i =0; i <=GameUtil.MAP_H; i++){
            g.drawLine(GameUtil.OFFSET,3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH,GameUtil.OFFSET+GameUtil.MAP_W*GameUtil.SQUARE_LENGTH,3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH);}for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H; j++){//雷if(GameUtil.DATA_BOTTOM[i][j]==-1){
                    g.drawImage(GameUtil.lei,GameUtil.OFFSET +(i -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.OFFSET *3+(j -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.SQUARE_LENGTH -2,GameUtil.SQUARE_LENGTH -2,null);}//数字if(GameUtil.DATA_BOTTOM[i][j]>=0){
                    g.drawImage(GameUtil.images[GameUtil.DATA_BOTTOM[i][j]],GameUtil.OFFSET +(i -1)*GameUtil.SQUARE_LENGTH +15,GameUtil.OFFSET *3+(j -1)*GameUtil.SQUARE_LENGTH +5,null);}}}//绘制数字,剩余雷数,倒计时GameUtil.drawWord(g,""+(GameUtil.RAY_MAX-GameUtil.FLAG_NUM),GameUtil.OFFSET,2*GameUtil.OFFSET,30,Color.red);GameUtil.drawWord(g,""+(GameUtil.END_TIME-GameUtil.START_TIME)/1000,GameUtil.OFFSET +GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W-1),2*GameUtil.OFFSET,30,Color.red);switch(GameUtil.state){case0:GameUtil.END_TIME=System.currentTimeMillis();
                g.drawImage(GameUtil.face,GameUtil.OFFSET +GameUtil.SQUARE_LENGTH *(GameUtil.MAP_W/2),GameUtil.OFFSET,null);break;case1:
                g.drawImage(GameUtil.win,GameUtil.OFFSET +GameUtil.SQUARE_LENGTH *(GameUtil.MAP_W/2),GameUtil.OFFSET,null);break;case2:
                g.drawImage(GameUtil.over,GameUtil.OFFSET +GameUtil.SQUARE_LENGTH *(GameUtil.MAP_W/2),GameUtil.OFFSET,null);break;default:}}}

顶层地图MapTop类

顶层地图类:绘制顶层组件
packagecom.sxt;importjava.awt.*;publicclassMapTop{//格子位置int temp_x;int temp_y;//重置游戏voidreGame(){for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){GameUtil.DATA_TOP[i][j]=0;}}}//判断逻辑voidlogic(){
        temp_x=0;
        temp_y=0;if(GameUtil.MOUSE_X>GameUtil.OFFSET &&GameUtil.MOUSE_Y>3*GameUtil.OFFSET){
            temp_x =(GameUtil.MOUSE_X -GameUtil.OFFSET)/GameUtil.SQUARE_LENGTH+1;
            temp_y =(GameUtil.MOUSE_Y -GameUtil.OFFSET *3)/GameUtil.SQUARE_LENGTH+1;}if(temp_x>=1&& temp_x<=GameUtil.MAP_W
                && temp_y>=1&& temp_y<=GameUtil.MAP_H){if(GameUtil.LEFT){//覆盖,则翻开if(GameUtil.DATA_TOP[temp_x][temp_y]==0){GameUtil.DATA_TOP[temp_x][temp_y]=-1;}spaceOpen(temp_x,temp_y);GameUtil.LEFT=false;}if(GameUtil.RIGHT){//覆盖则插旗if(GameUtil.DATA_TOP[temp_x][temp_y]==0){GameUtil.DATA_TOP[temp_x][temp_y]=1;GameUtil.FLAG_NUM++;}//插旗则取消elseif(GameUtil.DATA_TOP[temp_x][temp_y]==1){GameUtil.DATA_TOP[temp_x][temp_y]=0;GameUtil.FLAG_NUM--;}elseif(GameUtil.DATA_TOP[temp_x][temp_y]==-1){numOpen(temp_x,temp_y);}GameUtil.RIGHT=false;}}boom();victory();}//数字翻开voidnumOpen(int x,int y){//记录旗数int count=0;if(GameUtil.DATA_BOTTOM[x][y]>0){for(int i = x-1; i <=x+1; i++){for(int j = y-1; j <=y+1; j++){if(GameUtil.DATA_TOP[i][j]==1){
                        count++;}}}if(count==GameUtil.DATA_BOTTOM[x][y]){for(int i = x-1; i <=x+1; i++){for(int j = y-1; j <=y+1; j++){if(GameUtil.DATA_TOP[i][j]!=1){GameUtil.DATA_TOP[i][j]=-1;}//必须在雷区当中if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){spaceOpen(i,j);}}}}}}//失败判定  t 表示失败 f 未失败booleanboom(){if(GameUtil.FLAG_NUM==GameUtil.RAY_MAX){for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){if(GameUtil.DATA_TOP[i][j]==0){GameUtil.DATA_TOP[i][j]=-1;}}}}for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]==-1){GameUtil.state =2;seeBoom();returntrue;}}}returnfalse;}//失败显示voidseeBoom(){for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){//底层是雷,顶层不是旗,显示if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]!=1){GameUtil.DATA_TOP[i][j]=-1;}//底层不是雷,顶层是旗,显示差错旗if(GameUtil.DATA_BOTTOM[i][j]!=-1&&GameUtil.DATA_TOP[i][j]==1){GameUtil.DATA_TOP[i][j]=2;}}}}//胜利判断  t 表示胜利 f 未胜利booleanvictory(){//统计未打开格子数int count=0;for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){if(GameUtil.DATA_TOP[i][j]!=-1){
                    count++;}}}if(count==GameUtil.RAY_MAX){GameUtil.state=1;for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){//未翻开,变成旗if(GameUtil.DATA_TOP[i][j]==0){GameUtil.DATA_TOP[i][j]=1;}}}returntrue;}returnfalse;}//打开空格voidspaceOpen(int x,int y){if(GameUtil.DATA_BOTTOM[x][y]==0){for(int i = x-1; i <=x+1; i++){for(int j = y-1; j <=y+1; j++){//覆盖,才递归if(GameUtil.DATA_TOP[i][j]!=-1){if(GameUtil.DATA_TOP[i][j]==1){GameUtil.FLAG_NUM--;}GameUtil.DATA_TOP[i][j]=-1;//必须在雷区当中if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){spaceOpen(i,j);}}}}}}//绘制方法voidpaintSelf(Graphics g){logic();for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H; j++){//覆盖if(GameUtil.DATA_TOP[i][j]==0){
                    g.drawImage(GameUtil.top,GameUtil.OFFSET +(i -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.OFFSET *3+(j -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.SQUARE_LENGTH -2,GameUtil.SQUARE_LENGTH -2,null);}//插旗if(GameUtil.DATA_TOP[i][j]==1){
                    g.drawImage(GameUtil.flag,GameUtil.OFFSET +(i -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.OFFSET *3+(j -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.SQUARE_LENGTH -2,GameUtil.SQUARE_LENGTH -2,null);}//差错旗if(GameUtil.DATA_TOP[i][j]==2){
                    g.drawImage(GameUtil.noflag,GameUtil.OFFSET +(i -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.OFFSET *3+(j -1)*GameUtil.SQUARE_LENGTH +1,GameUtil.SQUARE_LENGTH -2,GameUtil.SQUARE_LENGTH -2,null);}}}}}

底层数字BottomNum类

//底层数字类packagecom.sxt;publicclassBottomNum{voidnewNum(){for(int i =1; i <=GameUtil.MAP_W ; i++){for(int j =1; j <=GameUtil.MAP_H ; j++){if(GameUtil.DATA_BOTTOM[i][j]==-1){for(int k = i-1; k <=i+1; k++){for(int l = j-1; l <=j+1; l++){if(GameUtil.DATA_BOTTOM[k][l]>=0){GameUtil.DATA_BOTTOM[k][l]++;}}}}}}}}

初始化地雷BottomRay类

//初始化地雷类packagecom.sxt;publicclassBottomRay{//存放坐标int[] rays =newint[GameUtil.RAY_MAX*2];//地雷坐标int x,y;//是否放置 T 表示可以放置 F 不可放置boolean isPlace =true;//生成雷voidnewRay(){for(int i =0; i <GameUtil.RAY_MAX*2; i=i+2){
            x=(int)(Math.random()*GameUtil.MAP_W +1);//1-12
            y=(int)(Math.random()*GameUtil.MAP_H +1);//1-12//判断坐标是否存在for(int j =0; j < i ; j=j+2){if(x==rays[j]&& y==rays[j+1]){
                    i=i-2;
                    isPlace =false;break;}}//将坐标放入数组if(isPlace){
                rays[i]=x;
                rays[i+1]=y;}
            isPlace =true;}for(int i =0; i <GameUtil.RAY_MAX*2; i=i+2){GameUtil.DATA_BOTTOM[rays[i]][rays[i+1]]=-1;}}}

工具GameUtil类

//工具类:存放静态参数,工具方法packagecom.sxt;importjava.awt.*;publicclassGameUtil{//地雷个数staticint RAY_MAX =5;//地图的宽staticint MAP_W =11;//地图的高staticint MAP_H =11;//雷区偏移量staticint OFFSET =45;//格子边长staticint SQUARE_LENGTH =50;//插旗数量staticint FLAG_NUM =0;//鼠标相关//坐标staticint MOUSE_X;staticint MOUSE_Y;//状态staticboolean LEFT =false;staticboolean RIGHT =false;//游戏状态 0 表示游戏中 1 胜利 2 失败staticint state =0;//倒计时staticlong START_TIME;staticlong END_TIME;//底层元素  -1 雷 0 空 1-8 表示对应数字staticint[][] DATA_BOTTOM =newint[MAP_W+2][MAP_H+2];//顶层元素  -1 无覆盖 0 覆盖 1 插旗 2 差错旗staticint[][] DATA_TOP =newint[MAP_W+2][MAP_H+2];//载入图片staticImage lei =Toolkit.getDefaultToolkit().getImage("imgs/lei.png");staticImage top =Toolkit.getDefaultToolkit().getImage("imgs/top.gif");staticImage flag =Toolkit.getDefaultToolkit().getImage("imgs/flag.gif");staticImage noflag =Toolkit.getDefaultToolkit().getImage("imgs/noflag.png");staticImage face =Toolkit.getDefaultToolkit().getImage("imgs/face.png");staticImage over =Toolkit.getDefaultToolkit().getImage("imgs/over.png");staticImage win =Toolkit.getDefaultToolkit().getImage("imgs/win.png");staticImage[] images =newImage[9];static{for(int i =1; i <=8; i++){
            images[i]=Toolkit.getDefaultToolkit().getImage("imgs/num/"+i+".png");}}staticvoiddrawWord(Graphics g,String str,int x,int y,int size,Color color){
        g.setColor(color);
        g.setFont(newFont("仿宋",Font.BOLD,size));
        g.drawString(str,x,y);}}

总结

在使用Java编写扫雷小游戏时遇到了很多问题,在解决问题时,确实对java的面向对象编程有了更加深入的理解。虽然GUI现在并没有很大的市场,甚至好多初学者已经放弃了学习GUI,但是利用GUI编程的过程对于培养编程兴趣,深入理解Java编程有很大的作用。

本程序共封装了五个类,分别是主类GameWin类,绘制底层地图和绘制顶层地图的类MapBottom类和MapTop类,绘制底层数字的类BottomNum类,以及初始化地雷的BottomRay类和工具GameUtil类,用于存静态参数和方法。

游戏的设计类似windows扫雷,用户在图形化用户界面内利用鼠标监听事件标记雷区,左上角表示剩余雷的数量,右上角动态显示使用的时间。用户可选择中间组件按钮重新游戏。

为了解决程序窗口闪动的问题,本程序采用了双缓冲技术。


程序的总体界面布局:
在这里插入图片描述


项目结构:
在这里插入图片描述


程序测试:

在这里插入图片描述


请大家指正!

标签: java 开发语言

本文转载自: https://blog.csdn.net/zhangxia_/article/details/124531040
版权归原作者 orangemilk_ 所有, 如有侵权,请联系我们删除。

“java实现扫雷小游戏【完整版】”的评论:

还没有评论