一、项目介绍
扫雷是一款大众类的益智小游戏。根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。这款游戏有着很长的历史,从扫雷被开发出来到现在进行了无数次的优化,这款游戏通过简单的玩法,加上一个好看的游戏界面,每一处的细节都体现了扫雷的魅力。
项目采用技术
二维数组
文件读取存储
人员 | 负责功能 |
杨德旭 | 页面搭建,雷的标记,方块点击,初始化雷区 |
功能需求分析
完成 难度选择,雷随机生成,数字生成,用户登录与注册等功能实现
游戏四种状态: 难度选择、游戏状态、游戏胜利、游戏失败
游戏难度: 初级、中级、高级(不同难度对应不同的雷区大小和雷数量)
游戏核心: 二维数组 的相关操作
其他: 窗口绘制、界面规划、操作计数、重新开始。
项目亮点
1.登陆注册用到了文件的读取和存储
2.用二维数组来储存信息
3.将容器划分为网格,每个网格中可以放置一个组件,再对组件进行处理
系统演示图片
注册
登录
主页面
核心代码
文件的存储和读取
public void mouseClicked(MouseEvent t) {
if (t.getSource() == submit) {
//注册
if (username.getText().length() == 0 || password.getText().length() == 0 || rePassword.getText().length() == 0) {
showDialog("用户名和密码不能为空");
return;
}
if (!password.getText().equals(rePassword.getText())) {
showDialog("两次密码不一致");
return;
}
if (!username.getText().matches("[a-zA-Z0-9]{3,16}")) {
showDialog("用户名不符合规则");
return;
}
if (!password.getText().matches("[a-zA-Z0-9]{3,16}")) {
showDialog("密码不符合规则");
return;
}
if (containsUsername(username.getText())) {
showDialog("用户名已存在,重新输入");
return;
}
//添加用户
allUsers.add(new User(username.getText(), password.getText()));
//写入文件
BufferedWriter bw = null;
try {
//创建输出缓冲流对象
bw = new BufferedWriter(new FileWriter("C:\\Users\\86151\\IdeaProjects\\untitled1\\42\\src\\user.txt"));
for (User u : allUsers) {
bw.write(u.toString());
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//提醒注册成功
showDialog("注册成功");
//关闭注册界面,打开登陆界面
this.setVisible(false);
new LoginJFrame();
}
else if (t.getSource() == reset) {
//重置
username.setText("");
password.setText("");
rePassword.setText("");
}
}
=====================================================================
private void readUser(){
//读取数据
// 创建了一个 BufferedReader 对象,并将其与一个 FileReader 对象关联。
BufferedReader reader = null;
// 创建了一个 List 集合,
List<String> list = new ArrayList<>();
try {
reader = new BufferedReader(new FileReader("C:\\Users\\86151\\IdeaProjects\\untitled1\\42\\src\\user.txt"));
String line;
// 使用 BufferedReader 类的 readLine() 方法来一行一行地读取文件中的内容。
while ((line = reader.readLine()) != null) {
// 对于每一行,我们都将其添加到 List 集合中
list.add(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//遍历集合获取用户信息
for(String str:list){
//username=zhangsan & password=123
String []userIn=str.split("&");
String[] list1=userIn[0].split("=");
String[] list2=userIn[1].split("=");
User u=new User(list1[1],list2[1]);
allUsers.add(u);
}
}
初始化雷区
public void initMineArea(int row,int colum,int mineCount,String grade){
//它首先清空面板 pCenter 中的所有组件,并将类的成员变量的值设置为相应的参数值。
pCenter.removeAll();
spendTime=0;
markMount=mineCount;
this.row=row;
this.colum=colum;
this.mineCount=mineCount;
this.grade=grade;
// 然后,它创建了一个二维数组,并使用两个嵌套循环遍历这个数组中的每一个元素。
block=new Block[row][colum];
for(int i=0;i<row;i++){
for(int j=0;j<colum;j++)
// 对于每一个元素,它创建了一个新的 Block 对象并将其存储在数组中。
block[i][j]=new Block();
}
// 接下来,它调用布雷者对象的成员方法来布置地雷,并调用扫雷者对象的成员方法来准备扫雷。
lay.layMinesForBlock(block,mineCount); //布雷
peopleScoutMine.setBlock(block,mineCount); //准备扫雷
blockView=new BlockView[row][colum]; //创建方块的视图
//GridLayout布局管理器将容器划分为网格,每个网格中可以放置一个组件。
// 指定网格的行数和列数。
pCenter.setLayout(new GridLayout(row,colum));
// 然后,它创建了一个二维数组,并使用两个嵌套循环遍历这个数组中的每一个元素。
// 对于每一个元素,它创建了一个新的 BlockView 视图对象并将其存储在数组中。
for(int i=0;i<row;i++) {
for(int j=0;j<colum;j++) {
blockView[i][j]=new BlockView();
block[i][j].setBlockView(blockView[i][j]); //方块设置自己的视图
// 调用视图对象的成员方法来将block[i][j]的数据放入视图中。
blockView[i][j].setDataOnView();
// 接下来,它将视图对象添加到面板 pCenter 中,
// 并为视图对象上的按钮注册了一个动作监听器和一个鼠标监听器。
pCenter.add(blockView[i][j]);
blockView[i][j].getBlockCover().addActionListener(this);//注册监视器
blockView[i][j].getBlockCover().addMouseListener(this);
blockView[i][j].seeBlockCover(); //初始时盖住block[i][j]的数据信息
//将按钮设置为可用状态。
blockView[i][j].getBlockCover().setEnabled(true);
//按钮将显示这个图标,而不是文本。
blockView[i][j].getBlockCover().setIcon(null);
}
}
//将探明的雷数添加到文本中
showMarkedMineCount.setText(""+markMount);
//重绘面板。
repaint();
}
点击方块
public void actionPerformed(ActionEvent e) {
// 如果方块是地雷,则调用视图对象的成员方法来显示标签。
//如果事件源是重新开始按钮,则调用类的成员方法来初始化雷区,并重绘面板。
//如果事件源是计时器,则将用时增加 1,并更新文本字段 showTime 的文本。
//最后,检查玩家是否获胜。如果获胜,则停止计时器并显示提示框。
if(e.getSource()!=reStart&&e.getSource()!=time) {
//开始计时
time.start();
int m=-1,n=-1;
for(int i=0;i<row;i++) { //找到单击的方块以及它的位置索引
for(int j=0;j<colum;j++) {
if(e.getSource()==blockView[i][j].getBlockCover()){
m=i;
n=j;
break;
}
}
}
//检查该方块是否是地雷。
if(block[m][n].isMine()) { //用户输掉游戏
//遍历二维数组中的每一个元素,并将每一个方块的按钮设置为不可用状态。
for(int i=0;i<row;i++) {
for(int j=0;j<colum;j++) {
blockView[i][j].getBlockCover().setEnabled(false);//用户单击无效了
if(block[i][j].isMine())
blockView[i][j].seeBlockNameOrIcon(); //视图显示方块上的数据信息
}
}
time.stop();
spendTime=0; //恢复初始值
markMount=mineCount; //恢复初始值
}
else {
//遍历周围没有地雷的方块,并显示它们上面的数据信息。
//首先调用peopleScoutMine.getNoMineAroundBlock(block[m][n])方法获取周围没有地雷的方块,并将它们存储在notMineBlock栈中。
Stack<Block> notMineBlock =peopleScoutMine.getNoMineAroundBlock(block[m][n]);
while(!notMineBlock.empty()){
//在每次循环中,它使用notMineBlock.pop()方法移除栈顶元素并返回它。。
Block bk = notMineBlock.pop();
//接下来,它调用bk.getBlockView()方法获取该方块的视图对象,并将其赋值给变量viewforBlock。
ViewForBlock viewforBlock = bk.getBlockView();
//最后,它调用viewforBlock.seeBlockNameOrIcon()方法显示方块上的数据信息。
viewforBlock.seeBlockNameOrIcon();
}
}
}
//如果事件源是重新开始按钮,则调用类的成员方法来初始化雷区,并重绘面板。
if(e.getSource()==reStart) {
initMineArea(row,colum,mineCount,grade);
repaint();
validate();
}
//如果点击计时器,则将用时增加 1,并更新文本字段 showTime 的文本。
if(e.getSource()==time){
spendTime++;
showTime.setText(""+spendTime);
}
if(peopleScoutMine.verifyWin()) { //判断用户是否扫雷成功
//则停止计时器并显示提示框
showDialog("你胜利了");
spendTime=0;
}
}
雷的标记
public void mousePressed(MouseEvent e){ //探雷:给方块上插一个小旗图标(再次单击取消)
// 当用户按下鼠标右键时,这个方法会被调用。
//e.getSource()方法返回了触发事件的组件。强转将其转换为JButton类型,并将其赋值给变量source
JButton source=(JButton)e.getSource();
for(int i=0;i<row;i++) {
for(int j=0;j<colum;j++) {
// 对于每一个元素,如果事件源与该元素上的按钮相同,则检查该元素是否已经被标记。
//1.检查鼠标事件的修饰符是否为InputEvent.BUTTON3_MASK。如果是,则表示用户按下了鼠标右键。
//2.检查事件源(即被单击的按钮)是否与blockView[i][j]元素上的按钮相同。
if(e.getModifiers()==InputEvent.BUTTON3_MASK&&
source==blockView[i][j].getBlockCover()){
if(block[i][j].getIsMark()) {
//将按钮上的图标设置为null。这样,按钮上原先显示的图标就会消失。
source.setIcon(null);
//将方块的isMark属性设置为false。这样,该方块就不再被标记为有地雷。
block[i][j].setIsMark(false);
markMount=markMount+1;
//更新文本
showMarkedMineCount.setText(""+markMount);
}
else{
// 标记该元素
source.setIcon(mark);
block[i][j].setIsMark(true);
markMount=markMount-1;
showMarkedMineCount.setText(""+markMount);
}
}
}
}
}
github地址:
https://gitee.com/yaun_123/minesweeping-mini-program-1
github提交照片: