全文手敲代码,教你用Java实现扫雷小游戏

[复制链接]
查看3543 | 回复1 | 2022-12-14 15:42:51 | 显示全部楼层 |阅读模式
摘要:本程序共封装了五个类,分别是主类GameWin类,绘制底层地图和绘制顶层地图的类MapBottom类和MapTop类,绘制底层数字的类BottomNum类,以及初始化地雷的BottomRay类和工具GameUtil类,用于存静态参数和方法。/ w" w  ~4 T! j7 d7 _# f& F, r8 m
本文分享自华为云社区《Java实现扫雷小游戏【完整版】-云社区-华为云》,作者:橙子!。% I" o2 H! d3 {  ?
效果展示4 J; d! G% ~7 Y3 h, _4 Y, L

( o, }) Z8 L, h4 t, h, `
全文手敲代码,教你用Java实现扫雷小游戏-1.jpg
2 M& C/ v* [9 p/ u4 \
主类:GameWin类
  v1 q/ _: j1 z; v
) s5 i9 q& a7 S2 spackage com.sxt;import javax.swing.*;import java.awt.*;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;public class GameWin extends JFrame {    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 = new MapBottom();    MapTop mapTop = new MapTop();    void launch(){        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(new MouseAdapter() {            @Override            public void mouseClicked(MouseEvent e) {                super.mouseClicked(e);                switch (GameUtil.state){                    case 0 :                        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,任何时候都监听鼠标事件                    case 1 :                    case 2 :                        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();            }        }    }    @Override    public void paint(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);    }    public static void main(String[] args) {        GameWin gameWin = new GameWin();        gameWin.launch();    }}底层地图MapBottom类
* d6 n7 T6 s  J+ G7 b9 h
( _+ H+ M0 F  u  l1 D) @8 d" @//底层地图:绘制游戏相关组件package com.sxt;import java.awt.*;public class MapBottom {    BottomRay bottomRay = new BottomRay();    BottomNum bottomNum = new BottomNum();    {        bottomRay.newRay();        bottomNum.newNum();    }    //重置游戏    void reGame(){        for (int i = 1; i <=GameUtil.MAP_W ; i++) {            for (int j = 1; j <=GameUtil.MAP_H ; j++) {                GameUtil.DATA_BOTTOM[j]=0;            }        }        bottomRay.newRay();        bottomNum.newNum();    }     //绘制方法    void paintSelf(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[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[j] >=0) {                    g.drawImage(GameUtil.images[GameUtil.DATA_BOTTOM[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){            case 0:                GameUtil.END_TIME=System.currentTimeMillis();                g.drawImage(GameUtil.face,                        GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2),                        GameUtil.OFFSET,                        null);                break;            case 1:                g.drawImage(GameUtil.win,                        GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2),                        GameUtil.OFFSET,                        null);                break;            case 2:                g.drawImage(GameUtil.over,                        GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2),                        GameUtil.OFFSET,                        null);                break;            default:        }    }}顶层地图MapTop类5 v  s; ]( b4 P

2 r% K+ N6 w' K4 r) p顶层地图类:绘制顶层组件package com.sxt;import java.awt.*;public class MapTop {    //格子位置    int temp_x;    int temp_y;    //重置游戏    void reGame(){        for (int i = 1; i <=GameUtil.MAP_W ; i++) {            for (int j = 1; j <=GameUtil.MAP_H ; j++) {                GameUtil.DATA_TOP[j]=0;            }        }    }    //判断逻辑    void logic(){        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++;                }                //插旗则取消                else if(GameUtil.DATA_TOP[temp_x][temp_y]==1){                    GameUtil.DATA_TOP[temp_x][temp_y]=0;                    GameUtil.FLAG_NUM--;                }                else if(GameUtil.DATA_TOP[temp_x][temp_y]==-1){                    numOpen(temp_x,temp_y);                }                GameUtil.RIGHT=false;            }        }        boom();        victory();    }    //数字翻开    void numOpen(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[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[j]!=1){                            GameUtil.DATA_TOP[j]=-1;                        }                        //必须在雷区当中                        if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){                            spaceOpen(i,j);                        }                    }                }            }        }    }    //失败判定  t 表示失败 f 未失败    boolean boom(){        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[j]==0){                        GameUtil.DATA_TOP[j]=-1;                    }                }            }        }        for (int i = 1; i <=GameUtil.MAP_W ; i++) {            for (int j = 1; j <=GameUtil.MAP_H ; j++) {                if(GameUtil.DATA_BOTTOM[j]==-1&&GameUtil.DATA_TOP[j]==-1){                    GameUtil.state = 2;                    seeBoom();                    return true;                }            }        }        return false;    }    //失败显示    void seeBoom(){        for (int i = 1; i <=GameUtil.MAP_W ; i++) {            for (int j = 1; j <=GameUtil.MAP_H ; j++) {                //底层是雷,顶层不是旗,显示                if(GameUtil.DATA_BOTTOM[j]==-1&&GameUtil.DATA_TOP[j]!=1){                    GameUtil.DATA_TOP[j]=-1;                }                //底层不是雷,顶层是旗,显示差错旗                if(GameUtil.DATA_BOTTOM[j]!=-1&&GameUtil.DATA_TOP[j]==1){                    GameUtil.DATA_TOP[j]=2;                }            }        }    }    //胜利判断  t 表示胜利 f 未胜利    boolean victory(){        //统计未打开格子数        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[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[j]==0){                        GameUtil.DATA_TOP[j]=1;                    }                }            }            return true;        }        return false;    }    //打开空格    void spaceOpen(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[j]!=-1){                        if(GameUtil.DATA_TOP[j]==1){GameUtil.FLAG_NUM--;}                        GameUtil.DATA_TOP[j]=-1;                        //必须在雷区当中                        if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){                            spaceOpen(i,j);                        }                    }                }            }        }    }    //绘制方法    void paintSelf(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[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[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[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类
9 d+ }; |' I1 J* Y
8 w5 M; K9 Y- c% ]  V! X$ k//底层数字类package com.sxt;public class BottomNum {    void newNum() {        for (int i = 1; i <=GameUtil.MAP_W ; i++) {            for (int j = 1; j <=GameUtil.MAP_H ; j++) {                if(GameUtil.DATA_BOTTOM[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类( a3 w9 `+ w* N  s2 ^5 J

