Java ゲーム開発 - マインスイーパー

導入:

        マインスイーパのコード実装は非常にシンプルで、マウスの左右ボタンを同時にクリックするのが少し面倒ですが、大きな問題ではありません。

アイデア:

        1. メインウィンドウ、ロードメニュー、ゲームパネルを作成します。

        2. ゲームパネル内の各種パラメータを初期化し、ゲームの難易度に応じて各種機能コンポーネントを設定します。

        3. マウスプレス関数mousePressed()を使用して、左クリックと右クリックの同時イベントを処理し、周囲の開くことのできる四角形を開きます。

        4. マウスリリース関数mouseReleased()を使用して、左右のキーのクリックイベントを処理し、特定の四角形を開きます. それが空白の四角形の場合は、再帰的に再帰メソッドを使用して、その周囲のすべての空白の四角形を開きます。

        5. 地雷を踏むか、すべての地雷を発見し、ゲームが終了するかを決定します。

 コード: 

 

        コンパイル後、イメージの位置はパッケージの位置と同じ高さになります。これは、イメージをロードするときにクラスパスから開始し、絶対パスが許可されていないためです。

このゲームは JDK1.8 を使用し、UTF-8 でエンコードします。

        合計 4 つのクラスがあり、Gobang.java はゲーム エントリ クラスです。 GameFrame.java はメイン ウィンドウ クラスです。 GamePanel.java はゲーム パネル クラスです。 GameLogic.java はゲーム ロジック クラスです。まずはすべてのコードを一度に投稿しましょう。

1. Gobang.java ゲームエントリークラス

package com.game.mine;

/**
 * 功能:扫雷<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class Mine {

    public static void main(String[] args)
    {
        new GameFrame();
    }
}

 2. GameFrame.java メイン ウィンドウ クラス。

package com.game.mine;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

/**
 * 功能:游戏窗口<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GameFrame extends JFrame implements ActionListener
{
	private static final long serialVersionUID = 2596945399892762751L;

	/** 游戏面板 */
	private GamePanel gamePanel;
	
	/** 菜单控件 */
	JMenuItem jmi_easy,jmi_normal,jmi_hard;
        
	/**
	 * 功能:构造函数<br>
	 */
	public GameFrame()
	{
		try
		{
			//窗口
			this.setTitle("扫雷");
			this.setLayout(null);
			this.setBackground(Color.WHITE);
			this.setResizable(false);
			this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			//菜单
			JMenuBar jmb_mine = new JMenuBar();
			JMenu jm_game = new JMenu("游戏");
			jm_game.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_new = jm_game.add("  开局");
			jmi_new.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_new.addActionListener(this);
			jmi_new.setActionCommand("new");
			jm_game.addSeparator();
			this.jmi_easy = jm_game.add("√ 初级");
			this.jmi_easy.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_easy.addActionListener(this);
			this.jmi_easy.setActionCommand("easy");
			this.jmi_normal = jm_game.add("  中级");
			this.jmi_normal.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_normal.addActionListener(this);
			this.jmi_normal.setActionCommand("normal");
			this.jmi_hard = jm_game.add("  高级");
			this.jmi_hard.setFont(new Font("微软雅黑",Font.PLAIN,12));
			this.jmi_hard.addActionListener(this);
			this.jmi_hard.setActionCommand("hard");
			jm_game.addSeparator();
			JMenuItem jmi_exit = jm_game.add("  退出");
			jmi_exit.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_exit.addActionListener(this);
			jmi_exit.setActionCommand("exit");
			jmb_mine.add(jm_game);
			JMenu jm_help = new JMenu("帮助");
			jm_help.setFont(new Font("微软雅黑",Font.PLAIN,12));
			JMenuItem jmi_about = jm_help.add("关于");
			jmi_about.setFont(new Font("微软雅黑",Font.PLAIN,12));
			jmi_about.addActionListener(this);
			jmi_about.setActionCommand("about");
			jmb_mine.add(jm_help);
			this.setJMenuBar(jmb_mine);
			//面板
			this.gamePanel = new GamePanel();
			this.add(this.gamePanel);
			//显示
			this.gamePanel.setLevel(this.gamePanel.EASY);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
			this.setLocationRelativeTo(null);   //居中
			this.setBounds(this.getX() - 63,this.getY() - 63,this.getWidth(),this.getHeight());     //因为初级、中级、高级窗口大小不一样,但都以左上角位置为固定点,向右向下拉伸,所以考虑左上角位置再向左上方多挪点。
			this.setVisible(true);
		}
		catch(Exception e)
		{
			JOptionPane.showMessageDialog(this,"程序出现异常错误,即将退出!\r\n\r\n"+e.toString(),"提示",JOptionPane.ERROR_MESSAGE);
			System.exit(0);
		}
	}
	
	/**
	 * 功能:事件监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		if("new".equals(command))
		{
			this.gamePanel.newGame();
		}
		else if("easy".equals(command))
		{
			this.jmi_easy.setText("√ 初级");
			this.jmi_normal.setText("  中级");
			this.jmi_hard.setText("  高级");
			this.gamePanel.setLevel(this.gamePanel.EASY);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("normal".equals(command))
		{
			this.jmi_easy.setText("  初级");
			this.jmi_normal.setText("√ 中级");
			this.jmi_hard.setText("  高级");
			this.gamePanel.setLevel(this.gamePanel.NORMAL);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("hard".equals(command))
		{
			this.jmi_easy.setText("  初级");
			this.jmi_normal.setText("  中级");
			this.jmi_hard.setText("√ 高级");
			this.gamePanel.setLevel(this.gamePanel.HARD);
			this.setSize(this.gamePanel.getWidth() + 15,this.gamePanel.getHeight() + 60);
		}
		else if("exit".equals(command))
		{
			System.exit(0);
		}
		else if("about".equals(command))
		{
			JOptionPane.showMessageDialog(this,"我是小木鱼(Lag)","提示",JOptionPane.INFORMATION_MESSAGE);
		}
	}

}

3. GamePanel.java ゲームパネルクラス。

package com.game.mine;

import java.util.Map;
import java.util.HashMap;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.BorderFactory;
import javax.swing.JLabel;

/**
 * 功能:游戏面板<br>
 * 作者:我是小木鱼(Lag)<br>
 */
