JAVA實現掃雷游戲


學習完java事件處理......老師要求寫個乞丐版掃雷......作為一只前端dog果斷不能慫阿,於是......

乞丐版掃雷

硬着頭皮寫出來了,參考了如下三份代碼:

乞丐版JAVA掃雷

Java語言實現的掃雷游戲(一)

Java語言實現的掃雷游戲(二)

先把代碼貼出來,需要注意的東西都寫在注釋里了,有空把教程寫出來

package sixth;

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

public class MineClearance {
    static private int midtime = 3600,mineNum = 0;/* 倒計時時間以及可用旗子數 */
    private static ImageIcon face = new ImageIcon("E:\\project\\JAVA\\test\\demo\\face.jpg");/* 小黃臉圖標 */
    static private JLabel label1,label2;/* 提示文字 */
    static private GamePanel gp;/* 雷區 */

    MineClearance(){
        /* 繪制窗口 */
        JFrame f = new JFrame("掃雷");
        f.setBounds(600,200,500,600);
        f.setDefaultCloseOperation(3);
        f.setLayout(null);
        label1 = new JLabel("剩余時間:" +(midtime / 60 / 60 % 60) + ":"+ (midtime / 60 % 60)+ ":" +(midtime % 60));
        label1.setBounds(10,20,120,20);
        f.add(label1);
        /* 顯示旗子數 */
        label2 = new JLabel("剩余:"+mineNum);
        label2.setBounds(400,20,120,20);
        f.add(label2);
        /* 重置按鈕 */
        JButton bt = new JButton(face);
        bt.setBounds(230, 15,30,30);
        bt.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                f.dispose();
                midtime = 3600;
                new MineClearance();
            }
        });
        f.add(bt);
        /* 繪制雷區 */
        gp = new GamePanel(20,20);
        gp.setBounds(40,100,400,400);
        f.add(gp);
        /* 顯示界面 */
        f.setVisible(true);
    }
    /* 倒計時線程 */
    static class CountDown extends Thread{
        public void run(){
            while (midtime > 0){
                try{
                    -- midtime;
                    label1.setText("剩余時間:" +(midtime / 60 / 60 % 60) + ":"+ (midtime / 60 % 60)+ ":" +(midtime % 60));
                    this.sleep(1000);
                }catch (Exception e){
                    System.out.println("錯誤:" + e.toString());
                }
            }
            if(midtime == 0) {
                gp.showBomb();
                JOptionPane.showMessageDialog(null,"時間已到","游戲結束",JOptionPane.PLAIN_MESSAGE);
            }
        }

    }
    public static void main(String[] args){
       new MineClearance();
       /* 倒計時 */
       CountDown cd = new CountDown();
       cd.start();
    }
    /* 修改旗子數 */
    public static void setMineNum(int i){
        mineNum = i;
        label2.setText("剩余:"+mineNum);
    }
}

class GamePanel extends JPanel {
    private int rows, cols, bombCount,flagNum;
    private final int BLOCKWIDTH = 20;
    private final int BLOCKHEIGHT = 20;
    private JLabel[][] label;
    private boolean[][] state;
    private Btn[][] btns;
    private byte[][] click;
    private static ImageIcon flag = new ImageIcon("E:\\project\\JAVA\\test\\demo\\flag.jpg");
    private static ImageIcon bomb = new ImageIcon("E:\\project\\JAVA\\test\\demo\\bomb.jpg");
    private static ImageIcon lucency = new ImageIcon("E:\\project\\JAVA\\test\\demo\\lucency.png");
    /* 構造雷區 */
    public GamePanel(int row, int col) {
        rows = row;/* 行數 */
        cols = col;/* 列數 */
        bombCount = rows * cols / 10; /* 地雷數 */
        flagNum = bombCount;/* 標記數(用於插旗) */
        label = new JLabel[rows][cols];
        state = new boolean[rows][cols];/* 用於存儲是否有地雷 */
        btns = new Btn[rows][cols];
        click = new byte[rows][cols];/* 用於存儲按鈕點擊狀態(0-未點擊,1-已點擊,2-未點擊但周圍有雷,3-插旗) */
        MineClearance.setMineNum(flagNum);
        setLayout(null);
        initLable();
        randomBomb();
        writeNumber();
        randomBtn();
    }

