基于Java的Windows扫雷游戏的设计与实现
目 錄
摘 要 i
Abstract ii
1 緒論 1
1.1 課題背景及意義 1
1.2 開發工具的選用及介紹 1
1.3 選題目的和意義 2
1.4 本文主要研究的內容 2
2 需求分析 3
2.1 可行性分析 3
2.2 掃雷游戲功能描述 3
2.3 掃雷游戲用例圖 4
2.4 掃雷游戲功能需求 4
2.5 掃雷游戲界面需求 5
2.6 掃雷游戲功能模塊 6
3 游戲的概要分析與設計 7
3.1 設計構想 7
3.2 流程規劃 8
3.3 界面規劃 9
3.4 算法思想 9
4 游戲的詳細設計 11
4.1 游戲初始化 11
4.2 雷區的布置 12
4.3 游戲中主要模塊的介紹與使用 13
4.3.1 鼠標事件 13
4.3.2 地雷及雷區表面探測情況 14
4.3.3 清除未靠近地雷的格子 15
4.3.4 游戲難度的選擇 16
4.3.5 菜單欄的功能 16
4.4 游戲的判斷 16
4.4.1 游戲成功完成 16
4.4.2 游戲失敗 16
4.5 類設計 17
4.5.1 MineGame類 17
4.5.2 Block類 18
4.5.3 BlockView類 19
4.5.4 Record類 20
4.5.5 ShowRecord類 21
4.5.6 MineArea類 22
4.5.7 LayMines類 23
5 游戲實現 25
5.1 游戲難度自定義 25
5.2 掃雷 28
5.2.1 玩家通過右鍵進行掃雷,并顯示小紅旗 28
5.2.2 玩家因觸碰到雷而導致游戲結束 29
5.2.3 玩家掃雷成功 29
5.2.4 玩家游戲數據顯示 30
5.3 程序打包發布過程 32
6 游戲測試結果 33
6.1 游戲難度自定義測試 33
6.2 掃雷測試 35
6.3 玩家游戲數據顯示測試 37
6.4 游戲數據顯示區測試 39
6.5 遞歸算法測試 43
結 論 44
參考文獻 45
致 謝 47
外文原文 48
中文翻譯 55
1.4本文主要研究的內容
掃雷游戲風靡全球,受到很多人的喜愛。我研究了這個掃雷游戲之后,發現有兩個關鍵點:
第一點是鼠標事件的處理,包括鼠標點擊菜單項中按鈕的事件,點擊雷區中任意一格的事件,點擊界面上按鈕的事件等。
第二點是初始化雷區,包括隨機生成雷的位置,界面的初始化,計算周圍雷數等。
具體要求如下:
(1)掃雷游戲分為三種難度,分別是初、中、高級,點擊游戲左上角的“游戲”菜單后會出現“初級”、“中級”、“高級”三種選項。除此之外玩家還可以自定義難度。
(2)在玩家選擇難度之后游戲將會改變界面大小,并改變雷的總數。當玩家點開第一個格子時雷區開始布雷同時計時開始。
(3)若玩家想放棄本局游戲并重新開始的話,可以通過點擊掃雷信息統計區中的按鈕,來結束當前的游戲并開始新的游戲。
(4)當玩家認為某個格沒有雷,可以直接用鼠標單擊這個格或者把鼠標放在該格子上按下空格鍵。如果玩家的判斷是正確的,則會顯示周圍8個格子中地雷的總數,如果玩家判斷錯誤,該格子下藏著雷的話,游戲就好結束,系統自動彈框提示玩家失敗。
(5)若玩家認為某個格下有雷,在該格子上鼠標右鍵就可以標記一個玩家認為該格是雷的圖標,也就是在格子上標記一個小紅旗的圖案。玩家每標記一個紅旗(不管玩家的判斷正確與否),界面上的計數區都會把雷數減一。
(6)當所有的雷都標記正確后,游戲會自動彈框顯示“您真厲害,請輸入您的名字,記錄上榜!”。
(7)若玩家在游戲過程中單擊了有雷的格子,游戲失敗并且記時停止,游戲會將剩余的雷全部顯示出來,自動彈框顯示“你輸了,請繼續努力!”,之后玩家可以開始一局新的游戲。
(8)如果玩家不清楚游戲玩法,可以點擊菜單欄上的幫助來獲取游戲玩法及游戲竅門。
(9)對于自定義難度,系統會有一個閾值,行數在9到16之間,列數在9到30之間,地雷數在10到99之間。如果玩家設置的值超過該閾值,系統會自動將超過的數值變成閾值。
2.4掃雷游戲功能需求
本次掃雷設計需要實現的主要功能有:
(1)玩家可以選擇合適的游戲難度
點擊游戲界面左上角菜單欄中的“游戲”菜單,會出現出現“初級”、“中級”、“高級”、“自定義”四種選項。在玩家選擇難度之后游戲將會改變界面尺寸,并改變雷的總數。前三種雷數和尺寸都是固定的,無需玩家設置,而自定義則是玩家自己定義的。
(2)進行掃雷游戲
游戲界面包括菜單欄,游戲數據顯示區域以及雷區,當玩家點擊雷區中的任意一格的時候游戲開始,雷區開始隨機布雷,玩家需要在最短的時間內找出雷區中所有的地雷,并加以標識。
掃雷的基本操作包括鼠標左鍵單擊和右鍵單擊兩種。其中左鍵用來點開玩家認為不是雷的格子,右鍵標記玩家認為是雷的格子。
左鍵單擊:玩家在判斷出該格子下沒有雷時單擊該格子,可以將該格子點開。如果該格子周圍有雷就會顯示周圍雷的數目(由于周圍最多只有8個格子,所以最多只能顯示8);如果格子上什么也不顯示(也就是為空),系統就會自動調用遞歸的方法打開附近的格子。如果點到了有地雷的格子,那么游戲結束,系統顯示所有雷的位置。
右鍵單擊:玩家可以通過使用鼠標右鍵單擊來標記自己認為是雷的格子,通過標記可以有效的提高掃雷游戲的效率。本文轉載自http://www.biyezuopin.vip/onews.asp?id=11244再次右擊該格子可以取消標記,且格子被標記的時候鼠標單擊無效(防止玩家誤操作導致游戲失敗)。
(3)游戲計時
當點擊雷區任意一個格子的時候雷區開始布雷同時計時開始,計時標準是一秒增加1。如果游戲失敗時,則計時停止。如果玩家開始了新游戲,計時也會重新開始。
(4)標記地雷
當玩家認為格子下有雷時可以右擊格子來標記該格子,被標記的格子顯示小紅旗。再次右擊可以取消標記,且格子被標記的時候鼠標單擊無效(防止玩家誤操作導致游戲失敗)。如果玩家標識的地雷的數量超過了該難度下規定的雷數,計數區會以負數來顯示超過的雷數并且游戲不會結束。
(5)統計功能
當玩家游戲勝利后會彈框提示并可以輸入玩家的名字,確認后本次游戲的記錄會被保存。玩家可以點擊菜單欄上的“游戲”菜單,再點擊其中的“掃雷榜”即可查看游戲的最佳記錄。
(6)退出
點擊關閉按鈕可以結束游戲。
package cn.itbaizhan.mine;import java.awt.*; import java.awt.event.*; import javax.swing.*;public class MineArea extends JPanel implements ActionListener, MouseListener {JButton reStart;Block[][] block;BlockView[][] blockView;LayMines lay;int row, colum, mineCount, markMount;// 雷區的行數、列數以及地雷個數和用戶給出的標記數ImageIcon mark;int grade; // 初、中、高級JPanel pCenter, pNorth;JTextField showTime, showMarkedMineCount; // 顯示用時以及標記數Timer time; // 計時器int spendTime = 0;Record record;JDialog lose = new JDialog();JPanel panel;JLabel str; JButton restart1 = new JButton("重新開始");JButton cancel = new JButton("取消");public MineArea(int row, int colum, int mineCount, int grade) {reStart = new JButton("重新開始");mark = new ImageIcon("mark.png"); // 探雷標記time = new Timer(1000, this);showTime = new JTextField(5);showMarkedMineCount = new JTextField(5);showTime.setHorizontalAlignment(JTextField.CENTER);showTime.setFont(new Font("Arial", Font.BOLD, 16));showTime.setDisabledTextColor(java.awt.Color.black); // 設置字體顏色showTime.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.gray));// 設置邊框顏色showTime.setEnabled(false);// 設置不能響應用戶輸入showMarkedMineCount.setHorizontalAlignment(JTextField.CENTER);showMarkedMineCount.setFont(new Font("Arial", Font.BOLD, 16));showMarkedMineCount.setDisabledTextColor(java.awt.Color.black);showMarkedMineCount.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.gray));showMarkedMineCount.setEnabled(false);pCenter = new JPanel();pNorth = new JPanel();lay = new LayMines();initMineArea(row, colum, mineCount, grade); // 初始化雷區,見下面的LayMines()reStart.addActionListener(this);pNorth.add(showMarkedMineCount);pNorth.add(reStart);pNorth.add(showTime);setLayout(new BorderLayout());add(pNorth, BorderLayout.NORTH);add(pCenter, BorderLayout.CENTER);}public void initMineArea(int row, int colum, int mineCount, int grade) {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[i][j] = new Block();}//lay.layMinesForBlock(block, mineCount);blockView = new BlockView[row][colum];pCenter.setLayout(new GridLayout(row, colum));for (int i = 0; i < row; i++) {for (int j = 0; j < colum; j++) {blockView[i][j] = new BlockView();//blockView[i][j].giveView(block[i][j]); // 給block[i][j]提供視圖pCenter.add(blockView[i][j]);blockView[i][j].getBlockCover().addActionListener(this);blockView[i][j].getBlockCover().addMouseListener(this);blockView[i][j].seeBlockCover();blockView[i][j].getBlockCover().setEnabled(true);blockView[i][j].getBlockCover().setIcon(null);}}showMarkedMineCount.setText("" + markMount);validate();}public void initMine(int m, int n){lay.layMinesForBlock(block, mineCount, m, n);for (int i = 0; i < row; i++) {for (int j = 0; j < colum; j++) {blockView[i][j].giveView(block[i][j]);}}}public void setRow(int row) {this.row = row;}public void setColum(int colum) {this.colum = colum;}public void setMineCount(int mineCount) {this.mineCount = mineCount;}public void setGrade(int grade) {this.grade = grade;}public void actionPerformed(ActionEvent e) {if (e.getSource() == restart1) {initMineArea(row, colum, mineCount, grade);lose.dispose();return;}if (e.getSource() == cancel){lose.dispose();return;}int temp = 0;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(block[i][j].getIsMine() == true)temp = -1;if (e.getSource() == blockView[i][j].getBlockCover()) {m = i;n = j;}}}if(temp == 0)initMine(m, n);if (block[m][n].getIsMine()) {for (int i = 0; i < row; i++) {for (int j = 0; j < colum; j++) {blockView[i][j].getBlockCover().setEnabled(false);if (block[i][j].getIsMine())blockView[i][j].seeBlockNameOrIcon();}}panel = new JPanel();panel.setLayout(new FlowLayout());str = new JLabel("你輸了哦!", JLabel.CENTER);//restart1 = new JButton("重新開始");restart1.addActionListener(this);//cancel = new JButton("取消");cancel.addActionListener(this);lose.setTitle("輸了");lose.setBounds(300,100,200,150);lose.setResizable(false);lose.setVisible(false);lose.setModal(true);time.stop();spendTime = 0;markMount = mineCount;lose.add(str, BorderLayout.CENTER);panel.add(restart1);panel.add(cancel);lose.add(panel, BorderLayout.SOUTH);lose.setVisible(true);} else {show(m, n); // 見本類后面的show方法}}if (e.getSource() == reStart) {initMineArea(row, colum, mineCount, grade);}if (e.getSource() == time) {spendTime++;showTime.setText("" + spendTime);}inquireWin();}public void show(int m, int n) {if (block[m][n].getAroundMineNumber() > 0 && block[m][n].getIsOpen() == false) {blockView[m][n].seeBlockNameOrIcon();block[m][n].setIsOpen(true);return;} else if (block[m][n].getAroundMineNumber() == 0 && block[m][n].getIsOpen() == false) {blockView[m][n].seeBlockNameOrIcon();block[m][n].setIsOpen(true);for (int k = Math.max(m - 1, 0); k <= Math.min(m + 1, row - 1); k++) {for (int t = Math.max(n - 1, 0); t <= Math.min(n + 1, colum - 1); t++)show(k, t);}}}public void mousePressed(MouseEvent e) {JButton source = (JButton) e.getSource();for (int i = 0; i < row; i++) {for (int j = 0; j < colum; j++) {if (e.getModifiers() == InputEvent.BUTTON3_MASK && source == blockView[i][j].getBlockCover()) {if (block[i][j].getIsMark()) {source.setIcon(null);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);}}}}}public void inquireWin() {int number = 0;for (int i = 0; i < row; i++) {for (int j = 0; j < colum; j++) {if (block[i][j].getIsOpen() == false)number++;}}if (number == mineCount) {time.stop();record = new Record();switch (grade) {case 1:record.setGrade("初級");break;case 2:record.setGrade("中級");break;case 3:record.setGrade("高級");break;}record.setTime(spendTime);record.setVisible(true);}}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void mouseClicked(MouseEvent e) {} }
總結
以上是生活随笔為你收集整理的基于Java的Windows扫雷游戏的设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java基础的文件操作(File类)
- 下一篇: 经典Windows 扫雷小游戏源码 展示