小编给大家分享一下如何使用Java开发扫雷游戏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
1.界面上可以点开的各种实际都是按钮,创建9行9列的二维数组,然后根据这个数组来创建JButton。
2.对应创建二维数组data,用来存取数据,0表示周围无雷,-1表示当前是雷,其他数字表示周围雷的数量。
3.对应创建二维数组state,用来存取按钮状态,0未打开,1 打开 2旗子 3 未知(控制显示对应的图标)
4.设置雷:随机行数 i 和列数 j,根据随机到 i、j 从二维数组data中取出对应的元素值,若值不为-1(不是雷),则将此元素data[i][j]设置为-1,若值是-1(已经是雷了),则跳过,不管是否跳过都进行递归,直到雷的数量达到设定的最大数量,跳出递归。
5.设置周围雷的数量:计算每个元素周围的雷数量(周围指的是 左上、上、右上、右、右下、下、左下、左 这8个位置),循环二维数组data,判断当前值不是-1,则需要计算周围雷的数量,等会细说。
6.有任一格子被揭开,则游戏开始并且计时,当格子被揭开的时候分3种情况
(1)格子是雷,执行爆炸动画,游戏结束。
(2)当前格子周围有雷,则仅仅打开此格子,对应显示周围雷数量的数字图片。
(3)当前格子不是雷且周围没有雷(data取到的元素值为0),则依次打开周围,并且被打开的周围元素也没有雷的情况下,继续打开(递归)。
7.右键可以进行插小旗、打问号等操作(对数组state进行的操作)。
//设置头部 private void setHeader() { Container container = new Container(); container.setLayout(new GridLayout(1, 3)); timeJLabel = new JLabel("时间:"+time,JLabel.CENTER); timeJLabel.setForeground(Color.DARK_GRAY); timeJLabel.setFont(new Font("微软雅黑",Font.BOLD, 16)); leiJLabel = new JLabel("雷:"+curLeiCount,JLabel.CENTER); leiJLabel.setForeground(Color.DARK_GRAY); leiJLabel.setFont(new Font("微软雅黑",Font.BOLD, 16)); reStart = new JButton((ImageIcon)imageMap.get(21)); Dimension preferredSize = new Dimension(100,40); reStart.setPreferredSize(preferredSize); reStart.addActionListener(this); //注意添加顺序 container.add(timeJLabel); container.add(reStart); container.add(leiJLabel); mainFrame.add(container,BorderLayout.NORTH); }
1.创建容器,并采用GridLayout 布局。
2.根据设定的ROWS、COLS创建二维数组,数组存储JButton,给每个按钮设置图标。
3.给每个按钮添加鼠标点击事件,右键事件。
private void setButtons() { Container container = new Container(); container.setLayout(new GridLayout(ROWS, COLS)); ImageIcon icon=null; for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { JButton btn = new JButton(); btn.setBounds(0, 0, 39, 39); icon = (ImageIcon)imageMap.get(10); setBtnImage(btn,icon); container.add(btn); btns[i][j]=btn; btn.addActionListener(this); btn.addMouseListener(this); } } mainFrame.add(container,BorderLayout.CENTER); }
1.随机行数 i 和列数 j,根据随机到 i、j 从二维数组data中取出对应的元素值。
2.判断值,若值不为-1(不是雷),则将此元素data[i][j]设置为-1,若值是-1(已经是雷了),则跳过。
3.不管上一步是否跳过都进行递归,直到雷数量达到设定的最大数量,跳出递归。
private void setLei() { if(computedLeiCount==LEICOUNT){//如果达到雷的最大数量则跳出 return; } Random random = new Random(); int r = random.nextInt(ROWS); int c = random.nextInt(COLS); //0 无; -1表示雷 ; 其他表示周围的雷数量 if(data[r][c]!=-1){//如果不是雷则设置为雷 data[r][c]=-1; computedLeiCount++; } setLei();//递归调用 }
1.循环之前的二维数组data,元素值是-1(雷)跳过,不是-1则继续。
2.如果当前元素的下标是(i,j),则左上为(i-1,j-1),上为(i-1,j ),右上为(i-1,j+1),以此类推,如下图所示:
3.分别取出这8个元素,并判断他们是不是雷,如果是则计数累加,最后把这个计数赋值给元素data[i][j]。
//设置周围雷的数量 private void setAroundLei() { for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { if(data[i][j]!=-1){如果当前不是雷,则判断他周围有几个雷,并设置值 data[i][j] = computedLei(i,j); } } } } //计算周围雷的数量 private int computedLei(int i,int j) { int count=0; //左上 int ci = i-1; int cj = j-1; if(ci>=0 && cj>=0){ if(data[ci][cj]==-1){ count++; } } //上 ci = i-1; cj = j; if(ci>=0){ if(data[ci][cj]==-1){ count++; } } //右上 ci = i-1; cj = j+1; if(ci>=0 && cj<COLS){ if(data[ci][cj]==-1){ count++; } } //右 ci = i; cj = j+1; if(cj<COLS){ if(data[ci][cj]==-1){ count++; } } //右下 ci = i+1; cj = j+1; if(ci<ROWS && cj<COLS){ if(data[ci][cj]==-1){ count++; } } //下 ci = i+1; cj = j; if(ci<ROWS){ if(data[ci][cj]==-1){ count++; } } //左下 ci = i+1; cj = j-1; if(ci<ROWS && cj >=0){ if(data[ci][cj]==-1){ count++; } } //左 ci = i; cj = j-1; if(cj >= 0){ if(data[ci][cj]==-1){ count++; } } return count; }
1.让代码实现 ActionListener
2.重写方法actionPerformed,获取点击的按钮进行揭开操作(分3种情况):
(1)格子是雷,执行爆炸动画,游戏结束。
(2)当前格子周围有雷,则仅仅打开此格子,显示周围雷数量的数字图片。
(3)当前格子不是雷且周围没有雷(data取到的元素值为0),则依次打开周围,并且被打开的周围元素也没有雷的情况下,继续打开(递归)。
//打开指定的button private void open(int i,int j) { JButton button = btns[i][j]; if(state[i][j]==1){//已经打开直接返回 return ; } state[i][j]=1;//设置打开状态 int num = data[i][j]; if(num==-1){//直接使用雷的图片 setBtnImage(button,(ImageIcon)imageMap.get(18)); //游戏结束,并爆炸 boom(button); }else{//如果当前不是雷,显示对应数字类图片 if(num==0){ num=9; //显示周围的图标,并且递归 openAround(i,j); } setBtnImage(button,(ImageIcon)imageMap.get(num)); setBtnEnabled(button,false);//按钮被打开设置不能再点击了 //判定是否成功 successOrNot(1); } }
爆炸采用线程来执行,就是切换图片,图片切换到最后一张后线程结束,回调定义好的方法进行结束提示、打开所有格子等操作。
//爆炸效果 private void boom(JButton button) { flag=true; GameRunnable gameRunnable = new GameRunnable(); gameRunnable.setParam(button, boomImageMap,this); thread = new Thread(gameRunnable); thread.start(); } //爆炸回调方法 public void reback(JButton button) { setBtnImage(button,(ImageIcon)imageMap.get(18)); flag=false; //设置全部按钮打开 openAll(); //弹出结束提示 UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋体", Font.ITALIC, 13))); UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋体", Font.ITALIC, 13))); JOptionPane.showMessageDialog(mainFrame, "你失败了!点击上方按钮重新开始"); }
//打开周围 private void openAround(int i,int j) { //左上 int ci = i-1; int cj = j-1; if(ci>=0 && cj>=0){ open(ci,cj); } //上 ci = i-1; cj = j; if(ci>=0){ open(ci,cj); } //右上 ci = i-1; cj = j+1; if(ci>=0 && cj<COLS){ open(ci,cj); } //右 ci = i; cj = j+1; if(cj<COLS){ open(ci,cj); } //右下 ci = i+1; cj = j+1; if(ci<ROWS && cj<COLS){ open(ci,cj); } //下 ci = i+1; cj = j; if(ci<ROWS){ open(ci,cj); } //左下 ci = i+1; cj = j-1; if(ci<ROWS && cj >=0){ open(ci,cj); } //左 ci = i; cj = j-1; if(cj >= 0){ open(ci,cj); } }
1.实现MouseListener,重写mouseClicked方法。
2.如果按钮是未打开状态则设置为旗子(设置state数组对应的元素值:2)。
3.如果按钮是旗子状态则设置为未知(设置state数组对应的元素值:3)。
4.如果按钮是未知状态则设置为原来的状态未打开(设置state数组对应的元素值:0)。
//鼠标右键的处理 @Override public void mouseClicked(MouseEvent e) { if(e.getButton()==MouseEvent.BUTTON3){ JButton button = (JButton)e.getSource(); for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { if(button.equals(btns[i][j])){//找到对应的按钮 if(state[i][j]==0){//如果是未打开状态则设置为旗子 state[i][j]=2; setBtnImage(button,(ImageIcon)imageMap.get(12)); curLeiCount--; leiJLabel.setText("雷:"+curLeiCount); //需求判断是否成功 successOrNot(2); }else if(state[i][j]==2){//如果是旗子状态则设置为未知 state[i][j]=3; setBtnImage(button,(ImageIcon)imageMap.get(13)); curLeiCount++; leiJLabel.setText("雷:"+curLeiCount); }else if(state[i][j]==3){//如果是未知状态则设置为原来的未打开 state[i][j]=0; setBtnImage(button,(ImageIcon)imageMap.get(10)); } } } } } }
1.判断旗子的位置是不是正确的雷,并统计数量,如果统计到的数量刚好和设定的雷总数一样,证明雷全部被查出了,判定为胜利。
2.如果未打开的数量与设定雷的总数一样,也判定为胜利。
//判断是否成功 参数type=2表示判断右键插旗子,参数 type=其他 表示判断鼠标点击 private void successOrNot(int type) { int count=0; if(type==2){ /* * 1.判断旗子的位置是否是正确的雷,并统计数量 * 2.如果统计到的数量刚好和雷的总数一样,证明全部被查出了,判定为胜利 */ for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { if(state[i][j]==2 && data[i][j]==-1){//是旗子,也是雷,则计数 count++; } } } }else{ //最终的未打开的数量与雷的数量一样,则表示成功 for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { if(state[i][j]!=1){//未打开就计数 count++; } } } } if(count==LEICOUNT){//成功 //关闭计时线程 gameTimeRunnable.setFlag(false); //设置全部按钮打开 openAll(); //弹出结束提示 UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋体", Font.ITALIC, 13))); UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋体", Font.ITALIC, 13))); JOptionPane.showMessageDialog(mainFrame, "恭喜你获得了胜利!你太棒了"); } }
最后加入重新开始事件就完成了。
重新开始就是重新设置相关参数。
//重新开始游戏 private void restart() { //关闭计时线程(可能正在进行游戏,所以要把计时线程关闭) gameTimeRunnable.setFlag(false); startFlag=false; computedLeiCount=0; curLeiCount=10; leiJLabel.setText("雷:"+curLeiCount); time=0; timeJLabel.setText("时间:"+time); data= new int[ROWS][COLS];//存取数据 state= new int[ROWS][COLS];//存取打开状态,0未打开,1 打开 setLei(); setAroundLei(); ImageIcon icon = null; for (int i = 0; i <ROWS; i++) { for (int j = 0; j < COLS; j++) { icon = (ImageIcon)imageMap.get(10); setBtnImage(btns[i][j],icon); setBtnEnabled(btns[i][j],true);//按钮重新设置可以点击 } } }
1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;2. 面向对象;3. 分布性,Java是面向网络的语言;4. 鲁棒性,java提供自动垃圾收集来进行内存管理,防止程序员在管理内存时容易产生的错误。;5. 安全性,用于网络、分布环境下的Java必须防止病毒的入侵。6. 体系结构中立,只要安装了Java运行时系统,就可在任意处理器上运行。7. 可移植性,Java可以方便地移植到网络上的不同机器。8.解释执行,Java解释器直接对Java字节码进行解释执行。
以上是“如何使用Java开发扫雷游戏”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。