public class GamePanel extends JPanel implements MouseListener,ActionListener
{
	private static final long serialVersionUID = -3395178511152885550L;

	/** 游戏逻辑 */
	private GameLogic gameLogic;

	/** 初级难度(9×9,10个地雷) */
	final int EASY = 1;
	
	/** 中级难度(16×16,40个地雷) */
	final int NORMAL = 2;

	/** 高级难度(30×16,99个地雷) */
	final int HARD = 3;

	/** 上次游戏难度 */
	private int oldLevel = -1;
	
	/** 本次游戏难度 */
	private int newLevel = 0;
	
	/** 网格行数 */
	int gridRows;

	/** 网格列数 */
	int gridColumns;

	/** 网格尺寸 */
	final int gridSize = 17;

	/** 网格宽度 */
	private int gridsWidth;

	/** 网格高度 */
	private int gridsHeight;

	/** 地雷数 */
	int mineNum;

	/** 提示区面板 */
	private JPanel panelTip = new JPanel();
	
	/** 地雷区面板 */
	private JPanel panelMine = new JPanel();
	
	/** 笑脸按钮 */
	private JButton buttonFace = new JButton();
        
	/** 地雷数提示标签 */
	JLabel labelMineTip[] = new JLabel[3];
        
	/** 时间提示标签 */
	JLabel labelTimeTip[] = new JLabel[3];

	/** 地雷按钮数组 */
	JButton[][] buttonMine = new JButton[16][30];
        
	/**
	 * 地雷信息数组<br>
	 * number->地雷数:-1-地雷,0到8-周围地雷数<br>
	 * flag->地雷状态:0-未打开,1-已打开,2-插小旗,3-插问号<br>
	 */
	@SuppressWarnings("unchecked")	//数组不支持泛型
	Map<String,Integer>[][] mapMine = new Map[16][30];

