教你怎么用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进行的操作)。

三、代码实现

3.1 设置头部

//设置头部
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);
}

3.2 设置游戏区域按钮

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);
}

3.3 设置雷

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();//递归调用
}

3.4 计算周围雷的数量并显示

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;
}

3.5 添加点击事件

1.让代码实现 ActionListener

2.重写方法actionPerformed,获取点击的按钮进行揭开操作(分3种情况):

(1)格子是雷,执行爆炸动画,游戏结束。

(2)当前格子周围有雷,则仅仅打开此格子,显示周围雷数量的数字图片。

(3)当前格子不是雷且周围没有雷(data取到的元素值为0),则依次打开周围,并且被打开的周围元素也没有雷的情况下,继续打开(递归)。

3.6 打开指定按钮

//打开指定的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);
	}
}

3.7 触雷爆炸

爆炸采用线程来执行,就是切换图片,图片切换到最后一张后线程结束,回调定义好的方法进行结束提示、打开所有格子等操作。

//爆炸效果
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, "你失败了!点击上方按钮重新开始");
}

3.8 递归打开周围

//打开周围
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);
	}
}

3.9 鼠标右键事件

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);//按钮重新设置可以点击
		}
	}

}

到此这篇关于教你怎么用Java开发扫雷游戏的文章就介绍到这了,更多相关Java扫雷游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java实现扫雷游戏控制台版

    本文实例为大家分享了java实现扫雷游戏控制台版,供大家参考,具体内容如下 扫雷游戏 a.游戏的分析 在游戏中需要存在对象包含哪些. 格子对象(Grid): 属性:内容(content).状态(type) b.工程架构 设计工程包结构 bean:存放实体类 core:游戏核心类(游戏操作) test:扫雷玩的测试类 c.编写类 Grid(属性:content.type) Core类–游戏核心类(雷区创建.显示雷区.布雷.踩雷) Test类–测试类 d.核心类设计 1.格子对象创建方法定义 2.显

  • java swing实现的扫雷游戏及改进版完整示例

    本文实例讲述了java swing实现的扫雷游戏及改进版.分享给大家供大家参考,具体如下: 版本1: package awtDemo; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JButton; import jav

  • Java Swing实现扫雷小游戏

    swing设计扫雷心得,供大家参考,具体内容如下 最近学习swing学习之余做了一个小游戏:扫雷 1.前期设计 2.实现 其实完成这个游戏的核心就在于对数组的操纵,下面贴主要代码Main.java: package first; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; import java.awt.Image; import java.

  • 利用java开发简易版扫雷游戏

    1.简介 学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识. 2.编写过程 编写这个游戏,一共经历了三个阶段,编写了三个版本的游戏代码. 第一版:完成了扫雷游戏的基本雏形,实现了游戏的基本功能,游戏运行在cmd黑窗口中,以字符绘制游戏界面,无图形化窗口,通过控制台输入字符完成游戏控制.代码放置在一个java文件中,代码的可读性以及可扩展性都比较差. 第二版:在第一版实现基本功能的基础之上,对游戏代码进行重构,根据各部分的功能创建多个类,增加代码注释,提高代码的可读性以及可

  • java实现扫雷游戏

    初学Java,写了一个扫雷代码来锻炼一下自己的代码能力. 一.代码思路 代码思路很重要,如果事先就想好了代码思路,那么写这一个代码肯定是事半功倍,比在哪里瞎打要强不知道多少. 经过思考,觉得可以创建一个二维数组来记录情况 未翻开的牌:(统一显示 █ ) 数组的值 代表 -1 雷 0 旁边没有雷 1 旁边有一个雷 以此类推 翻开的牌则: if(a[x][y] == 9) System.out.print("?"); if(a[x][y] == 10) System.out.print(&

  • Java语言实现的扫雷游戏(1)

    Java类库中提供了用于GUI的swing开发工具包,我们可以利用swing设计出一些简单的经典小游戏,如扫雷,推箱子,俄罗斯方块等.接下来我就简单分享一下用Java设计扫雷游戏的思路与过程. 首先,我们要设计出扫雷的窗口界面,说白了,也就是在窗口上绘制出指定行数和列数的小方格.要在窗体上绘制方格,我们需要一个JPanel面板,所以我们定义类GamePanel让它继承自JPanel,然后我们在就可以这个类上绘制我们所要的信息了.然后,在类中,我们定义一些基本的变量,如行数,列数,雷的数量等等,方

  • java实现扫雷小游戏

    本文实例为大家分享了java实现扫雷小游戏的具体代码,供大家参考,具体内容如下 代码: package GUI; import java.util.Random; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.awt.BorderLayout; import java.awt.GridLayo

  • java实现简单扫雷游戏

    本文实例为大家分享了java实现简单扫雷游戏的具体代码,供大家参考,具体内容如下 package com.test.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JButton; import javax.

  • java实现简单扫雷小游戏

    本文实例为大家分享了java实现扫雷游戏的具体代码,供大家参考,具体内容如下 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.GridLayout; import java.awt.Insets; import java.awt.Label; import java.awt.event.ActionEvent; import java.awt.event

  • Java语言实现的扫雷游戏(2)

    本文实例为大家分享了Java语言实现的扫雷游戏的第2部分代码,供大家参考,具体内容如下 在上一篇文章中,我们已经将扫雷的绘制了方格阵列并随机分配了炸弹的位置,接下来我们要将阵列全部覆盖上按钮.因为我们要通过按钮来获知当前方格的坐标,所以简单的Button按钮还无法满足我们的要求,所以,我们就自定义一个按钮的类,让它继承自Button类,但要给他加上行号和列号,这样我们就能直接通过按钮读取它的位置了 import javax.swing.JButton; public class MyButton

随机推荐