    public void initLable() {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                JLabel l = new JLabel("", JLabel.CENTER);
                // 設置每個小方格的邊界
                l.setBounds(j * BLOCKWIDTH, i * BLOCKHEIGHT, BLOCKWIDTH, BLOCKHEIGHT);
                // 繪制方格邊框
                l.setBorder(BorderFactory.createLineBorder(Color.GRAY));
                // 設置方格為透明,便於我們填充顏色
                l.setOpaque(true);
                // 背景填充為黃色
                l.setBackground(Color.lightGray);
                // 將方格加入到容器中(即面板JPanel)
                this.add(l);
                // 將方格存到類變量中,方便公用
                label[i][j] = l;
                label[i][j].setVisible(false);
            }
        }
    }

    /* 繪制地雷 */
    private void randomBomb() {
        for (int i = 0; i < bombCount; i++) {
            int rRow = (int) (Math.random() * rows);
            int rCol = (int) (Math.random() * cols);
            label[rRow][rCol].setIcon(bomb);
            state[rRow][rCol] = true;/* 有地雷的格子state為真 */
        }
    }

    /* 繪制數字 */
    private void writeNumber() {
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                if (state[i][j]) {
                    continue;
                }
                int bombCount = 0;
                /* 尋找以自己為中心的九個格子中的地雷數 */
                for (int r = -1; (r + i < rows) && (r < 2); ++r) {
                    if (r + i < 0) continue;
                    for (int c = -1; (c + j < cols) && (c < 2); ++c) {
                        if (c + j < 0) continue;
                        if (state[r + i][c + j]) ++bombCount;
                    }
                }
                if (bombCount > 0) {
                    click[i][j] = 2;
                    label[i][j].setText(String.valueOf(bombCount));
                }
            }
        }
    }
    /* 繪制按鈕 */
    private void randomBtn() {
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                Btn btn = new Btn();
                btn.i = i;
                btn.j = j;
                btn.setBounds(j * BLOCKWIDTH, i * BLOCKHEIGHT, BLOCKWIDTH, BLOCKHEIGHT);
                this.add(btn);
                btns[i][j] = btn;
                btn.addMouseListener(new MouseAdapter() {
                    public void mouseClicked(MouseEvent e) {
                        /* 左鍵點擊 */
                        if(e.getButton() == MouseEvent.BUTTON1) open(btn);
                        /* 右鍵點擊 */
                        if(e.getButton() == MouseEvent.BUTTON3) placeFlag(btn);
                    }

                }
                );

            }
        }

    }
    /* 打開這個雷區 */
    private void open(Btn b){
        /* 踩雷 */
        if(state[b.i][b.j]){
            for (int r = 0;r < rows;++r){
                for(int c = 0;c < cols; ++c){
                    btns[r][c].setVisible(false);/* 隱藏label */
                    label[r][c].setVisible(true);/* 顯示按鈕(這里只有隱藏了按鈕才能顯示按鈕下面的label) */
                }
            }
            JOptionPane.showMessageDialog(null,"您失敗了","游戲結束",JOptionPane.PLAIN_MESSAGE);
        }else /* 沒有踩雷 */{
            subopen(b);
        }
    }
    /* 遞歸打開周邊雷區 */
    private void subopen(Btn b){
        /* 有雷,不能打開 */
        if(state[b.i][b.j]) return;
        /* 打開過的和插旗的,不用打開 */
        if(click[b.i][b.j] == 1 || click[b.i][b.j] == 4) return;
        /* 周圍有雷的,只打開它 */
        if(click[b.i][b.j] == 2) {
            b.setVisible(false);
            label[b.i][b.j].setVisible(true);
            click[b.i][b.j] = 1;
            return;
        }
        /* 打開當前這個按鈕 */
        b.setVisible(false);
        label[b.i][b.j].setVisible(true);
        click[b.i][b.j] = 1;
        /* 遞歸檢測周邊八個按鈕 */
        for (int r = -1; (r + b.i < rows) && (r < 2); ++r) {
            if (r + b.i < 0) continue;
            for (int c = -1; (c + b.j < cols) && (c < 2); ++c) {
                if (c + b.j < 0) continue;
                if (r==0 && c==0) continue;
                Btn newbtn = btns[r + b.i][c + b.j];
                subopen(newbtn);
            }
        }
    }
    /* 插旗 */
    private void placeFlag(Btn b){
        /* 只能插和地雷數相同數目的旗子 */
        if(flagNum>0){
            /* 插過旗的,再點一次取消 */
            if(click[b.i][b.j] == 3){
                if(label[b.i][b.j].getText() == "[0-9]") click[b.i][b.j] = 2;
                else click[b.i][b.j] = 0;
                b.setIcon(lucency);
                ++ flagNum;
                MineClearance.setMineNum(flagNum);
            }else /* 未插旗的,插旗 */{
                b.setIcon(flag);
                click[b.i][b.j] = 3;
                -- flagNum;
                MineClearance.setMineNum(flagNum);
            }
            /* 把所有旗子插完了,檢測是否成功 */
            if(flagNum == 0){
                boolean flagstate = true;
                for(int i = 0;i < rows; ++i){
                    for(int j = 0;j < cols; ++j){
                        if (click[i][j] != 3 && state[i][j]) flagstate = false;
                    }
                }
                if(flagstate) JOptionPane.showMessageDialog(null,"您成功了","游戲結束",JOptionPane.PLAIN_MESSAGE);
            }
        }else /* 旗子用完了,不能插 */{
            JOptionPane.showMessageDialog(null,"標記已用盡","錯誤操作",JOptionPane.PLAIN_MESSAGE);
        }
    }
    /* 顯示雷區 */
    public void showBomb(){
        for (int r = 0;r < rows;++r){
            for(int c = 0;c < cols; ++c){
                btns[r][c].setVisible(false);/* 隱藏label */
                label[r][c].setVisible(true);/* 顯示按鈕(這里只有隱藏了按鈕才能顯示按鈕下面的label) */
            }
        }
    }
}

class Btn extends JButton{
    public int i,j;
}

需要用到的素材:

bomb.jpg bomb.jpg -- 用於顯示炸彈

face.jpg face.jpg -- 頂部中間那個酷酷的重置按鈕

flag.jpg flag.jpg -- 插的旗子

luncecy.jpg luncecy.png -- 你什么都看不到?那就對了,這是張純透明的圖片,用於再次右鍵有旗子的按鈕時把旗子替換成透明的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM