1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Java实现扫雷小游戏

Java实现扫雷小游戏

时间:2022-11-15 19:50:00

相关推荐

Java实现扫雷小游戏

借鉴帖子链接

/qq_41061352/article/details/90766855

游戏规则:在有限的时间内,用鼠标右键把可能是地雷的方块插上旗子

笑脸左手边是剩余时间,右手边是剩余旗子数,点击笑脸可以重新开始

左上角的级别可以选择不同的难度,目前有初中高三个等级,炸弹不多,都非常的简单

如果觉得实在是太简单了,代码中已经把方法改成公共方法了,只需要修改几个参数就可以任意调整难度

参数由上->下:当前等级/倒计时时间/炸弹数 和 旗子数/行数/列数

👇

首先,需要绘制游戏的框架

新建Boom类,继承JFrame

public class Boom extends JFrame

设置窗口名字

//游戏名字private final static String gameName = "Boom";//名字setTitle(gameName);

获取电脑尺寸,将窗口定位到屏幕中央

//获取电脑窗口信息private final static Dimension window = Toolkit.getDefaultToolkit().getScreenSize();//程序窗口宽度private static int boxW = 220;//程序窗口高度private static int boxH = 300;//获取当前电脑窗口的宽和高int windowWidth = (int)window.getWidth();int windowHeight = (int)window.getHeight();//窗口在中间显示setBounds(windowWidth/2 - boxW/2,windowHeight/2 - boxH/2,boxW,boxH);

绘制笑脸

private static JButton bt;//笑脸图标的宽度private final static int faceW = 30;//绘制重置按钮bt = new JButton(face);bt.setBounds( boxW/2-faceW/2,10,faceW,faceW);

绘制倒计时和旗子数

//提示文字private static JLabel label1,label2;//绘制倒计时label1 = new JLabel("时间:" + countdown);label1.setBounds(25,15,80,20);//显示旗子数label2 = new JLabel("剩余:"+mineNum);label2.setBounds(boxW-80,15,80,20);

👇

第二大步,绘制雷区

新建GamePanel类,继承JPanel

首先定义每个方格的参数

private JLabel[][] label;private boolean[][] state;private Btn[][] btns;private byte[][] click;label = new JLabel[rows][cols];//用于存储是否有地雷state = new boolean[rows][cols];btns = new Btn[rows][cols];//用于存储按钮点击状态(0-未点击,1-已点击,2-未点击但周围有雷,3-插旗)click = new byte[rows][cols];

接着绘制底层小方格

public void initLabel() {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {JLabel l = new JLabel("", JLabel.CENTER);// 设置每个小方格的边界l.setBounds(j * BLOCK_WIDTH, i * BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);// 绘制方格边框l.setBorder(BorderFactory.createLineBorder(Color.GRAY));// 设置方格为透明,便于我们填充颜色l.setOpaque(true);// 背景填充为黄色l.setBackground(Color.yellow);// 将方格加入到容器中(即面板JPanel)this.add(l);// 将方格存到类变量中,方便公用label[i][j] = l;label[i][j].setVisible(false);}}}

然后随机生成地雷

//绘制地雷private void randomBomb() {for (int i = 0; i < bombCount;) {int rRow = (int) (Math.random() * rows);int rCol = (int) (Math.random() * cols);if (state[rRow][rCol] == true){continue;} else {//有地雷的格子state为真state[rRow][rCol] = true;++i;}}}

地雷并没有在一开始画上去,只是修改了状态,当踩雷的时候,才会把地雷画上去

//显示雷区public void showBomb(){for (int r = 0;r < rows;r++){for(int c = 0;c < rows; c++){btns[r][c].setVisible(false);/* 隐藏label */label[r][c].setVisible(true);/* 显示按钮(这里只有隐藏了按钮才能显示按钮下面的label) */if (state[r][c]){label[r][c].setIcon(bomb);//如果是雷并且插旗子了if (click[r][c] == 3){grade++;}} else {//如果不是雷但是插旗子了if (click[r][c] == 3){label[r][c].setText(null);label[r][c].setIcon(boomError);}}}}}

接着,再画上数字和按钮

/*** 绘制数字和按钮*/private void writeNumberAndBtn(){for (int i = 0; i < rows; ++i) {for (int j = 0; j < cols; ++j) {writeNumber(i,j,rows,cols);randomBtn(i,j);}}}//绘制数字private void writeNumber(int i, int j, int rows, int cols) {if (!state[i][j]) {int bombCount = 0;/* 寻找以自己为中心的九个格子中的地雷数 */for (int r = -1; (r + i < rows) && (r < 2); ++r) {if (r + i < 0)continue;for (int c = -1; (c + j < cols) && (c < 2); ++c) {if (c + j < 0)continue;if (state[r + i][c + j])bombCount++;}}if (bombCount > 0) {click[i][j] = 2;label[i][j].setText(String.valueOf(bombCount));}}}//绘制按钮private void randomBtn(int i, int j) {Btn btn = new Btn();btn.i = i;btn.j = j;btn.setBounds(j * BLOCK_WIDTH, i * BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);this.add(btn);btns[i][j] = btn;btn.addMouseListener(new MouseAdapter() {public void mouseClicked(MouseEvent e) {//左键点击if(e.getButton() == MouseEvent.BUTTON1 && click[btn.i][btn.j] != 3)open(btn);//右键点击if(e.getButton() == MouseEvent.BUTTON3)placeFlag(btn);}});}

👇

基础的画完之后,就需要实现一些功能

👇比如插旗子

// 插旗private void placeFlag(Btn b){byte clickClick = click[b.i][b.j];String text = label[b.i][b.j].getText();//只能插和地雷数相同数目的旗子if(flagNum>0){//插过旗的,再点一次取消if(clickClick == 3){if(!"".equals(text) && "0".equals(text))click[b.i][b.j] = 2;elseclick[b.i][b.j] = 0;b.setIcon(lucency);Boom.setMineNum(++flagNum);}else {//未插旗的,插旗b.setIcon(flag);click[b.i][b.j] = 3;Boom.setMineNum(--flagNum);}if(flagNum == 0){boolean flagstate = false;for(int i = 0;i < rows; ++i){for(int j = 0;j < rows; ++j){if (click[i][j] != 3 && state[i][j])flagstate = true;}}if(!flagstate){//停止倒计时Boom.stopCountDown();JOptionPane.showMessageDialog(null,"您成功了! 得分:"+bombCount,"游戏结束",JOptionPane.PLAIN_MESSAGE);}}} else if(clickClick == 3){//棋子用完了之后取消if(!"".equals(text) && "0".equals(text))click[b.i][b.j] = 2;elseclick[b.i][b.j] = 0;b.setIcon(lucency);Boom.setMineNum(++flagNum);} else {// 旗子用完了,不能插JOptionPane.showMessageDialog(null,"标记已用尽","错误操作",JOptionPane.PLAIN_MESSAGE);}}

👇点击空白区域,把周边的空白区域也打开

// 递归打开周边空白区域private void subOpen(Btn b){/* 有雷,不能打开 */if(state[b.i][b.j])return;/* 打开过的和插旗的,不用打开 */if(click[b.i][b.j] == 1 || click[b.i][b.j] == 3)return;/* 周围有雷的,只打开它 */if(click[b.i][b.j] == 2) {b.setVisible(false);label[b.i][b.j].setVisible(true);click[b.i][b.j] = 1;return;}/* 打开当前这个按钮 */b.setVisible(false);label[b.i][b.j].setVisible(true);click[b.i][b.j] = 1;/* 递归检测周边八个按钮 */for (int r = -1; (r + b.i < rows) && (r < 2); ++r) {if (r + b.i < 0) continue;for (int c = -1; (c + b.j < cols) && (c < 2); ++c) {if (c + b.j < 0) continue;if (r==0 && c==0) continue;Btn newBtn = btns[r + b.i][c + b.j];subOpen(newBtn);}}}

👇还有倒计时,才用的是新建线程的方式

static CountDown countDown; //倒计时线程static class CountDown extends Thread{public void run() {while (countdown > 0){try{if (!countStatus){break;}-- countdown;label1.setText("时间:" + countdown);sleep(1000);}catch (Exception e){e.printStackTrace();}}if(countdown <= 0) {gp.showBomb();JOptionPane.showMessageDialog(null,"时间已到,成功标记:"+GamePanel.getGrade(),"游戏结束",JOptionPane.PLAIN_MESSAGE);}countDown = null;}}

代码上传到码云了,需要的随时下载

/cy_name/boom

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。