	/** 笑脸图片 */
	private ImageIcon[] imageIconFace = new ImageIcon[2];
        
	/** 数字提示图片 */
	ImageIcon[] imageIconNumberTip = new ImageIcon[10];
        
	/** 数字图片 */
	ImageIcon[] imageIconNumber = new ImageIcon[9];
        
	/** 空白图片 */
	ImageIcon imageIconBlank = new ImageIcon();
        
	/** 方格图片 */
	ImageIcon imageIconCell = new ImageIcon();

	/** 红旗图片 */
	ImageIcon imageIconFlag = new ImageIcon();
	
	/** 问号图片 */
	ImageIcon imageIconQuestion = new ImageIcon();
	
	/** 地雷图片 */
	ImageIcon imageIconMine = new ImageIcon();
        
	/** 爆炸图片 */
	ImageIcon imageIconBomb = new ImageIcon();
	
	/** 找雷错误图片 */
	ImageIcon imageIconWrongMine = new ImageIcon();
        
	/** 时间提示数字 */
	int timeTip = 0;
	
	/** 扫雷提示数字 */
	int mineTip = 0;

	/** 计时器 */
	Timer timer = new Timer(1000,this);
	
	/** 游戏是否开始(true-开始,false-未开始) */
	boolean isStart = false;

	/** 游戏是否结束(true-结束,false-未结束) */
	boolean isGameOver = true;
	
	/**
	 * 功能:构造函数<br>
	 */
	public GamePanel()
	{
		//主面板初始化
		this.setBackground(Color.LIGHT_GRAY);
		this.setBorder(BorderFactory.createRaisedBevelBorder());    //边框凸起
		this.setLayout(null);   //自由布局

		//提示区面板初始化
		this.panelTip.setBackground(Color.LIGHT_GRAY);
		this.panelTip.setBorder(BorderFactory.createLoweredBevelBorder());  //边框下凹
		this.panelTip.setLayout(null);
		this.add(this.panelTip);
		
		//地雷区面板初始化
		this.panelMine.setBackground(Color.LIGHT_GRAY);
		this.panelMine.setBorder(BorderFactory.createLoweredBevelBorder());     //边框下凹
		this.add(this.panelMine);
                
		//地雷数提示标签初始化
		for(int i=0;i<this.labelMineTip.length;i++)
		{
			this.labelMineTip[i] = new JLabel();
		}

		//笑脸按钮初始化
		this.buttonFace.addActionListener(this);     //事件监听只能添加一次,若多次添加会造成监听事件重复执行。
                
		//时间提示标签初始化
		for(int i=0;i<this.labelTimeTip.length;i++)
		{
			this.labelTimeTip[i] = new JLabel();
		}
                
		//地雷按钮初始化
		for(int row=0;row<this.buttonMine.length;row++)
		{
		    for(int column=0;column<this.buttonMine[0].length;column++)
		    {
		        this.buttonMine[row][column] = new JButton();
		        this.buttonMine[row][column].addMouseListener(this);
		        this.buttonMine[row][column].setName(row+"_"+column);         //用名字来区分行列坐标
		    }
		}
                
		//地雷信息初始化
		for(int row=0;row<this.mapMine.length;row++)
		{
		    for(int column=0;column<this.mapMine[0].length;column++)
		    {
		    	this.mapMine[row][column] = new HashMap<String,Integer>();
		    	this.mapMine[row][column].put("number",0);	//0个雷
		    	this.mapMine[row][column].put("flag",0);	//未打开
		    }
		}

		//加载图片
		this.loadImage();

		//游戏逻辑
		this.gameLogic = new GameLogic(this);

		//设置游戏难度并调整各组件大小
		this.setLevel(this.EASY);
		
	}
	
