Java扫雷游戏总结 (小项目)

·【尚学堂Java开发扫雷游戏项目】1个半小时做出java扫雷小游戏_java小游戏_Java游戏开发_Java练手项目_java项目实战_java初级项目_哔哩哔哩_bilibili

前言:

  1. 记录的是大致的写代码过程
  2. 为了视觉上更清晰,下面只是放出了完成该功能的核心代码,把每个功能的代码拼装起来,才是完整的项目代码
  3. 项目中导入的图片,是缩小过它们的尺寸的

项目结构: 

Java扫雷游戏总结 (小项目)_第1张图片

一、窗口绘制

5、GameWin

package com.study;

import javax.swing.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {

    void launch(){//绘制窗口
        this.setVisible(true);//窗口是否可见
        this.setSize(500,500);//窗口大小
        this.setLocationRelativeTo(null);//窗口位置居中显示
        this.setTitle("扫雷游戏");//窗口标题
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//窗口关闭方式
    }

    public static void main(String[] args) {
        GameWin gameWin=new GameWin();
        gameWin.launch();//调用方法绘制窗口
    }
}

 运行结果:

Java扫雷游戏总结 (小项目)_第2张图片

二、雷区绘制

 5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {

    MapBottom mapBottom=new MapBottom();
    public void paint(Graphics g){//绘制组件
        mapBottom.paintSelf(g);
    }
}

6、MapBottom

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {

    //绘制方法
    void paintSelf(Graphics g){
        for(int i=0;i<500;i=i+50){//每隔50像素画一条线
            g.setColor(Color.red);
            //通过画线,组成网格,代表雷区
            //横坐标x1和x2相等,是竖线
            //纵坐标y1和y2相等,是横线
            g.drawLine(0,i,500,i);//横线
            g.drawLine(i,0,i,500);//竖线
        }
    }
}

 运行结果:

Java扫雷游戏总结 (小项目)_第3张图片

三、界面规划

画草图处理变量间的数据关系,整理成公式

Java扫雷游戏总结 (小项目)_第4张图片

4、GameUtil

package com.study;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {

    //地图的宽
    static int MAP_W=11;
    //地图的高
    static int MAP_H=11;
    //雷区偏移量
    static int OFFSET=45;
    //格子边长
    static int SQUARE_LENGTH=50;


}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {

    int width=2*GameUtil.OFFSET+GameUtil.MAP_W*GameUtil.SQUARE_LENGTH;
    int height=4*GameUtil.OFFSET+GameUtil.MAP_H*GameUtil.SQUARE_LENGTH;

    void launch(){//绘制窗口
        this.setSize(width,height);//窗口大小
    }
}

6、MapBottom 

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {

    //绘制方法
    void paintSelf(Graphics g){

        g.setColor(Color.red);

        //相比上一个功能画雷区时的做法,
        //该做法把横线和竖线分开画,如此,雷区就可以是正方形,也可以是其他矩形
        //雷区的形状更灵活
        //画竖线
        for(int i=0;i<=GameUtil.MAP_W;i++){
            g.drawLine(GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH,
                    3*GameUtil.OFFSET,
                    GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH,
                    3*GameUtil.OFFSET+GameUtil.MAP_H*GameUtil.SQUARE_LENGTH);
        }
        //画横线
        for(int i=0;i<=GameUtil.MAP_H;i++){
            g.drawLine(GameUtil.OFFSET,
                    3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH,
                    GameUtil.OFFSET+GameUtil.MAP_W*GameUtil.SQUARE_LENGTH,
                    3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH);
        }
    }
}

运行结果:

 Java扫雷游戏总结 (小项目)_第5张图片

四、底层地图

 4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //底层元素 -1:雷 0:空 1-8:雷数
    static int[][] DATA_BOTTOM=new int[MAP_W+2][MAP_H+2];
    //载入图片
    static Image lei=Toolkit.getDefaultToolkit().getImage("imgs/lei.png");

}

