1.主类 package s1213扫雷6; //3.改变难度 关闭旧窗体,新建一个窗体,执行所有原来的代码 //7.菜单栏选项的时间,应该放在public void actionPerformed(ActionEvent e) 这个方法里面 //8尽量使用if+elseif 少用if+else 因为一旦情况发生改变,else很容易出现判断失误的情况 //10.每一次更改状态变量都要写上条件,因为以后更改程序,有可能发生条件变化,原代码就会出错!!! //12.打开和读取文件的功能 import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.*; public class Main1213 extends JFrame { int bombNum=30; //地雷数目 int nearBombNum[][]=new int[100][100]; //存储这个格子周围地雷的数目 int stackNum=0; //表示堆栈中有多少个元素,用作while循环的终止条件 Boolean isBomb[][]=new Boolean [50][50]; //存储格子是不是地雷,false(不是地雷),true(地雷) Mybutton button[][]=new Mybutton[100][100]; //Mybutton类型的数组,专门存放按钮,方便得到按钮的x,y参数(坐标参数) Stack a=new Stack(); //创建一个堆栈对象,用来开图 static Main1213 b=null; ImageIcon redFlagIcon=new ImageIcon("E:/Michael/javaImage/扫雷图片/1.jpg"); //红旗 ImageIcon clickIcon=new ImageIcon("E:/Michael/javaImage/扫雷图片/2.jpg"); //鼠标左键单击时的图标 ImageIcon InitialIcon=new ImageIcon("E:/Michael/javaImage/扫雷图片/3.png"); //初始图片 ImageIcon mouseOverIcon=new ImageIcon("E:/Michael/javaImage/扫雷图片/4.png"); //鼠标覆盖时的图标 ImageIcon bombIcon=new ImageIcon("E:/Michael/javaImage/扫雷图片/5.jpg"); //地雷的图标 //地雷数从1-8的对应图标,BombNumberPicture[0]对应图标地雷数为1,BombNumberPicture[7]对应图标地雷数为8 ImageIcon BombNumberPicture[]={ new ImageIcon("E:/Michael/javaImage/扫雷图片/6.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/7.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/8.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/9.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/10.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/11.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/12.jpg"), new ImageIcon("E:/Michael/javaImage/扫雷图片/13.jpg"),}; public static void main(String[] args) { b=new Main1213(); b.setBomb(); //布雷 b.Mymenu(); //添加菜单栏 b.init(); //setVisiable的位置很重要,a.Mymenu();a.init(); 顺序交换就看不到菜单栏了。 b.setButton(); //在界面中添加按钮和监听事件 } public void init() { this.setTitle("扫雷"); //设置窗体的标题 this.setLocationRelativeTo(null); //设置窗体出现位置居中 this.setDefaultCloseOperation(3); //设置窗体的关闭操作 this.setResizable(true); //设置禁止调整窗体的大小 this.setIconImage((new ImageIcon("E:/Michael/javaImage/扫雷图片/bomb.png").getImage()));//设置标题栏图标 this.setSize(430,500); //设置窗体的大小 this.setLocationRelativeTo(null); //设置窗体出现在屏幕中间 this.setLayout(new FlowLayout(FlowLayout.LEFT,0,0)); this.setVisible(true); } public void setButton() //绘制界面,鼠标对界面的操作事件(地雷格子) { //事件监听*************************************************************************************************** MouseListener mouseListener=new MouseListener() { public void mousePressed(MouseEvent e) { //右键点击******************************************************************** if(e.getButton()==MouseEvent.BUTTON3) { Mybutton btn = (Mybutton)e.getSource(); //得到事件源对象,并强制转型为Mybutton int flagAndBomb=0; if(btn.status==0) //如果该按钮状态为没翻转过 {btn.setIcon(redFlagIcon);btn.setStatus(4);} //改变图标为redFlagIcon,并设置为状态3(红旗) else if(btn.status==4) //如果该按钮状态为红旗 {btn.setIcon(InitialIcon);btn.setStatus(0);} //改变图标为InitialIcon(初始图标) else if(btn.status==1) //如果是已经翻开的图标 { int x=btn.x, y=btn.y; //x,y用来表示当前按钮的坐标 checkBomb(x, y); //如果标记的红旗下面不是地雷,那么游戏结束********************************* } //胜利判断************************** for(int i=0;i<20;i++) for(int j=0;j<20;j++) { if(isBomb[i][j]&&button[i][j].status==4) flagAndBomb++; } if(flagAndBomb==bombNum) { for(int i=0;i<20;i++) //判断胜利后开全图 for(int j=0;j<20;j++) {changeBombIcon(button[i][j]);} JOptionPane.showMessageDialog(null, "你胜利了");} //********************************** } //*************************************************************************** //左键点击******************************************************************** if(e.getButton()==MouseEvent.BUTTON1) { Mybutton btn = (Mybutton)e.getSource(); if(btn.status==0) { btn.setStatus(1); if(!isBomb[btn.x][btn.y]) //如果点击不是地雷 { findBomb(); //遍历地图,找到所有位置周围的地雷数目 showBomb(btn); //根据周围地雷数目,更换图标 } if(isBomb[btn.x][btn.y]) //如果鼠标点击是地雷 { for(int i=0;i<20;i++) //找到所有的地雷 for(int j=0;j<20;j++) { button[i][j].setStatus(1); //改变所有按钮的状态变量为1(翻转状态) if(isBomb[i][j]) button[i][j].setIcon(bombIcon);} //找到地雷并改变图标为bombIcon(地雷图标) JOptionPane.showMessageDialog(null, "游戏结束"); //弹出消息提示框,提示游戏结束 } } } //左键点击********************************************************************** } //计算点击处周围8个格子中的红旗数,保存在flag,用count来记录红旗和地雷的吻合数目 public void checkBomb(int x, int y) { int bomb=0,flag=0; for(int i=0;i<8;i++) { if(new Mybutton(getX(x,i),getY(y,i)).locationLegalJudge()) //边界判断 { if(button[getX(x,i)][getY(y,i)].status==3||button[getX(x,i)][getY(y,i)].status==4) { flag++; //如果格子状态表示红旗,那么红旗数目+1 if(isBomb[getX(x,i)][getY(y,i)]) {bomb++; } } } } //如果红旗和地雷吻合,则开图,不吻合就结束游戏,共2种情况*************************************** if(bomb==nearBombNum[x][y]) //如果周围雷数和判断一样 { for(int i=0;i<8;i++) //周围8个格子,每个格子判断一次 { if(new Mybutton(getX(x,i),getY(y,i)).locationLegalJudge()&&!isBomb[x][y]) //边界判断,而且不是地雷 { changeBombIcon(button[getX(x,i)][getY(y,i)]); //点击处左上角判断 if(nearBombNum[getX(x,i)][getY(y,i)]==0&&!isBomb[getX(x,i)][getY(y,i)]) showBomb(button[getX(x,i)][getY(y,i)]); } } } //如果红旗和地雷吻合,则开图,不吻合就结束游戏,共2种情况*************************************** //如果标记的红旗下面不是地雷,那么游戏结束********************************* if ((bomb!=nearBombNum[x][y]&&flag>=nearBombNum[x][y])) { for(int i=0;i<20;i++) //找到所有的地雷 for(int j=0;j<20;j++) { button[i][j].setStatus(1); //改变所有按钮的状态变量为1(翻转状态) if(isBomb[i][j]) button[i][j].setIcon(bombIcon);} //找到地雷并改变图标为bombIcon(地雷图标) JOptionPane.showMessageDialog(null, "游戏结束"); //弹出消息提示框,提示游戏结束 } } public void mouseEntered(MouseEvent e) { Mybutton btn=(Mybutton)e.getSource(); //要强制转型 if(btn.status==0) btn.setIcon(mouseOverIcon); //如果还没有翻转,那么改变按钮图案 } public void mouseExited(MouseEvent e) { Mybutton btn=(Mybutton)e.getSource(); //要强制转型,得到事件源 if(btn.status==0) btn.setIcon(InitialIcon); //如果按钮还未翻转,那么改变按钮图案 } public void mouseReleased(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} }; //******************************************************************************************************* //绘制游戏界面************************************************************************************************ for(int i=0;i<20;i++) //生成界面按钮20行20列 for(int j=0;j<20;j++) { Mybutton jb=new Mybutton(i,j); jb.setPreferredSize(new Dimension(20,20)); jb.addMouseListener(mouseListener); //要将new mouselistener的代码放到前面这行代码才不会出错 button[i][j]=jb; //通过这种方式就可以根据i,j唯一确定每个按钮 this.add(jb); //界面添加按钮 } JLabel jl = new JLabel(); //用来计时的标签 JLabel j2 = new JLabel("游戏计时:"); this.add(j2); this.add(jl); //计时功能********************************************* TimerTask task = new TimerTask() { int n=0; public void run() { jl.setText(""+n); n++;} //计时++ }; Timer timer = new Timer(); timer.schedule(task, 0, 1000); //计时功能********************************************* //绘制游戏界面************************************************************************************************ } public void setBomb() //布雷 { for(int i=0;i<20;i++) //遍历地图,将所有格子的地雷状态变量都初始化为0,0表示不是地雷 for(int j=0;j<20;j++) //遍历地图,将所有格子的地雷状态变量都初始化为0,0表示不是地雷 isBomb[i][j]=false; //遍历地图,将所有格子的地雷状态变量都初始化为0,0表示不是地雷 int n=0; while(n0) //深度优先遍历,先将所有空格加进去,再倒出来 { stackNum--;showBomb(a.pop());} } else changeBombIcon(btn); //如果点击的不是空格,那么直接改变按钮图案 } public void changeBombIcon(Mybutton btn) //根据周围地雷数,改变按钮图标 { int nearBombNumber=nearBombNum[btn.x][btn.y]; //k用来表示是按钮周围的地雷数 if(nearBombNumber==0){ btn.setIcon(mouseOverIcon); if(isBomb[btn.x][btn.y]) {btn.setIcon(redFlagIcon);btn.setStatus(3);} //如果是地雷,那么就改变图标 } else { btn.setIcon(BombNumberPicture[nearBombNumber-1]); btn.setStatus(1); } } //**************************************菜单栏*************************************************// public void Mymenu() { JMenu file,edit,help,nandu;//声明JMenu类对象 JMenuItem newgame,exit,copy,chuji,zhongji,gaoji,author,wanfa;//声明menuitem类对象 //初始菜单项 newgame=new JMenuItem("新游戏",new ImageIcon("C:/Users/Administrator/Desktop/images/2.jpg")); //创建menuItem对象 exit=new JMenuItem("关闭"){{b.dispose();}}; //创建menuItem对象 copy=new JMenuItem("保存战绩"){ //创建menuItem对象 { addActionListener( e->{ JFileChooser a=new JFileChooser(); //打开文件路径程序框 a.setDialogTitle("另存为"); a.showSaveDialog(null) ; //注意showSaveDialog和showOpenDialog的区别 }); }}; author=new JMenuItem("作者"){ //创建menuItem对象 { addActionListener( e->JOptionPane.showMessageDialog(null,"游戏作者:贺思源 制作时间:2014.12.13")); }}; wanfa=new JMenuItem("玩法"); //创建menuItem对象 chuji=new JMenuItem("初级"); //创建menuItem对象 zhongji=new JMenuItem("中级"); //创建menuItem对象 gaoji=new JMenuItem("高级"); //创建menuItem对象 nandu=new JMenu("难度"){{add(chuji);add(zhongji);add(gaoji);}}; //创建menuItem对象 help=new JMenu("帮助"){{add(author);add(wanfa); }}; //创建JMenu对象 file=new JMenu("游戏(G)"){{setMnemonic('G');add(newgame);add(nandu);addSeparator();add(exit);}}; //创建JMenu对象 edit=new JMenu("编辑"){{add(copy);}}; JMenuBar menubar=new JMenuBar(){{add(file);add(help);add(edit);}}; //创建menubar对象 chuji.addActionListener( e-> { this.dispose(); //关闭旧窗体 Main1213 s2=new Main1213(); s2.setbombNum(30); s2.setBomb(); //布雷 s2.Mymenu(); //添加菜单栏 s2.init(); //setVisiable的位置很重要,a.Mymenu();a.init(); 顺序交换就看不到菜单栏了。 s2.setButton(); //在界面中添加按钮和监听事件 }); zhongji.addActionListener( e-> { this.dispose(); //关闭旧窗体 Main1213 s2=new Main1213(); s2.setbombNum(60); s2.setBomb(); //布雷 s2.Mymenu(); //添加菜单栏 s2.init(); //setVisiable的位置很重要,a.Mymenu();a.init(); 顺序交换就看不到菜单栏了。 s2.setButton(); //在界面中添加按钮和监听事件 }); gaoji.addActionListener( e-> { this.dispose(); //关闭旧窗体 Main1213 s2=new Main1213(); s2.setbombNum(90); s2.setBomb(); //布雷 s2.Mymenu(); //添加菜单栏 s2.init(); //setVisiable的位置很重要,a.Mymenu();a.init(); 顺序交换就看不到菜单栏了。 s2.setButton(); //在界面中添加按钮和监听事件 }); exit.addActionListener(e-> this.dispose()); //关闭游戏 this.setJMenuBar(menubar); //设置menuBar } //********************************************************************************************// public void setbombNum(int x) //设置地雷数目 { bombNum=x;} public Mybutton getButton(int x,int y) { return button[x][y]; } //根据x坐标和index,得到周围第i个格子的x坐标 public int getX(int x,int index) { int xLocation[]={x-1,x,x+1,x-1,x+1,x-1,x,x+1,}; return xLocation[index]; } //根据y坐标和index,得到周围第i个格子的y坐标 public int getY(int y,int index) { int yLocation[]={y+1,y+1,y+1,y,y,y-1,y-1,y-1}; return yLocation[index]; } public int[][] getNearBombNum() { return nearBombNum; } public void setNearBombNum(int x,int y,int bombNumber) { nearBombNum[x][y]=bombNumber; } } 2.Mybutton类 package s1213扫雷6; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.border.EmptyBorder; public class Mybutton extends JButton { int status; // 0(未翻转),1(翻转),3(地雷),4(红旗) int x, y; ImageIcon i1 = new ImageIcon("E:/Michael/javaImage/扫雷图片/3.png"); // 初始图片 EmptyBorder o = new EmptyBorder(2, 2, 0, 0); // 生成按钮边界对象 Mybutton() { // 构造方法 this.setIcon(i1); // 给按钮添加图标 this.setBorder(o); // 改变按钮边界 } Mybutton(int x, int y) { // 调用本类构造方法 this(); this.x = x; this.y = y; } public boolean locationLegalJudge() { return this.x >= 0 && this.x <=19 && this.y >= 0 && this.y <=19; } public void setStatus(int x) // 改变按钮的状态变量方法 { this.status = x; } public int getStatus() { return status; } }