	/**
	 * 功能:加载图片<br>
	 * 备注:考虑Jar包问题,所以图片路径用URL格式<br>
	 */
	private void loadImage()
	{
		try
		{
			//笑脸图片
			this.imageIconFace[0] = new ImageIcon(this.getClass().getResource("/resource/mine/smile.gif"));
			this.imageIconFace[1] = new ImageIcon(this.getClass().getResource("/resource/mine/ooo.gif"));
			//数字提示图片
			for(int i=0;i<this.imageIconNumberTip.length;i++)
			{
			    this.imageIconNumberTip[i] = new ImageIcon(this.getClass().getResource("/resource/mine/c"+i+".gif"));
			}
			//数字图片
			for(int i=0;i<this.imageIconNumber.length;i++)
			{
			    this.imageIconNumber[i] = new ImageIcon(this.getClass().getResource("/resource/mine/"+i+".gif"));
			}
			//空白图片
			this.imageIconBlank = new ImageIcon(this.getClass().getResource("/resource/mine/blank.gif"));
			//方格图片
			this.imageIconCell = new ImageIcon(this.getClass().getResource("/resource/mine/cell.gif"));
			//红旗图片
			this.imageIconFlag = new ImageIcon(this.getClass().getResource("/resource/mine/flag.gif"));
			//问号图片
			this.imageIconQuestion = new ImageIcon(this.getClass().getResource("/resource/mine/question.gif"));
			//地雷图片
			this.imageIconMine = new ImageIcon(this.getClass().getResource("/resource/mine/mine.gif"));
			//爆炸图片
			this.imageIconBomb = new ImageIcon(this.getClass().getResource("/resource/mine/bomb.gif"));
			//找雷错误图片
			this.imageIconWrongMine = new ImageIcon(this.getClass().getResource("/resource/mine/wrongmine.gif"));
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * 功能:初始化游戏<br>
	 */
	private void initGame()
	{
		//重新设置参数
		this.mineTip = this.mineNum;
		this.gameLogic.setNumberTip(this.mineNum,0);
		this.timeTip = 0;
		this.gameLogic.setNumberTip(0,1);
		this.isGameOver = false;
		this.isStart = false;
		this.timer.stop();
		//重置所有的信息
		this.gameLogic.resetAll();
		//随机生雷并记录周围地雷数
		this.gameLogic.randomMine();
	}
	
	/**
	 * 功能:设置游戏难度级别<br>
	 */
	public void setLevel(int _level)
	{
		//判断难度是否有变化
		if(this.oldLevel == _level){return;}
		//记录难度
		this.oldLevel = _level;
		this.newLevel = _level;
		//开始调试
		if(this.newLevel == this.EASY)
		{
			this.gridRows = 9;
			this.gridColumns = 9;
			this.mineNum = 10;
		}
		else if(this.newLevel == this.NORMAL)
		{
			this.gridRows = 16;
			this.gridColumns = 16;
			this.mineNum = 40;
		}
		else if(this.newLevel == this.HARD)
		{
			this.gridRows = 16;
			this.gridColumns = 30;
			this.mineNum = 99;
		}
		this.gridsWidth = this.gridSize * (this.gridColumns);
		this.gridsHeight = this.gridSize * (this.gridRows);
		//重新设置主面板尺寸
		this.setBounds(0,0,this.gridsWidth + 22,this.gridsHeight + 64);
		//重新设置提示区面板尺寸并清除上面的组件
		this.panelTip.setBounds(8,8,this.getWidth() - 17,36);
		this.panelTip.removeAll();
		//重新设置地雷区面板尺寸并清除上面的组件
		this.panelMine.setBounds(8,50,this.gridsWidth + 5,this.gridsHeight + 5);
		this.panelMine.removeAll();
		//重新设置笑脸按钮
		this.buttonFace.setBounds((this.panelTip.getX() + this.panelTip.getWidth() - 34)/2,5,26,27);
		this.buttonFace.setIcon(this.imageIconFace[0]);
		this.buttonFace.setPressedIcon(this.imageIconFace[1]);
		this.buttonFace.setBorder(null);   //边框太难看,不要
		this.panelTip.add(this.buttonFace);
		//重新设置地雷数提示标签并显示总地雷数
		this.labelMineTip[0].setBounds(8,7,13,23);
		this.labelMineTip[1].setBounds(21,7,13,23);
		this.labelMineTip[2].setBounds(34,7,13,23);
		this.gameLogic.setNumberTip(this.mineNum,0);
		this.panelTip.add(this.labelMineTip[0]);
		this.panelTip.add(this.labelMineTip[1]);
		this.panelTip.add(this.labelMineTip[2]);
		//重新设置时间提示标签并显示时间数
		this.labelTimeTip[0].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 54,7,13,23);
		this.labelTimeTip[1].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 41,7,13,23);
		this.labelTimeTip[2].setBounds(this.panelTip.getX() + this.panelTip.getWidth() - 28,7,13,23);
		this.gameLogic.setNumberTip(0,1);
		this.panelTip.add(this.labelTimeTip[0]);
		this.panelTip.add(this.labelTimeTip[1]);
		this.panelTip.add(this.labelTimeTip[2]);
		//重新设置地雷区按钮
		this.panelMine.setLayout(null);		//千万不要用GridLayout布局,那就是一个坑啊
		for(int row=0;row<this.gridRows;row++)
		{
		    for(int column=0;column<this.gridColumns;column++)
		    {
		    	this.buttonMine[row][column].setIcon(this.imageIconCell);
		    	this.buttonMine[row][column].setPressedIcon(this.imageIconBlank);
		    	this.buttonMine[row][column].setBorder(null);		//先不要边框,极其难看。但后面开始挖雷时又必须设置边框,要不更极其难看。
		    	this.buttonMine[row][column].setBounds(column * this.gridSize + 2,row * this.gridSize + 2,this.gridSize,this.gridSize);
		    	this.panelMine.add(this.buttonMine[row][column]);
		    }
		}
		//初始化游戏
		this.initGame();
	}
	
