老樣子,先上效果
?
?視頻演示
C++經典掃雷-介紹
一、引言
在這篇博客中,我將詳細介紹掃雷游戲項目的開發過程。掃雷作為一款經典的游戲,其規則簡單但富有挑戰性。通過開發這個項目,我不僅加深了對 C++ 編程的理解,還提升了自己處理圖形界面和游戲邏輯的能力。接下來,我將從項目概述、技術選型、核心代碼解析、功能實現、開發過程、測試與優化以及總結展望等方面進行詳細闡述。
項目下載獲取
點擊此處獲取掃雷項目安裝包和項目文件
開發者承諾文件安全,請放心下載!
二、項目概述
2.1 項目背景
掃雷游戲自 1992 年被微軟集成到 Windows 系統中后,便成為了一代人的經典回憶。游戲的目標是在一個網格中找出所有地雷,同時避免踩到它們。每點擊一個方塊,可能會顯示一個數字,表示周圍 8 個方塊中的地雷數量,或者直接踩到地雷導致游戲結束。
2.2 項目目標
本項目旨在使用 C++ 語言結合 EasyX 圖形庫開發一個完整的掃雷游戲。游戲應具備以下功能:
- 自定義地圖大小(4x4 到 60x60 之間)
- 隨機生成地雷分布
- 顯示周圍地雷數量
- 標記地雷功能
- 游戲計時和剩余地雷計數
- 游戲勝利和失敗判斷
- 友好的用戶界面和交互體驗
2.3 項目結構
項目采用面向對象的設計思想,主要由以下幾個模塊組成:
- 游戲管理模塊:負責游戲的整體流程控制和界面顯示
- 地圖邏輯模塊:處理地圖生成、地雷分布和游戲規則
- 文件操作模塊:讀取和保存游戲配置
- 數學輔助模塊:提供一些數學計算功能
具體文件結構如下:
Manage.h
?和?Manage.cpp
:游戲管理類BoomMap.h
?和?BoomMap.cpp
:地圖邏輯類MyFile.h
?和?MyFile.cpp
:文件操作類MyMath.h
:數學輔助類main.cpp
:程序入口
三、技術選型
3.1 編程語言
選擇 C++ 作為開發語言,主要基于以下原因:
- 高性能:C++ 是一種編譯型語言,執行效率高,適合處理游戲邏輯
- 面向對象:支持類和繼承,便于實現游戲的模塊化設計
- 廣泛的庫支持:可以使用各種圖形庫和工具
3.2 圖形庫
選擇 EasyX 圖形庫作為圖形界面開發工具,原因如下:
- 簡單易用:對于初學者友好,容易上手
- 與 C++ 兼容:無縫集成到 C++ 項目中
- 功能足夠:提供了基本的圖形繪制、圖像處理和鼠標鍵盤事件處理功能
3.3 開發環境
- 操作系統:Windows 10
- 開發工具:Visual Studio 2019
- 版本控制:Git
四、核心代碼解析
4.1 數據結構設計
// 2D點類,用于表示坐標 class _2D_Point { private:int x;int y; public:_2D_Point(int x = -1, int y = -1);int GetX() { return x; }int GetY() { return y; }void SetX(int x) { this->x = x; }void SetY(int y) { this->y = y; } };// 方塊狀態枚舉 enum BOOMSTATE {_BOOM_HIDE_0 = 0, // 未翻開_BOOM_SHOW_1 = 1, // 已翻開_BOOM_SIGN_2 = 2, // 標記為地雷_BOOM_DOUBT_3 = 3, // 標記為疑問_BOOM_WRONG_4 = 4, // 錯誤標記_BOOM_EXPLODE_5 = 5, // 爆炸地雷_BOOM_SHOWED_6 = 6 // 已顯示數字 };// 方塊類 class BoomSpace { public:bool existBoom; // 是否存在地雷int adjacentBooms; // 周圍地雷數量int state; // 當前狀態bool doubt; // 是否標記為疑問bool sign; // 是否標記為地雷bool isShowed; // 是否已顯示BoomSpace(); };
4.2 地圖生成與初始化
// 初始化地圖數據 void BoomMap::_initData() {currRightBoomNum = 0;currDisSpaceNum = 0; // 當前已顯示的空格數量currSignBoomNum = 0; // 當前標記的地雷數量// 隨機生成地雷int count = 0;srand(time(NULL));while (count != boomNum){int i = rand() % size;int j = rand() % size;if (map[i][j].existBoom == false){map[i][j].existBoom = true;count++;}}// 計算每個方塊周圍的地雷數量for (int i = 0; i < size; i++){for (int j = 0; j < size; j++){map[i][j].adjacentBooms = _getAdjacentBooms(i, j);}} }// 計算指定位置周圍的地雷數量 int BoomMap::_getAdjacentBooms(int i, int j) {int count = 0;for (int x = max(i - 1, 0); x <= min(i + 1, size - 1); x++){for (int y = max(j - 1, 0); y <= min(j + 1, size - 1); y++){if (x == i && y == j) continue;if (map[x][y].existBoom) count++;}}return count; }
4.3 游戲主循環與事件處理
// 游戲主循環 void Manage::Run() {while (1){BeginBatchDraw();_initSurface();_2D_Point msg_P = _mouseControl();// 處理開始游戲按鈕if (msg_P.GetX() == MOUSE_START){showButtonImg(_BUTTON_STARTGAME_DOWN_3, BUTTON_START_X1, BUTTON_START_Y1);Sleep(100);isStartGame = true;startTime = clock();}// 處理退出按鈕if (msg_P.GetY() == MOUSE_EXIT){if (isStartGame){int x = MessageBox(GetForegroundWindow(), "游戲尚未結束,你確定要退出嗎?", "退出提示", MB_OKCANCEL);if (x != IDCANCEL){break;}}else{break;}}// 處理鼠標點擊地圖if (msg_P.GetX() >= 0 && isStartGame && !gameOver && !isVictory){int i = msg_P.GetX();int j = msg_P.GetY();// 左鍵點擊:翻開方塊if (msg.uMsg == WM_LBUTTONDOWN){if (!(boomMap.map[i][j].doubt == 1 || boomMap.map[i][j].sign == 1)){GAMESTATUE flag = boomMap.display(i, j);if (flag == _GAME_OVER){_showAll(i, j);gameOver = true;}else if (flag == _GAME_VICTORY){_showMap();isVictory = true;}}}// 右鍵點擊:標記方塊else if (msg.uMsg == WM_RBUTTONDOWN){boomMap.changeSignState(i, j);}}// 顯示游戲信息_showGameInfo();EndBatchDraw();} }
五、功能實現
5.1 地圖大小自定義
用戶可以通過輸入框自定義地圖大小,程序會將設置保存到配置文件中:
// 讀取地圖大小配置 void readSize(int &size) {fstream file;file.open("initData.ini", std::ios::in | std::ios::binary);if (file.is_open()){file.read((char*)&size, sizeof(int));file.close();} }// 寫入地圖大小配置 void writeSize(int &size) {fstream file;file.open("initData.ini", std::ios::out | std::ios::binary);if (file.is_open()){file.write((char*)&size, sizeof(int));file.close();} }// 獲取用戶輸入的地圖大小 void intputSize(int& s) { input:char str[4];_InputBox(str, 4, "請輸入你要挑戰的地圖邊長!(4-60)");// 驗證輸入是否為數字bool isValid = true;for (int i = 0; i < strlen(str); i++){if (!('0' <= str[i] && str[i] <= '9')){isValid = false;break;}}if (!isValid){MessageBox(NULL, "你輸入的不是數字,請重新輸入!", "輸入錯誤", MB_OK);goto input;}int size = stoi(str);if (size < 4 || size > 60){MessageBox(NULL, "地圖邊長必須在4-60之間,請重新輸入!", "輸入錯誤", MB_OK);goto input;}s = size; }
5.2 游戲狀態管理
游戲有三種狀態:游戲中、游戲勝利和游戲失敗。程序會根據用戶的操作實時更新游戲狀態:
// 顯示方塊 GAMESTATUE BoomMap::display(int i, int j) {// 如果已經顯示或標記,則不處理if (map[i][j].isShowed || map[i][j].sign || map[i][j].doubt)return _GAME_CONTINUE;// 如果是地雷,游戲結束if (map[i][j].existBoom){map[i][j].state = _BOOM_EXPLODE_5;return _GAME_OVER;}// 顯示方塊map[i][j].isShowed = true;map[i][j].state = _BOOM_SHOWED_6;currDisSpaceNum++;// 如果周圍沒有地雷,遞歸顯示周圍的方塊if (map[i][j].adjacentBooms == 0){for (int x = max(i - 1, 0); x <= min(i + 1, size - 1); x++){for (int y = max(j - 1, 0); y <= min(j + 1, size - 1); y++){if (x == i && y == j) continue;display(x, y);}}}// 檢查是否游戲勝利if (currDisSpaceNum == spaceNum){// 自動標記剩余的地雷for (int i = 0; i < size; i++){for (int j = 0; j < size; j++){if (map[i][j].existBoom && !map[i][j].sign){map[i][j].sign = true;map[i][j].state = _BOOM_SIGN_2;currSignBoomNum++;currRightBoomNum++;}}}return _GAME_VICTORY;}return _GAME_CONTINUE; }
5.3 圖形界面實現
使用 EasyX 圖形庫實現游戲界面,包括加載圖片資源、繪制地圖和處理鼠標事件:
// 初始化界面 void Manage::_initSurface() {// 清屏cleardevice();// 繪制背景setbkcolor(EGERGB(240, 240, 240));cleardevice();// 繪制游戲標題settextcolor(BLACK);settextstyle(24, 0, _T("宋體"));outtextxy(10, 10, _T("掃雷游戲"));// 繪制按鈕if (isStartGame){showButtonImg(_BUTTON_STARTGAME_UP_2, BUTTON_START_X1, BUTTON_START_Y1);}else{showButtonImg(_BUTTON_STARTGAME_NORMAL_1, BUTTON_START_X1, BUTTON_START_Y1);}showButtonImg(_BUTTON_EXIT_NORMAL_1, BUTTON_EXIT_X1, BUTTON_EXIT_Y1);// 繪制地圖邊框setlinecolor(EGERGB(128, 128, 128));setlinestyle(PS_SOLID, 2);rectangle(MAP_X1, MAP_Y1, MAP_X2, MAP_Y2);// 繪制地圖if (isStartGame){_showMap();}else{_showCoverMap();} }
六、開發過程
6.1 需求分析與設計
在項目開始前,我對掃雷游戲的功能和流程進行了詳細分析,確定了游戲的基本需求和設計方案。這包括地圖生成算法、游戲狀態管理、用戶交互方式等。
6.2 模塊劃分與實現
根據設計方案,我將項目劃分為多個模塊,并逐步實現每個模塊的功能。首先實現了核心的地圖邏輯和游戲規則,然后添加了圖形界面和用戶交互功能,最后進行了整合和優化。
6.3 調試與測試
在開發過程中,我遇到了許多問題,如地圖生成算法不正確、鼠標事件處理不靈敏、游戲狀態判斷錯誤等。通過調試和測試,逐步解決了這些問題。我還編寫了一些測試用例,確保游戲在各種情況下都能正常運行。
6.4 優化與改進
在基本功能實現后,我對游戲進行了優化和改進,包括提高游戲性能、優化界面顯示、增強用戶體驗等方面。例如,添加了游戲計時和剩余地雷計數功能,優化了地圖顯示效果,改進了鼠標交互體驗等。
七、測試與優化
7.1 功能測試
對游戲的各項功能進行了全面測試,包括:
- 地圖生成是否隨機且正確
- 數字顯示是否準確反映周圍地雷數量
- 標記和取消標記功能是否正常
- 游戲勝利和失敗條件判斷是否正確
- 自定義地圖大小功能是否正常
7.2 性能測試
測試了游戲在不同地圖大小下的性能表現,發現當地圖較大時,游戲響應速度會有所下降。針對這個問題,我對地圖顯示和事件處理進行了優化,提高了游戲的運行效率。
7.3 用戶體驗優化
根據用戶反饋,對游戲界面和交互進行了優化,包括:
- 改進了圖片顯示效果,使界面更加美觀
- 添加了游戲狀態提示,如剩余地雷數和游戲時間
- 優化了鼠標交互,使操作更加流暢
- 添加了錯誤處理和提示,提高了程序的健壯性
八、總結與展望
8.1 項目成果
通過本次項目,我成功開發了一個功能完整、界面美觀的掃雷游戲。游戲支持自定義地圖大小,具有良好的用戶交互體驗,可以滿足玩家的基本需求。
8.2 技術收獲
在開發過程中,我學到了很多知識和技能,包括:
- 如何使用 C++ 和 EasyX 圖形庫開發圖形界面應用程序
- 面向對象編程思想在實際項目中的應用
- 游戲開發的基本流程和方法
- 如何進行代碼調試和性能優化
8.3 改進方向
盡管游戲已經具備了基本功能,但還有很多可以改進的地方,例如:
- 添加更多的游戲難度級別和預設地圖
- 實現游戲存檔和讀檔功能
- 添加音效和動畫效果,增強游戲體驗
- 優化算法,提高游戲性能
- 增加多人對戰功能,提升游戲趣味性
8.4 聲明
本文由 Go_Far_for_Dream (持夢遠方) 原創,轉載請注明出處。項目代碼僅供學習交流,請勿用于商業用途。
九、結束語
開發掃雷游戲是一次非常有意義的經歷,讓我對游戲開發有了更深入的理解。通過不斷學習和實踐,我相信自己可以開發出更加優秀的游戲作品。希望這篇博客對大家有所幫助,謝謝閱讀!