6、MapBottom 

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {

    //绘制方法
    void paintSelf(Graphics g){
        //画雷格
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                g.drawImage(GameUtil.lei,
                        GameUtil.OFFSET+(i-1)*GameUtil.SQUARE_LENGTH+1,//+1是为了露出红线
                        GameUtil.OFFSET*3+(j-1)*GameUtil.SQUARE_LENGTH+1,
                        GameUtil.SQUARE_LENGTH-2,
                        GameUtil.SQUARE_LENGTH-2,
                        null);
            }
        }
    }
}

 运行结果:

Java扫雷游戏总结 (小项目)_第6张图片

五、地雷生成

2、BottomRay

package com.study;

/**
 * 初始化地雷
 */
public class BottomRay {

    //存放坐标
    int[] rays=new int[GameUtil.RAY_MAX*2];
    //地雷坐标
    int x,y;
    {
        for(int i=0;i

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {

    //地雷个数
    static int RAY_MAX=5;
}

6、MapBottom 

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {
    BottomRay bottomRay=new BottomRay();
    //绘制方法
    void paintSelf(Graphics g){
        //画地雷
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                if(GameUtil.DATA_BOTTOM[i][j]==-1) {//根据二维数组存储的随机地雷坐标,来画地雷
                    g.drawImage(GameUtil.lei,
                            GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1,//+1是为了露出红线
                            GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.SQUARE_LENGTH - 2,
                            GameUtil.SQUARE_LENGTH - 2,
                            null);
                }
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第7张图片

六、地雷重合

2、BottomRay

package com.study;

/**
 * 初始化地雷
 */
public class BottomRay {
    //是否可以放置 T:可以;F:不可以
    boolean isPlace=true;
    {
        for(int i=0;i

 4、GameUtil

package com.study;

import java.awt.*;

public class GameUtil {
    //地雷个数
    static int RAY_MAX=121;
}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    void launch(){//绘制窗口
        while(true){//让窗口实时刷新
            repaint();
            try {
                Thread.sleep(40);//每隔40毫秒刷新一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

 Java扫雷游戏总结 (小项目)_第8张图片

七、数字生成

Java扫雷游戏总结 (小项目)_第9张图片

1、BottomNum

package com.study;

/**
 * 底层数据类
 */
public class BottomNum {
    {
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                //如果遍历整个雷区时,遍历到了雷,就进一步遍历该雷周围3*3区域的雷数
                if(GameUtil.DATA_BOTTOM[i][j]==-1){
                    for(int k=i-1;k<=i+1;k++){
                        for(int l=j-1;l<=j+1;l++){
                            if(GameUtil.DATA_BOTTOM[k][l]>=0){
                                GameUtil.DATA_BOTTOM[k][l]++;
                            }
                        }
                    }
                }
            }
        }
    }
}

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {

    //地雷个数
    static int RAY_MAX=5;    
    //载入数字图片
    static Image[] images=new Image[9];
    static{
        for(int i=1;i<=8;i++){
            images[i]=Toolkit.getDefaultToolkit().getImage("imgs/nums/"+i+".png");
        }
    }
}

6、MapBottom

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {

    BottomNum bottomNum=new BottomNum();

    //绘制方法
    void paintSelf(Graphics g){
        //画地雷
        for(int i=1;i<=GameUtil.MAP_W;i++){    
                //雷数
                if(GameUtil.DATA_BOTTOM[i][j]>=0) {
                    g.drawImage(GameUtil.images[GameUtil.DATA_BOTTOM[i][j]],
                            GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 15,//+15是为了让图片更居中
                            GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 5,
                            null);
                }
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第10张图片

八、顶层绘制

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //项层元素 -1:无覆盖 0:覆盖 1:插旗 2:差错旗
    static int[][] DATA_TOP=new int[MAP_W+2][MAP_H+2];
    //载入图片
    static Image top=Toolkit.getDefaultToolkit().getImage("imgs/top.png");
    static Image flag=Toolkit.getDefaultToolkit().getImage("imgs/flag.png");
    static Image noflag=Toolkit.getDefaultToolkit().getImage("imgs/noflag.png");
}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    MapTop mapTop=new MapTop();
    public void paint(Graphics g){//绘制组件
        mapTop.paintSelf(g);
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {

    //绘制方法
    void paintSelf(Graphics g){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                //覆盖
                if(GameUtil.DATA_TOP[i][j]==0) {
                    g.drawImage(GameUtil.top,
                            GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.SQUARE_LENGTH - 2,
                            GameUtil.SQUARE_LENGTH - 2,
                            null);
                }
                //插旗
                if(GameUtil.DATA_TOP[i][j]==1) {
                    g.drawImage(GameUtil.flag,
                            GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.SQUARE_LENGTH - 2,
                            GameUtil.SQUARE_LENGTH - 2,
                            null);
                }
                //插错旗
                if(GameUtil.DATA_TOP[i][j]==2) {
                    g.drawImage(GameUtil.noflag,
                            GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1,
                            GameUtil.SQUARE_LENGTH - 2,
                            GameUtil.SQUARE_LENGTH - 2,
                            null);
                }
            }
        }
    }
}

运行结果:

 Java扫雷游戏总结 (小项目)_第11张图片

九、双缓存技术

  • 用于解决窗口不断闪动问题
  • 闪动原因:在不停地绘制窗口,底层组件和顶层组件是分开被绘制进窗口,所以会交叉出现,造成闪动
  • 解决办法:新建一个画布,把底层组件和顶层组件都绘制好在画布上,再把画布绘制进窗口

 5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    //新建画布,用于组合底层组件和顶层组件
    Image offScreenImage=null;
    public void paint(Graphics g){//绘制组件
        offScreenImage=this.createImage(width,height);//初始化画布
        Graphics gImage=offScreenImage.getGraphics();//新建画笔
        gImage.setColor(Color.orange);//背景颜色
        gImage.fillRect(0,0,width,height);//填充
        mapBottom.paintSelf(gImage);//调用画笔
        mapTop.paintSelf(gImage);//调用画笔
        g.drawImage(offScreenImage,0,0,null);//将画布绘制进窗口
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第12张图片

十、鼠标事件

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //鼠标相关
    //鼠标点击处的坐标
    static int MOUSE_X;
    static int MOUSE_Y;
    //鼠标左右键的状态
    static boolean LEFT=false;
    static boolean RIGHT=false;
}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    void launch(){//绘制窗口     
        //鼠标事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if(e.getButton()==1){//点击鼠标左键
                    GameUtil.MOUSE_X=e.getX();
                    GameUtil.MOUSE_Y=e.getY();
                    GameUtil.LEFT=true;
                }
                if(e.getButton()==3){//点击鼠标右键
                    GameUtil.MOUSE_X=e.getX();
                    GameUtil.MOUSE_Y=e.getY();
                    GameUtil.RIGHT=true;
                }
            }
        });
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {

    //判断逻辑
    void logic(){
        if(GameUtil.LEFT){
            System.out.println(GameUtil.MOUSE_X);
            System.out.println(GameUtil.MOUSE_Y);
            GameUtil.LEFT=false;//释放左键
        }
        if(GameUtil.RIGHT){
            System.out.println(GameUtil.MOUSE_X);
            System.out.println(GameUtil.MOUSE_Y);
            GameUtil.RIGHT=false;//释放右键
        }
    }

    //绘制方法
    void paintSelf(Graphics g){
        logic();//调用上面的逻辑方法
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第13张图片

十一、左键翻开

格子区域的数据分析:

Java扫雷游戏总结 (小项目)_第14张图片

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    void launch(){//绘制窗口
        //鼠标事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if(e.getButton()==1){//点击鼠标左键
                    GameUtil.MOUSE_X=e.getX();
                    GameUtil.MOUSE_Y=e.getY();
                    GameUtil.LEFT=true;
                }
                if(e.getButton()==3){//点击鼠标右键
                    GameUtil.MOUSE_X=e.getX();
                    GameUtil.MOUSE_Y=e.getY();
                    GameUtil.RIGHT=true;
                }
            }
        });
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {

    //格子位置
    int temp_x;
    int temp_y;
    //判断逻辑
    void logic(){
        temp_x=0;//初始化
        temp_y=0;
        //只能点击画了格子的区域,若不加判断,点击上边界也会翻开格子,不合规矩
        if(GameUtil.MOUSE_X>GameUtil.OFFSET && GameUtil.MOUSE_Y>3*GameUtil.OFFSET){
            //对鼠标点击到的格子区域进行进一步处理
            temp_x=(GameUtil.MOUSE_X-GameUtil.OFFSET)/GameUtil.SQUARE_LENGTH+1;
            temp_y=(GameUtil.MOUSE_Y-GameUtil.OFFSET*3)/GameUtil.SQUARE_LENGTH+1;
        }
        if(temp_x>=1 && temp_x<=GameUtil.MAP_W
                && temp_y>=1 && temp_y<=GameUtil.MAP_H) {
            if (GameUtil.LEFT) {
                if(GameUtil.DATA_TOP[temp_x][temp_y]==0){//左键点击覆盖格子,就把格子翻开
                    GameUtil.DATA_TOP[temp_x][temp_y]=-1;
                }
                GameUtil.LEFT = false;//释放左键
            }
            if (GameUtil.RIGHT) {
                System.out.println(GameUtil.MOUSE_X);
                System.out.println(GameUtil.MOUSE_Y);
                GameUtil.RIGHT = false;//释放右键
            }
        }
    }
}

 运行结果:

Java扫雷游戏总结 (小项目)_第15张图片

十二、递归翻开

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {

    //判断逻辑
    void logic(){
        if(temp_x>=1 && temp_x<=GameUtil.MAP_W
                && temp_y>=1 && temp_y<=GameUtil.MAP_H) {
            if (GameUtil.LEFT) {
                if(GameUtil.DATA_TOP[temp_x][temp_y]==0){//左键点击覆盖格子,就把格子翻开
                    GameUtil.DATA_TOP[temp_x][temp_y]=-1;
                }
                spaceOpen(temp_x,temp_y);
            }
        }
    }
    //打开空格
    //此处用递归,递归打开点击处的空格周围相邻的所有空格
    void spaceOpen(int x,int y){
        if(GameUtil.DATA_BOTTOM[x][y]==0){//判断是否是空格
            for(int i=x-1;i<=x+1;i++){
                for(int j=y-1;j<=y+1;j++){
                    if(GameUtil.DATA_TOP[i][j]!=-1){//判断是否有覆盖,没有打开过的才可继续
                        GameUtil.DATA_TOP[i][j]=-1;//打开格子
                        if(i>=1 && j>=1 && i<=GameUtil.MAP_W && j<=GameUtil.MAP_H){//判断是否在雷区内
                            spaceOpen(i,j);//调用方法本身,是递归明显的特征
                        }
                    }
                }
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第16张图片

十三、右键插旗

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //判断逻辑
    void logic(){
        if(temp_x>=1 && temp_x<=GameUtil.MAP_W
                && temp_y>=1 && temp_y<=GameUtil.MAP_H) {
            if (GameUtil.RIGHT) {
                //覆盖则插旗
                if(GameUtil.DATA_TOP[temp_x][temp_y]==0){
                    GameUtil.DATA_TOP[temp_x][temp_y]=1;
                }
                //插旗则取消
                else if(GameUtil.DATA_TOP[temp_x][temp_y]==1){
                    GameUtil.DATA_TOP[temp_x][temp_y]=0;
                }
                GameUtil.RIGHT = false;//释放右键
            }
        }
    }
}

运行结果:

 Java扫雷游戏总结 (小项目)_第17张图片

十四、右键翻开

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //判断逻辑
    void logic(){
        if(temp_x>=1 && temp_x<=GameUtil.MAP_W
                && temp_y>=1 && temp_y<=GameUtil.MAP_H) {
            if (GameUtil.RIGHT) {
                //数字翻开
                else if(GameUtil.DATA_TOP[temp_x][temp_y]==-1){
                    numOpen(temp_x,temp_y);
                }
            }
        }
    }

    //数字翻开
    void numOpen(int x,int y){
        //记录旗数
        int count=0;
        if(GameUtil.DATA_BOTTOM[x][y]>0){
            for(int i=x-1;i<=x+1;i++){
                for(int j=y-1;j<=y+1;j++){
                    if(GameUtil.DATA_TOP[i][j]==1){
                        count++;
                    }
                }
            }
            if(count==GameUtil.DATA_BOTTOM[x][y]){//旗数等于翻开格子上的数字,此时右击数字,可以翻开一大块区域
                //循环遍历周围的格子并翻开,如果是空格就递归打开相邻的区域
                for(int i=x-1;i<=x+1;i++){
                    for(int j=y-1;j<=y+1;j++){
                        //翻开未插旗的格子
                        if(GameUtil.DATA_TOP[i][j]!=1){
                            GameUtil.DATA_TOP[i][j]=-1;
                        }
                        //递归翻开空格
                        if(i>=1 && j>=1 && i<=GameUtil.MAP_W && j<=GameUtil.MAP_H){//判断是否在雷区内
                            spaceOpen(i,j);//调用方法本身,是递归明显的特征
                        }
                    }
                }
            }
        }
    }
}

运行结果:

 Java扫雷游戏总结 (小项目)_第18张图片

十五、失败判定

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //判断逻辑
    void logic(){
       boom();
    }
    //失败判定 true:失败;false:未失败
    boolean boom(){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                //底层为雷,顶层无覆盖,即为游戏失败
                if(GameUtil.DATA_BOTTOM[i][j]==-1 && GameUtil.DATA_TOP[i][j]==-1){
                    System.out.println("fail");
                    seeBoom();
                    return true;
                }
            }
        }
        return false;
    }
    //失败后显示所有雷
    void seeBoom(){
        for(int i=1;i<=GameUtil.MAP_W;i++) {
            for (int j = 1; j <= GameUtil.MAP_H; j++) {
                //底层是雷,顶层未插旗,则翻开
                if(GameUtil.DATA_BOTTOM[i][j]==-1 && GameUtil.DATA_TOP[i][j]!=1){
                    GameUtil.DATA_TOP[i][j]=-1;
                }
                //底层不是雷,顶层插旗,显示差错旗
                if(GameUtil.DATA_BOTTOM[i][j]!=-1 && GameUtil.DATA_TOP[i][j]==1){
                    GameUtil.DATA_TOP[i][j]=2;
                }
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第19张图片

十六、胜利判定

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //判断逻辑
    void logic(){
        victory();
    }

    //胜利判断 t:胜利;f:未胜利
    boolean victory(){
        //统计未打开格子数
        int count=0;
        for(int i=1;i<=GameUtil.MAP_W;i++) {
            for (int j = 1; j <= GameUtil.MAP_H; j++) {
                if(GameUtil.DATA_TOP[i][j]!=-1){
                    count++;
                }
            }
        }
        //当未打开格子数等于雷数时,胜利
        if(count==GameUtil.RAY_MAX){
            System.out.println("success");
            for(int i=1;i<=GameUtil.MAP_W;i++) {
                for (int j = 1; j <= GameUtil.MAP_H; j++) {
                    //未翻开的格子全部插上旗
                    if(GameUtil.DATA_TOP[i][j]==0){
                        GameUtil.DATA_TOP[i][j]=1;
                    }
                }
            }
            return true;
        }
        return false;
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第20张图片

十七、游戏状态

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //游戏状态 0:游戏中;1:胜利;2:失败
    static int state=0;
    //载入图片
    static Image face=Toolkit.getDefaultToolkit().getImage("imgs/face.png");
    static Image over=Toolkit.getDefaultToolkit().getImage("imgs/over.png");
    static Image win=Toolkit.getDefaultToolkit().getImage("imgs/win.png");
}

6、MapBottom

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {
    //绘制方法
    void paintSelf(Graphics g){
        switch (GameUtil.state){
            case 0:
                g.drawImage(GameUtil.face,//游戏中
                        GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2),
                        GameUtil.OFFSET,
                        null);
                break;
            case 1:
                g.drawImage(GameUtil.win,//胜利
                        GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2),
                        GameUtil.OFFSET,
                        null);
                break;
            case 2:
                g.drawImage(GameUtil.over,//失败
                        GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2),
                        GameUtil.OFFSET,
                        null);
                break;
            default:
        }
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //失败判定,true:失败;false:未失败
    boolean boom(){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                if(GameUtil.DATA_BOTTOM[i][j]==-1 && GameUtil.DATA_TOP[i][j]==-1){
                    GameUtil.state=2;                }
            }
        }
        return false;
    }
   //胜利判断 t:胜利;f:未胜利
    boolean victory(){
        if(count==GameUtil.RAY_MAX){
            GameUtil.state=1;
        }
    }
}

运行结果:

失败:Java扫雷游戏总结 (小项目)_第21张图片

胜利:Java扫雷游戏总结 (小项目)_第22张图片

游戏中:Java扫雷游戏总结 (小项目)_第23张图片

十八、游戏重置

1、BottomNum

package com.study;

/**
 * 底层数据类
 */
public class BottomNum {
    void newNum(){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            //...
        }
    }
}

2、BottomRay

package com.study;

/**
 * 初始化地雷
 */
public class BottomRay {
    //生成雷
    void newRay(){
        for(int i=0;i

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    void launch(){//绘制窗口
        //鼠标事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                switch (GameUtil.state){
                    case 0:
                        if(e.getButton()==1){//点击鼠标左键
                            GameUtil.MOUSE_X=e.getX();
                            GameUtil.MOUSE_Y=e.getY();
                            GameUtil.LEFT=true;
                        }
                        if(e.getButton()==3){//点击鼠标右键
                            GameUtil.MOUSE_X=e.getX();
                            GameUtil.MOUSE_Y=e.getY();
                            GameUtil.RIGHT=true;
                        }
                    case 1:
                    case 2://在任何状态下,点击中间的图案都可以重置游戏
                        if(e.getButton()==1){
                            if(e.getX()>GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2)
                            && e.getX()GameUtil.OFFSET
                            && e.getY()

6、MapBottom

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {
    {
        //游戏初始化界面
        bottomRay.newRay();//生成雷
        bottomNum.newNum();//生成底层数字
    }

    //重置游戏
    void reGame(){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                GameUtil.DATA_BOTTOM[i][j]=0;
            }
        }
        bottomRay.newRay();
        bottomNum.newNum();
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {

    //格子位置
    int temp_x;
    int temp_y;

    //重置游戏
    void reGame(){
        for(int i=1;i<=GameUtil.MAP_W;i++){
            for(int j=1;j<=GameUtil.MAP_H;j++){
                GameUtil.DATA_TOP[i][j]=0;
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第24张图片

十九、数字添加

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //倒计时
    static long START_TIME;
    static long END_TIME;
    //绘制数字
    static void drawWord(Graphics g,String str,int x,int y,int size,Color color){
        g.setColor(color);
        g.setFont(new Font("仿宋",Font.BOLD,size));
        g.drawString(str,x,y);
    }
}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    void launch(){//绘制窗口
        GameUtil.START_TIME=System.currentTimeMillis();
        //鼠标事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                switch (GameUtil.state){
                    case 0:
                    case 1:
                    case 2://在任何状态下,点击中间的图案都可以重置游戏
                        if(e.getButton()==1){
                            if(e.getX()>GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2)
                            && e.getX()GameUtil.OFFSET
                            && e.getY()

6、MapBottom

package com.study;

import java.awt.*;

/**
 * 底层地图
 * 绘制游戏相关组件
 */
public class MapBottom {
    //绘制方法
    void paintSelf(Graphics g){
        //绘制数字,剩余雷数
        GameUtil.drawWord(g,""+(GameUtil.RAY_MAX-GameUtil.FLAG_NUM),
                GameUtil.OFFSET,
                2*GameUtil.OFFSET,
                30,
                Color.red);
        //绘制数字,倒计时
        GameUtil.drawWord(g,""+(GameUtil.END_TIME-GameUtil.START_TIME)/1000,
                GameUtil.OFFSET+GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W-1),
                2*GameUtil.OFFSET,
                30,
                Color.red);
        switch (GameUtil.state){
            case 0:
                GameUtil.END_TIME=System.currentTimeMillis();//实时刷新
        }
    }
}

7、MapTop

package com.study;

import java.awt.*;

/**
 * 顶层地图类
 * 绘制顶层组件
 * 判断逻辑
 */
public class MapTop {
    //判断逻辑
    void logic(){
        if(temp_x>=1 && temp_x<=GameUtil.MAP_W
                && temp_y>=1 && temp_y<=GameUtil.MAP_H) {
            if (GameUtil.RIGHT) {
                //覆盖则插旗
                if(GameUtil.DATA_TOP[temp_x][temp_y]==0){
                    GameUtil.FLAG_NUM++;
                }
                //插旗则取消
                else if(GameUtil.DATA_TOP[temp_x][temp_y]==1){
                    GameUtil.FLAG_NUM--;
                }
            }
        }
    }

    //失败判定,true:失败;false:未失败
    boolean boom(){
        //插旗数等于雷数
        if(GameUtil.FLAG_NUM==GameUtil.RAY_MAX){
            for(int i=1;i<=GameUtil.MAP_W;i++) {
                for (int j = 1; j <= GameUtil.MAP_H; j++) {
                    if(GameUtil.DATA_TOP[i][j]==0){
                        GameUtil.DATA_TOP[i][j]=-1;
                    }
                }
            }
        }
    }
    //打开空格
    //此处用递归,递归打开点击处的空格周围相邻的所有空格
    void spaceOpen(int x,int y){
        if(GameUtil.DATA_BOTTOM[x][y]==0){//判断是否是空格
            for(int i=x-1;i<=x+1;i++){
                for(int j=y-1;j<=y+1;j++){
                    if(GameUtil.DATA_TOP[i][j]!=-1){//判断是否有覆盖,没有打开过的才可继续
                        if(GameUtil.DATA_TOP[i][j]==1){
                            GameUtil.FLAG_NUM--;//释放旗子
                        }
                    }
                }
            }
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第25张图片

二十、难度选择

2、BottomRay

package com.study;

/**
 * 初始化地雷
 */
public class BottomRay {
    //存放坐标,改成static,初始化为最大值,后续可防止数组越界
    static int[] rays=new int[GameUtil.RAY_MAX*2];
}

3、GameSelect

package com.study;

import java.awt.*;

/**
 * 难度选择类
 */
public class GameSelect {

    //判断是否点击到难度
    boolean hard(){
        if(GameUtil.MOUSE_X>100 && GameUtil.MOUSE_X<400){
            if(GameUtil.MOUSE_Y>50 && GameUtil.MOUSE_Y<150){
                GameUtil.level=1;
                GameUtil.state=0;
                return true;
            }
            if(GameUtil.MOUSE_Y>200 && GameUtil.MOUSE_Y<300){
                GameUtil.level=2;
                GameUtil.state=0;
                return true;
            }
            if(GameUtil.MOUSE_Y>350 && GameUtil.MOUSE_Y<450){
                GameUtil.level=3;
                GameUtil.state=0;
                return true;
            }
        }
        return false;
    }

    void paintSelf(Graphics g){
        //难度选择的框用黑色线
        g.setColor(Color.black);
        g.drawRect(100,50,300,100);
        GameUtil.drawWord(g,"简单",220,100,30,Color.black);
        g.drawRect(100,200,300,100);
        GameUtil.drawWord(g,"普通",220,250,30,Color.black);
        g.drawRect(100,350,300,100);
        GameUtil.drawWord(g,"困难",220,400,30,Color.black);
    }

    void hard(int level){//方法重载:方法名相同,参数不同
        switch (level){
            case 1:
                GameUtil.RAY_MAX=10;
                GameUtil.MAP_W=9;
                GameUtil.MAP_H=9;
                break;
            case 2:
                GameUtil.RAY_MAX=40;
                GameUtil.MAP_W=16;
                GameUtil.MAP_H=16;
                break;
            case 3:
                GameUtil.RAY_MAX=99;
                GameUtil.MAP_W=30;
                GameUtil.MAP_H=16;
                break;
            default:
        }
    }
}

4、GameUtil

package com.study;

import java.awt.*;

/**
 * 工具类
 * 存放静态参数
 * 工具方法
 */
public class GameUtil {
    //游戏状态 0:游戏中;1:胜利;2:失败 3:难度选择
    static int state=3;
    //游戏难度 1:简单2:普通 3:困难
    static int level;
}

5、GameWin

package com.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * 绘制
 */
public class GameWin extends JFrame {
    GameSelect gameSelect=new GameSelect();

    //是否开始 f:未开始 t:开始
    boolean begin=false;
    void launch(){//绘制窗口
        if(GameUtil.state==3){
            this.setSize(500,500);//游戏难度选择窗口大小
        }else{
            this.setSize(width,height);//游戏界面窗口大小
        }
        //鼠标事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                switch (GameUtil.state){
                    case 0:
                    case 1:
                    case 2:
                        //在游戏重置时点击鼠标中间的滚轮可以再次选择难度
                        if(e.getButton()==2){
                            GameUtil.state=3;
                            begin=true;
                        }
                        break;
                    case 3://难度选择
                        if(e.getButton()==1){
                            GameUtil.MOUSE_X=e.getX();
                            GameUtil.MOUSE_Y=e.getY();
                            begin=gameSelect.hard();
                        }
                        break;
                    default:
                }

            }
        });

        while(true){
            begin();//时时刻刻在调用
        }
    }
    void begin(){
        if(begin){//是否开始游戏
            begin=false;//释放状态
            gameSelect.hard(GameUtil.level);
            dispose();//窗口关闭方式
            GameWin gameWin=new GameWin();
            GameUtil.START_TIME=System.currentTimeMillis();
            GameUtil.FLAG_NUM=0;
            mapBottom.reGame();
            mapTop.reGame();
            gameWin.launch();
        }
    }
    public void paint(Graphics g) {//绘制组件
        if (GameUtil.state == 3) {
            //难度选择窗口的背景颜色
            g.setColor(Color.white);
            g.fillRect(0,0,500,500);
            gameSelect.paintSelf(g);
        } else {
            //...
        }
    }
}

运行结果:

Java扫雷游戏总结 (小项目)_第26张图片Java扫雷游戏总结 (小项目)_第27张图片Java扫雷游戏总结 (小项目)_第28张图片

Java扫雷游戏总结 (小项目)_第29张图片

你可能感兴趣的:(java项目,java,游戏,开发语言)