	/**
	 * 功能:开始新游戏<br>
	 */
	public void newGame()
	{
		this.initGame();
	}
	
	/**
	 * 功能:事件监听<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		if(e.getSource() == this.timer)		//定时器
		{
			this.timeTip++;
			this.gameLogic.setNumberTip(this.timeTip,1);
		}
		else if(e.getSource() == this.buttonFace)
		{
			this.newGame();
		}
	}
	
	/**
	 * 功能:鼠标按下事件监听<br>
	 */
	@Override
	public void mousePressed(MouseEvent e)
	{
		//游戏结束,退出
		if(this.isGameOver) {return;}
		
		//游戏未开始,开始游戏,不退出
	    if(this.isStart == false)
		{
			this.isStart = true;
			this.timer.start();
		}
		
        //判断是否鼠标左右键同时点击。该判断仅在鼠标按下事件中判断,我认为无论如何操作都可能会触发鼠标左键点击事件和鼠标右键点击事件。
	    if(e.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK + MouseEvent.BUTTON3_DOWN_MASK)
	    {
	        Object obj = e.getSource();
	        if(obj instanceof JButton)
            {
            	JButton jbMine = (JButton)obj;
            	String location[] = jbMine.getName().split("_");
            	int row = Integer.parseInt(location[0]);
            	int column = Integer.parseInt(location[1]);
            	this.gameLogic.openCellAround(row, column);	//鼠标左右键同时点击会打开周围的格子
            }
	    }

	}