/ `: d% m( G. v9 ?8 t6 `' f7 }//初始化地雷类package com.sxt;public class BottomRay {    //存放坐标    int[] rays = new int[GameUtil.RAY_MAX*2];    //地雷坐标    int x,y;    //是否放置 T 表示可以放置 F 不可放置    boolean isPlace = true;    //生成雷    void newRay() {        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=x;                rays[i+1]=y;            }            isPlace = true;        }        for (int i = 0; i < GameUtil.RAY_MAX*2; i=i+2) {            GameUtil.DATA_BOTTOM[rays][rays[i+1]]=-1;        }    }}工具GameUtil类
! O8 B( S# C6 Z* ]4 o  M" R6 @# e4 U. p  e5 U! A5 U# I' ?. X4 q+ J
//工具类:存放静态参数,工具方法package com.sxt;import java.awt.*;public class GameUtil {    //地雷个数    static int RAY_MAX = 5;    //地图的宽    static int MAP_W = 11;    //地图的高    static int MAP_H = 11;    //雷区偏移量    static int OFFSET = 45;    //格子边长    static int SQUARE_LENGTH = 50;    //插旗数量    static int FLAG_NUM = 0;    //鼠标相关    //坐标    static int MOUSE_X;    static int MOUSE_Y;    //状态    static boolean LEFT = false;    static boolean RIGHT = false;    //游戏状态 0 表示游戏中 1 胜利 2 失败    static int state = 0;    //倒计时    static long START_TIME;    static long END_TIME;    //底层元素  -1 雷 0 空 1-8 表示对应数字    static int[][] DATA_BOTTOM = new int[MAP_W+2][MAP_H+2];    //顶层元素  -1 无覆盖 0 覆盖 1 插旗 2 差错旗    static int[][] DATA_TOP = new int[MAP_W+2][MAP_H+2];    //载入图片    static Image lei = Toolkit.getDefaultToolkit().getImage("imgs/lei.png");    static Image top = Toolkit.getDefaultToolkit().getImage("imgs/top.gif");    static Image flag = Toolkit.getDefaultToolkit().getImage("imgs/flag.gif");    static Image noflag = Toolkit.getDefaultToolkit().getImage("imgs/noflag.png");    static Image face = Toolkit.getDefaultToolkit().getImage("imgs/face.png");    static Image over = Toolkit.getDefaultToolkit().getImage("imgs/over.png");    static Image win = Toolkit.getDefaultToolkit().getImage("imgs/win.png");    static Image[] images = new Image[9];    static {        for (int i = 1; i <=8 ; i++) {            images = Toolkit.getDefaultToolkit().getImage("imgs/num/"+i+".png");        }    }    static void drawWord(Graphics g,String str,int x,int y,int size,Color color){        g.setColor(color);        g.setFont(new Font("仿宋",Font.BOLD,size));        g.drawString(str,x,y);    }}总结
, N( _; m3 f) Z* G0 {6 J- X: f+ s9 M' D( U7 j% @
在使用Java编写扫雷小游戏时遇到了很多问题,在解决问题时,确实对java的面向对象编程有了更加深入的理解。虽然GUI现在并没有很大的市场,甚至好多初学者已经放弃了学习GUI,但是利用GUI编程的过程对于培养编程兴趣,深入理解Java编程有很大的作用。' v% O8 f6 |5 F& Y
本程序共封装了五个类,分别是主类GameWin类,绘制底层地图和绘制顶层地图的类MapBottom类和MapTop类,绘制底层数字的类BottomNum类,以及初始化地雷的BottomRay类和工具GameUtil类,用于存静态参数和方法。
2 y* N; \* n' ]8 B5 \游戏的设计类似windows扫雷,用户在图形化用户界面内利用鼠标监听事件标记雷区,左上角表示剩余雷的数量,右上角动态显示使用的时间。用户可选择中间组件按钮重新游戏。为了解决程序窗口闪动的问题,本程序采用了双缓冲技术。/ J* B; {# @' V$ J- b3 P
程序的总体界面布局:
: x1 v, f; s$ [! e$ ?# |4 }6 u6 M0 x+ Q$ v6 P/ l
全文手敲代码,教你用Java实现扫雷小游戏-2.jpg

( i6 B2 O0 M4 @5 w) I. @项目结构:& {5 t2 R& ]# g' N. Z: Y& u( j
8 c5 p2 N, X) g) U2 e+ b9 j
全文手敲代码,教你用Java实现扫雷小游戏-3.jpg
  h# Z+ w$ D( ?$ @: |) A
程序测试:" k/ F5 i# x* M' w" a
) B1 e2 D3 E; f6 ?7 W3 D! M
全文手敲代码,教你用Java实现扫雷小游戏-4.jpg

5 a0 z8 h0 n7 Z请大家指正!3 U/ p; Q6 [5 o7 D+ k. F
点击下方,第一时间了解华为云新鲜技术~
/ T# V+ @% z6 U8 m, P. R华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云
辛集杨森辛f | 2022-12-15 03:20:01 | 显示全部楼层
有没有C#或者C++的啊
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

286

金钱

0

收听

0

听众
性别

新手上路

金钱
286 元