我又来水博客了……把之前的库存发一发~

开发工具:IDEA
不到三百行代码即可开发一个简单的扫雷小游戏,只需掌握Java基础语法知识以及部分swing知识点即可~
运行效果如图:


项目中图片可自行从网络上寻找替换
想要原始项目压缩文件可私聊博主~
代码如下:
package Mine;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class Mine implements ActionListener{
JFrame frame = new JFrame();//JFrame设置初始界面
ImageIcon bannerIcon =new ImageIcon(getClass().getResource("banner.JPG"));//设置头部图片
ImageIcon guessIcon =new ImageIcon(getClass().getResource("guess.png"));
ImageIcon bombIcon =new ImageIcon(getClass().getResource("bomb.png"));
ImageIcon failIcon =new ImageIcon(getClass().getResource("fail.JPG"));
ImageIcon winIcon =new ImageIcon(getClass().getResource("win.JPG"));
ImageIcon win_flagIcon =new ImageIcon(getClass().getResource("win_flag.png"));
//扫雷基本数据结构
private final int row = 20;//行
private final int col = 20;//列
private final int[][] data = new int[row][col];//数据
JButton[][] btns = new JButton[row][col];//按钮的行列
private final int mineCount = 20;//雷的总数
private final int mineCode = -1;//雷的代码
private int unOpen = row * col;//未开
private int open = 0;//已开
private int second = 0;//设置初始时间
JButton bannerBtn = new JButton((bannerIcon));//JButton设置头部菜单栏并导入图片
JLabel label1 = new JLabel("待开启:"+ unOpen);//添加计时和已开待开
JLabel label2 = new JLabel("已开启:"+ open);
JLabel label3 = new JLabel("用时:"+ second + "s");//设置表头
Timer timer=new Timer(1000,this);//1000ms触发一次
//构造一个扫雷方法
public Mine(){
frame.setSize(700,800);//设置高和宽
frame.setResizable(false);//不能改变大小
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出
frame.setLayout(new BorderLayout());//设置界面布局
setHead();//设置头部
addMine();//添加雷
setButtons();//设置主界面
timer.start();//计时器第一次启动
frame.setVisible(true);//显示
}
//添加雷
private void addMine(){
Random rand = new Random();//随机布雷
for (int i = 0; i < mineCount;) {//不能i++,可能会重复,导致雷的数量变少
int r = rand.nextInt(row);
int c = rand.nextInt(col);
if (data[r][c] != mineCode){
data[r][c] = mineCode;
i++;//直到放满雷
}
}
//开始计算周边雷的数量
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (data[i][j]==mineCode)
continue;
int count =0;//无需判断i,j,不会越界,但要判断其他八种情况是否越界
if (i>0 && j>0 && data[i-1][j-1] == mineCode)
count++;
if (i>0 && data[i-1][j] == mineCode)
count++;
if (i>0 && j<19 && data[i-1][j+1] == mineCode)
count++;
if (j>0 && data[i][j-1] == mineCode)
count++;
if (j<19 && data[i][j+1] == mineCode)
count++;
if (i<19 && j>0 && data[i+1][j-1] == mineCode)
count++;
if (i<19 && data[i+1][j] == mineCode)
count++;
if (i<19 && j<19 && data[i+1][j+1] == mineCode)
count++;
data[i][j] = count;
}
}
}
//设置一个20*20的主界面的按钮
private void setButtons(){
Container con=new Container();//和panel类似,更加轻量化
con.setLayout(new GridLayout(row,col));
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
JButton btn=new JButton(guessIcon);//初始时按钮上用“?”图片
btn.setOpaque(true);//设置为不透明,否则按钮颜色无法显示
btn.setBackground(Color.orange);//设置按钮背景色
btn.addActionListener(this);
con.add(btn);
btns[i][j]=btn;
}
}
frame.add(con,BorderLayout.CENTER);
}
//设置顶部
private void setHead(){
JPanel panel=new JPanel(new GridBagLayout());//布局
//设置布局的代码
GridBagConstraints c1 = new GridBagConstraints(0,0,3,1,1.0,1.0,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0,0);
panel.add(bannerBtn, c1);
bannerBtn.addActionListener(this);//让此按钮点了之后有反应
label1.setOpaque(true);//设置透明度
label1.setBackground(Color.white);//背景色
label1.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));//灰边
label2.setOpaque(true);
label2.setBackground(Color.white);
label2.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
label3.setOpaque(true);
label3.setBackground(Color.white);
label3.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
bannerBtn.setOpaque(true);
bannerBtn.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
bannerBtn.setBackground(Color.white);
GridBagConstraints c2 = new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0,0);
panel.add(label1, c2);
GridBagConstraints c3 = new GridBagConstraints(1,1,1,1,1.0,1.0,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0,0);
panel.add(label2, c3);
GridBagConstraints c4 = new GridBagConstraints(2,1,1,1,1.0,1.0,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0,0);
panel.add(label3, c4);
frame.add(panel,BorderLayout.NORTH);//放到最上方
}
@Override//按钮动作方法
public void actionPerformed(ActionEvent e) {
if (e.getSource()instanceof Timer){//判断类型是否为Timer
second++;
label3.setText("用时:"+second+"s");
timer.start();//执行完一次启动一次时钟
return;
}
JButton btn=(JButton)e.getSource();//强制类型转换
if (btn.equals(bannerBtn)){
restart();
return;
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (btn.equals(btns[i][j])){
if (data[i][j]==mineCode){
lose();
}else {
openBlank(i, j);
checkWin();
}
return;
}
}
}
}
//游戏赢啦!!!
private void checkWin(){
int wincount=0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (btns[i][j].isEnabled()){
wincount++;
}
}
}
if (wincount==mineCount){//如果和类的数量相等就赢了
timer.stop();
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (btns[i][j].isEnabled()){
btns[i][j].setIcon(win_flagIcon);//把雷的图片换成小旗子
}
}
}
bannerBtn.setIcon(winIcon);
JOptionPane.showMessageDialog(frame,"你赢啦!!!\n请点击顶部图片重新开始","你赢了!",JOptionPane.PLAIN_MESSAGE);
}
}
//游戏输了…………
private void lose(){
timer.stop();
bannerBtn.setIcon(failIcon);
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (btns[i][j].isEnabled()){
JButton btn=btns[i][j];
if (data[i][j]==mineCode){
btns[i][j].setEnabled(false);
btns[i][j].setIcon(bombIcon);
btns[i][j].setDisabledIcon(bombIcon);
}else {
btn.setIcon(null);//先清空
btn.setEnabled(false);//点开之后不必再响应
btn.setOpaque(true);//设置为不透明
btn.setText(data[i][j]+"");
btn.setMargin(new Insets(0,0,0,0));//执行之前的操作后显示数字为...,经查询需要加上这条语句才能显示数字
}//踩雷后全部打开
}
}
}
JOptionPane.showMessageDialog(frame,"你GG了!!!\n请点击顶部图片重新开始","你死啦!!!",JOptionPane.PLAIN_MESSAGE);
}
//空格自动打开
private void openBlank(int i,int j){
JButton btn=btns[i][j];
if (!btn.isEnabled())//如果按钮已经被打开
return;//终止递归
btn.setIcon(null);//先清空
btn.setEnabled(false);//点开之后不必再响应
btn.setOpaque(true);//设置为不透明
btn.setBackground(Color.CYAN);//按钮色
btn.setText(data[i][j]+"");
btn.setMargin(new Insets(0,0,0,0));//执行之前的操作后显示数字为...,经查询需要加上这条语句
addOpenCount();//让上方表格动起来
if(data[i][j] == 0) {//如果周围有空格继续打开
if (i>0 && j>0 && data[i-1][j-1] >= 0)
openBlank(i-1, j-1);
if (i>0 && data[i-1][j] >= 0)
openBlank(i-1, j);
if (i>0 && j<19 && data[i-1][j+1] >= 0)
openBlank(i-1, j+1);
if (j>0 && data[i][j-1] >= 0)
openBlank(i, j-1);
if (j<19 && data[i][j+1] >= 0)
openBlank(i, j+1);
if (i<19 && j>0 && data[i+1][j-1] >= 0)
openBlank(i+1, j-1);
if (i<19 && data[i+1][j] >= 0)
openBlank(i+1, j);
if (i<19 && j<19 && data[i+1][j+1] >= 0)
openBlank(i+1, j+1);
}
}
//让上方的表格栏随着按钮的展开动起来
private void addOpenCount(){
open++;
unOpen--;
label1.setText("待开启:"+unOpen);
label2.setText("已开启:"+open);
}
//重新启动要数据清零,按钮恢复,时间重启
private void restart(){
//恢复数据和按钮
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
data[i][j]=0;
btns[i][j].setBackground(Color.orange);
btns[i][j].setEnabled(true);
btns[i][j].setText("");
btns[i][j].setIcon(guessIcon);
}
}
//顶部状态栏的恢复
unOpen=row*col;
open=0;
second=0;
label1.setText("待开启:"+unOpen);
label2.setText("已开启:"+open);
label3.setText("用时:"+second+"s");
bannerBtn.setIcon(bannerIcon);//标题图片恢复
addMine();
timer.start();
}
//main方法
public static void main(String[] args) {
new Mine();
}
}```
