	/**
	 * 功能:鼠标释放事件监听<br>
	 */
	@Override
	public void mouseReleased(MouseEvent e) 
	{
		//游戏结束,退出
		if(this.isGameOver) {return;}
		
		//游戏未开始,开始游戏,不退出
	    if(this.isStart == false)
		{
			this.isStart = true;
			this.timer.start();
		}
		
        Object obj = e.getSource();
        
        //鼠标左键点击
        if(e.getButton() == MouseEvent.BUTTON1)
        {
            if(obj instanceof JButton)
            {
            	JButton jbMine = (JButton)obj;
            	String location[] = jbMine.getName().split("_");
            	int row = Integer.parseInt(location[0]);
            	int column = Integer.parseInt(location[1]);
            	this.gameLogic.openCell(row,column);	//打开该格子
            }
        }
        else if(e.getButton() == MouseEvent.BUTTON3)    //鼠标右键点击
        {
            if(obj instanceof JButton)
            {
	        	JButton jbMine = (JButton)obj;
	        	String location[] = jbMine.getName().split("_");
	        	int row = Integer.parseInt(location[0]);
	        	int column = Integer.parseInt(location[1]);
	        	if(this.mapMine[row][column].get("flag") == 0)		//处于未打开状态插红旗
	        	{
	        		this.mapMine[row][column].put("flag",2);
	        		this.buttonMine[row][column].setIcon(this.imageIconFlag);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconFlag);
	        		//更改地雷提示数字
	        		this.mineTip--;
	        		this.gameLogic.setNumberTip(this.mineTip,0);
	        	}
	        	else if(this.mapMine[row][column].get("flag") == 2)	//处于插红旗状态变问号
	        	{
	        		this.mapMine[row][column].put("flag",3);
	        		this.buttonMine[row][column].setIcon(this.imageIconQuestion);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconQuestion);
	        		//更改地雷提示数字
	        		this.mineTip++;
	        		this.gameLogic.setNumberTip(this.mineTip,0);
	        	}
	        	else if(this.mapMine[row][column].get("flag") == 3)	//处于问号状态变未打开
	        	{
	        		this.mapMine[row][column].put("flag",0);
	        		this.buttonMine[row][column].setIcon(this.imageIconCell);
	        		this.buttonMine[row][column].setPressedIcon(this.imageIconBlank);
	        	}
            }
        }
		
	}

	@Override
	public void mouseClicked(MouseEvent e){}
	
	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

}

 4. GameLogic.java ゲーム ロジック クラス。

package com.game.mine;

import java.awt.Color;
import javax.swing.JOptionPane;
import javax.swing.BorderFactory;

public class GameLogic
{
	/** 游戏面板 */
	private GamePanel gamePanel;
    
	/**
	 * 功能:构造函数<br>
	 */
	public GameLogic(GamePanel _gamePanel)
	{
		this.gamePanel = _gamePanel;
	}
        
	/**
	 * 功能:设置地雷数与时间提示<br>
	 * 参数:_number -> 要显示的数字<br>
	 * 参数:_flag -> 标识(0-地雷数,1-时间)<br>
	 */
	public void setNumberTip(int _number,int _flag)
	{
		if(_number <0){_number = 0;}
		
		//将数字转换为3位长字符串,前面不足补零
		String tip = "000" + Integer.toString(_number);
		tip = tip.substring(tip.length() - 3,tip.length());
		if(_flag == 0)      //显示剩余地雷数
		{
			if(_number > this.gamePanel.mineNum){_number = this.gamePanel.mineNum;}
		    for(int i=0;i<3;i++)
		    {
		        this.gamePanel.labelMineTip[i].setIcon(this.gamePanel.imageIconNumberTip[Integer.parseInt(tip.substring(i,i+1))]);
		    }
		}
		else if(_flag == 1)     //显示游戏时间
		{
			if(_number > 999){_number = 999;}
		    for(int i=0;i<3;i++)
		    {
		        this.gamePanel.labelTimeTip[i].setIcon(this.gamePanel.imageIconNumberTip[Integer.parseInt(tip.substring(i,i+1))]);
		    }
		}

	}

