扫雷小游戏
基本思路
此次的扫雷小游戏游戏规则与经典扫雷基本相同,需要点开所有非雷区域方可胜利。
作为一个游戏需要有以下几个基本功能:开始游戏,重新开始,退出游戏;选择游戏的难度,如简单,中单,困难;游戏胜利或失败后的反馈界面。
首先,一个游戏要对游戏数据进行存储和处理并将结果呈现出来。扫雷所需的游戏数据有各个格子的状态,如:格子的开闭,格子是否为雷。这些状态都是独立的,因此可以用不同的数字来表示不同的状态。由于扫雷为一个二维的格子矩阵,因此可以用两个二维数组来对应每个格子的状态(一个对应开闭状态,用0表示闭,1表示开;另一个对应格子存放的内容,用9表示雷,0~8表示格子所在的九宫格内所含有的雷数)
以下为后面需要用到的数据变量
public class Saolei extends JPanel implements ActionListener, MouseListener {
private static final int WIDTH = 15;//格子的列数
private static final int HEIGHT = 15;//格子的行数
private int[][] initial = new int[WIDTH][HEIGHT];//格子的显示状态
private int[][] shape = new int[WIDTH][HEIGHT];//格子的存储对象
private Graphics g;
private String str;
private int x0, y0;
private JFrame jf = new JFrame("扫雷");//游戏窗体
private JFrame jfr = new JFrame("选择难度");//选择难度窗体
private JFrame jfra = new JFrame("游戏结果");//游戏失败窗体
private JFrame jfram = new JFrame("游戏结果");//游戏胜利窗体
private int firstbegin = 0;//控制游戏开始
private int firstover = 0;//控制失败窗体
private int firstvictory = 0;//控制胜利窗体
private int victory;//判断胜利
}
在开始游戏时要进行游戏数据的初始化并在后续的游戏操作中不断改变数据。首先设置所有的格子为闭状态。
public void setIn() {
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
initial[i][j] = 0;
}
}
}
接着设置雷的数量,根据不同的难度来确定设置的雷数。设置雷需要设置雷的坐标,因此设置两个随机变量,分别代表x,y坐标,要求每个雷设置的坐标不重复,因此先获取一个随机坐标,然后判断该坐标是否已经存在雷,若已存在雷,则重新获取坐标,这一步使用do,while循环来解决;若不存在雷,则退出循环,并把该坐标设置为有雷状态。
public void setLei(int count) {
int x, y;
Random rx = new Random();
Random ry = new Random();
for (int i = 0; i < count; i++) {
do {
x = rx.nextInt(WIDTH);
y = ry.nextInt(HEIGHT);
} while (shape[x][y] == 9);
shape[x][y] = 9;
}
}
当第一次开始游戏或多次进行游戏时,不仅格子开闭状态需要重置,雷的坐标也需要重新设置,要达到这一效果就需要将之前设置的所有的雷清除,然后再重新设置雷。
public void initiallei() {
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
shape[i][j] = 0;
}
}
}
当雷设置完后,则需要设置其他格子的状态,按照游戏规则,每个非雷的格子上的数字表示以它为中心的九宫格所有的雷数,因此,此处有两种方法计算这个数字。一种为在雷的周围8个格子加上一,将每个雷周围的格子都进行此操作即可;另一种为计算每个格子周围有几个雷(此种方法计算次数相对较多,此处采用这种方法示例)
public void setothers(int x, int y) {
int current = 0;
if (shape[x][y] != 9) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (x - 1 + i >= 0 && x - 1 + i <= 14 && y - 1 + j >= 0 && y - 1 + j <= 14) {
if (shape[x - 1 + i][y - 1 + j] == 9) {
current++;
}
}
}
}
shape[x][y] = current;
}
}
当基础数据设置完毕后便开始游戏界面的设置,首先选好相应的图片与0~9的格子相匹配,还有一张格子未打卡开的图片。当点击开始游戏按钮时,将图片绘制的面板上,此时运用到之前所设置的firstbegin变量,第一次点击开始游戏后,firstbegin++,于是继承JPanel且重写的paint方法开始能够发挥作用。
public void paint(Graphics g) {
super.paint(g);
if (firstbegin != 0) {
//点击开始游戏后执行
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
if (initial[i][j] == 1) {
String string = "image/" + shape[i][j] + ".png";//1~9状态的图片
ImageIcon image = new ImageIcon(string);
Image im = image.getImage();
g.drawImage(im, 60 * i, 60 * j, 60, 60, null);
} else if (initial[i][j] == 0) {
String string = "image/" + "10" + ".png";//格子未打开的图片
ImageIcon image = new ImageIcon(string);
Image im = image.getImage();
g.drawImage(im, 60 * i, 60 * j, 60, 60, null);
} else {
ImageIcon image = new ImageIcon("image/红旗.png");//此处涉及到后期的游戏完善功能,在下面将会介绍
Image im = image.getImage();
g.drawImage(im, 60 * i, 60 * j, 60, 60, null);
}
}
}
}
}
此外点击开始游戏还需要弹出难度选择的窗体,并根据选择的难度来进行以下一系列的设置。
public void actionPerformed(ActionEvent e) {
str = e.getActionCommand();
if (str.equals("开始游戏") && firstbegin == 0) {
firstbegin++;
jfr.setSize(300, 80);
jfr.setLocationRelativeTo(null);
jfr.setLayout(new FlowLayout());
String[] str1 = {
"简单", "中等", "困难" };
for (int i = 0; i < str1.length; i++) {
JButton jb = new JButton(str1[i]);
jfr.add(jb);
jb.addActionListener(this);
}
jfr.setVisible(true);
}
if (str.equals("简单")) {
victory=15;//判断胜利条件,在数值上等于雷数,在后面将会介绍
setIn();//初始化格子开闭状态
initiallei();//重置雷
setLei(15);//设置雷
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
setothers(i, j);//设置其他格子
}
}
jfr.setVisible(false);//当选择难度后,该窗体隐藏
_paint();//将设置的格子绘制到面板上
}
if (str.equals("中等")) {
victory=30;
setIn();
initiallei();
setLei(30);
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
setothers(i, j);
}
}
jfr.setVisible(false);
_paint();
}
if (str.equals("困难")) {
victory=45;
setIn();
initiallei();
setLei(45);
for (int i = 0