	/**
	 * 功能:模拟雷区组件不可用效果<br>
	 * 备注:只是模拟实际不好用,鼠标点击事件仍然执行。但起码表面看起来像是只读一样。<br>
	 */
	public void setMineAreaDisable()
	{
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	if(this.gamePanel.mapMine[row][column].get("flag") == 0)
		    	{
			    	this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconCell);
			    	this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconCell);
		    	}
		    }
		}
	}
	
	/**
	 * 功能:重置所有的信息<br>
	 */
	public void resetAll()
	{
		//重置地雷按钮
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconCell);
		    	this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconBlank);
		    	this.gamePanel.buttonMine[row][column].setBorder(null);
		    }
		}
		//重置地雷信息
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	this.gamePanel.mapMine[row][column].put("number",0);	//0个雷
		    	this.gamePanel.mapMine[row][column].put("flag",0);		//未打开
		    }
		}
	}
	
	/**
	 * 功能:随机生雷并记录周围地雷数<br>
	 */
	public void randomMine()
	{
		//随机生成地雷
		for(int i=0;i<this.gamePanel.mineNum;)
		{
			int row = (int)(Math.random() * this.gamePanel.gridRows);
			int column = (int)(Math.random() * this.gamePanel.gridColumns);
			//判断该位置是否已经有雷
			if(this.gamePanel.mapMine[row][column].get("number") != -1)
			{
				this.gamePanel.mapMine[row][column].put("number",-1);
				i++;
			}
		}
		//记录周围的雷数
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
			{
				if(this.gamePanel.mapMine[row][column].get("number") != -1)
				{
					this.gamePanel.mapMine[row][column].put("number",this.countMineAround(row,column));
				}
			}
		}
	}	
	
	/**
	 * 功能:计算周围的雷数<br>
	 * 备注:九宫格(上、下、左、右、左上、左下、右上、右下)<br>
	 */
	private int countMineAround(int _row,int _column)
	{
		int count = 0;
		for(int row=_row-1;row<=_row+1;row++)
		{
			if(row < 0 || row >= this.gamePanel.gridRows){continue;}	//行出边界了
			for(int column=_column-1;column<=_column+1;column++)
			{
				if(column < 0 || column >= this.gamePanel.gridColumns){continue;}	//列出边界了
				if(row == _row && column == _column){continue;}	//自身不计算在内
				if(this.gamePanel.mapMine[row][column].get("number") == -1){count++;}
			}
		}
		
		return count;
	}
	
	/**
	 * 功能:显示所有的雷<br>
	 */
	public void showMine()
	{
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
		    	if(this.gamePanel.mapMine[row][column].get("number") == -1)
		    	{
		    		this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconMine);
		    		this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconMine);
		    		this.gamePanel.mapMine[row][column].put("flag",1);
		    	}
		    }
		}
	}
	
	/**
	 * 功能:打开单元格<br>
	 * 备注:调用递归法<br>
	 */
	public void openCell(int _row,int _column)
	{
    	//System.out.println(_row+","+_column);

		//如果状态是已经打开或标注小红旗了就不往下判断了
		if(this.gamePanel.mapMine[_row][_column].get("flag") == 1 || this.gamePanel.mapMine[_row][_column].get("flag") == 2){return;}
		
		//设置该格子的边框为线条形(这个很重要,要不效果会很难看)
    	this.gamePanel.buttonMine[_row][_column].setBorder(BorderFactory.createLineBorder(Color.GRAY,1));

		if(this.gamePanel.mapMine[_row][_column].get("number") == -1)			//踩到地雷了
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
			this.showMine();	//显示所有雷
    		this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconBomb);	//本格子的雷特殊标记
    		this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconBomb);
    		this.setMineAreaDisable();	//雷区禁止点击,骗人的
			this.gamePanel.isGameOver = true;
    		this.gamePanel.isStart = false;
			this.gamePanel.timer.stop();
			return;
		}
		else if(this.gamePanel.mapMine[_row][_column].get("number") == 0)		//踩到空白处
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
			this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconNumber[0]);
			this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconNumber[0]);
			//开始判断周围四面八方的地雷数
			for(int row=_row-1;row<=_row+1;row++)
			{
				if(row < 0 || row >= this.gamePanel.gridRows){continue;}
				for(int column=_column-1;column<=_column+1;column++)
				{
					if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
					if(row == _row && column == _column){continue;}
					if(this.gamePanel.mapMine[row][column].get("number") != -1){openCell(row,column);}	//如果是空白需采用递归法继续向该格子的四面八方判断地雷数,直到无空白格
				}
			}
		}
		else	//踩到数字处
		{
			this.gamePanel.mapMine[_row][_column].put("flag",1);
    		this.gamePanel.buttonMine[_row][_column].setIcon(this.gamePanel.imageIconNumber[this.gamePanel.mapMine[_row][_column].get("number")]);
    		this.gamePanel.buttonMine[_row][_column].setPressedIcon(this.gamePanel.imageIconNumber[this.gamePanel.mapMine[_row][_column].get("number")]);
		}
		
		//判断游戏是否结束
		if(this.GameOver())
		{
    		this.setMineAreaDisable();
			this.gamePanel.isGameOver = true;
    		this.gamePanel.isStart = false;
			this.gamePanel.timer.stop();
		}
		
	}

	/**
	 * 功能:打开周围的单元格<br>
	 * 备注:用于鼠标左右键同时点击事件<br>
	 */
	public void openCellAround(int _row,int _column)
	{
		//仅状态是已经打开且周围地雷数大于零时才生效
		if(this.gamePanel.mapMine[_row][_column].get("flag") == 1 || this.gamePanel.mapMine[_row][_column].get("number") > 0)
		{
			//如果它周围的雷都已经标记出来(插红旗),且没错误,那么它周围未打开的非雷格子都默认打开
			//先判断它周围有几个插了红旗的地雷,是否正确
			int count = 0;
			for(int row=_row-1;row<=_row+1;row++)
			{
				if(row < 0 || row >= this.gamePanel.gridRows){continue;}
				for(int column=_column-1;column<=_column+1;column++)
				{
					if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
					if(row == _row && column == _column){continue;}
					if(this.gamePanel.mapMine[row][column].get("flag") == 2)	//插上小红旗了
					{
						if(this.gamePanel.mapMine[row][column].get("number") == -1)
						{
							count++;
						}
						else
						{
							//完蛋了,标记错误,结束游戏
							this.gamePanel.buttonMine[row][column].setIcon(this.gamePanel.imageIconWrongMine);
							this.gamePanel.buttonMine[row][column].setPressedIcon(this.gamePanel.imageIconWrongMine);
							this.gamePanel.mapMine[row][column].put("flag",1);
							this.showMine();
				    		this.setMineAreaDisable();
							this.gamePanel.isGameOver = true;
				    		this.gamePanel.isStart = false;
							this.gamePanel.timer.stop();
							return;
						}
					}
				}
			}
			if(count == this.gamePanel.mapMine[_row][_column].get("number"))	//当前格子附近的雷都已经挖出来了,那么默认它周围非雷的格子都打开。
			{
				for(int row=_row-1;row<=_row+1;row++)
				{
					if(row < 0 || row >= this.gamePanel.gridRows){continue;}
					for(int column=_column-1;column<=_column+1;column++)
					{
						if(column < 0 || column >= this.gamePanel.gridColumns){continue;}
						if(row == _row && column == _column){continue;}
						if(this.gamePanel.mapMine[row][column].get("flag") == 0 || this.gamePanel.mapMine[row][column].get("flag") == 3)
						{
							this.openCell(row,column);
						}
					}
				}
			}
		}

	}
	
	/**
	 * 功能:判断游戏是否结束<br>
	 */
	public boolean GameOver()
	{
		//判断未被打开的方格数与雷数是否相等
		int count = 0;
		for(int row=0;row<this.gamePanel.gridRows;row++)
		{
		    for(int column=0;column<this.gamePanel.gridColumns;column++)
		    {
	    		if(this.gamePanel.mapMine[row][column].get("flag") != 1){count++;}
		    }
		}
		if(count == this.gamePanel.mineNum)
		{
			this.gamePanel.isGameOver = true;
			JOptionPane.showMessageDialog(null,"恭喜您取得了胜利!");
			return true;
		}
		
		return false;
	}
}

詳細な説明:

        わずかに。

ダウンロード: 

        Baidu ネットワーク ディスク リンク: https://pan.baidu.com/s/1s_Q1UCvM4XZFd7wUvjCcTA 抽出コード: yluk

備考:

        なし。

おすすめ

転載: blog.csdn.net/lag_csdn/article/details/122062674