迷宮游戲其實有很多種類型,比如說營救公主的一款,又比如說闖關的一款,其他的一些種類這里就不一一列舉了。但是不管哪一款迷宮游戲,唯一不變的就是迷宮的實現這一核心功能,每一款迷宮游戲無非就是根據自己的游戲性質在迷宮之中添加一些必要的元素罷了。
我們今天的主要目標就是用C語言來實現迷宮的原本功能,純天然無污染,沒有添加任何防腐劑(因為沒有其他的花里胡哨的功能)
上面就是咱們的效果圖預覽,以圖形庫easyX來搭配C語言語法實現的迷宮界面,然后也實現了例如一些按鍵操作,邊界檢測這樣的功能,整體來說還是比較完善的。
本項目編譯環境:Visual Studio 2019/2022,EasyX插件
代碼展示:
#include#include #include ////////////////////////////////////////////////////// // 定義全局變量 // BYTE** g_aryMap = NULL; // 迷宮地圖 SIZE g_szMap; // 迷宮地圖的尺寸 IMAGE g_imgSight(360, 280); // 游戲的視野 RECT g_rtSight; // 游戲的視野的范圍 IMAGE g_imgItem(180, 20); // 地圖元素 IMAGE g_imgGPS; // 迷你地圖,用于顯示游戲者在地圖中的位置 POINT g_ptGPS; // 迷你地圖的顯示位置 SIZE g_szGPS; // 迷你地圖的尺寸 POINT g_ptPlayer; // 游戲者的位置 // 枚舉地圖元素,兼做元素位置的 x 坐標 enum MAPITEM { MAP_WALL = 0, MAP_PLAYER = 20, MAP_GROUND = 40, MAP_MARKRED = 60, MAP_MARKGREEN = 80, MAP_MARKYELLOW = 100, MAP_ENTRANCE = 120, MAP_EXIT = 140, MAP_OUTSIDE = 160 }; // 枚舉用戶的控制命令 enum CMD { CMD_QUIT = 1, CMD_UP = 2, CMD_DOWN = 4, CMD_LEFT = 8, CMD_RIGHT = 16, CMD_MARKRED = 32, CMD_MARKGREEN = 64, CMD_MARKYELLOW = 128, CMD_CLEARMARK = 256 }; ////////////////////////////////////////////////////// // 函數聲明 // void Welcome(); // 繪制游戲界面 void InitImage(); // 初始化游戲圖片 void InitGame(); // 初始化游戲數據 void GetMazeSize(); // 提示用戶輸入迷宮大小 void MakeMaze(int width, int height); // 生成迷宮:初始化(注:寬高必須是奇數) void TravelMaze(int x, int y); // 生成迷宮:遍歷 (x, y) 四周 MAPITEM GetMazeItem(int x, int y); // 獲取指定坐標的迷宮元素 void Paint(); // 繪制視野范圍內的迷宮 int GetCmd(); // 獲取用戶輸入的命令 void DispatchCmd(int cmd); // 處理用戶輸入的命令 void OnUp(); // 向上移動 void OnLeft(); // 向左移動 void OnRight(); // 向右移動 void OnDown(); // 向下移動 void OnMark(MAPITEM value); // 在地圖中做標記 bool CheckWin(); // 檢查是否到出口 bool Quit(); // 詢問用戶是否退出游戲 ////////////////////////////////////////////////////// // 函數定義 // // 主程序 void main() { // 初始化 initgraph(640, 480); // 創建繪圖窗口 srand((unsigned)time(NULL)); // 設置隨機種子 // 顯示主界面 Welcome(); // 初始化 InitImage(); InitGame(); // 游戲過程 int c; while( !(((c = GetCmd()) & CMD_QUIT) && Quit()) ) { DispatchCmd(c); Paint(); if (CheckWin()) break; // 延時 Sleep(100); } // 清理迷宮地圖占用的內存 for(int x = 0; x < g_szMap.cx + 2; x++) delete[] g_aryMap[x]; delete [] g_aryMap; // 關閉圖形模式 closegraph(); } // 繪制游戲界面 void Welcome() { // 繪制漸變色外框 for(int i=0; i<128; i++) { setlinecolor(RGB(0, 0, (127 - i) << 1)); rectangle(149 - i, 109 - (i >> 1), 490 + i, 370 + (i >> 1)); } // 設置字體樣式 settextcolor(WHITE); setbkmode(TRANSPARENT); // 繪制標題 settextstyle(36, 0, _T("宋體")); outtextxy(248, 40, _T("迷宮")); // 繪制操作說明 settextstyle(12, 0, _T("宋體")); outtextxy(50, 382, _T("控制說明:")); outtextxy(74, 400, _T("方向鍵或 A/S/D/W:移動")); outtextxy(74, 418, _T("空格、Y、G:在地圖上做紅、黃、綠色 M 標記")); outtextxy(74, 436, _T("C:清除地圖上的標記")); outtextxy(74, 454, _T("ESC:退出程序")); } // 初始化游戲圖片 void InitImage() { // 預繪制游戲圖片到 IMAGE 緩存(可以修改為加載圖片以獲得更好效果) SetWorkingImage(&g_imgItem); cleardevice(); // 繪制 PLAYER setorigin(MAP_PLAYER, 0); setfillcolor(YELLOW); setlinecolor(YELLOW); fillellipse(2, 2, 17, 17); setlinecolor(BLACK); line(7, 7, 7, 8); line(12, 7, 12, 8); arc(5, 6, 14, 14, 3.34, 6.08); // 繪制墻壁 setorigin(MAP_WALL, 0); settextcolor(BROWN); setfillstyle((BYTE*)"x20x20x20xffx04x04x04xff"); setlinecolor(BROWN); solidrectangle(1, 1, 18, 18); rectangle(0, 0, 19, 19); // 繪制紅色標記 setorigin(MAP_MARKRED, 0); setlinecolor(RED); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 繪制綠色標記 setorigin(MAP_MARKGREEN, 0); setlinecolor(GREEN); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 繪制黃色標記 setorigin(MAP_MARKYELLOW, 0); setlinecolor(YELLOW); moveto(5, 15); linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10); // 繪制入口 setorigin(MAP_ENTRANCE, 0); setlinecolor(GREEN); settextstyle(12, 0, _T("宋體")); outtextxy(4, 4, _T("入")); // 繪制出口 setorigin(MAP_EXIT, 0); outtextxy(4, 4, _T("出")); // 繪制迷宮外面的空地 setorigin(MAP_OUTSIDE, 0); settextcolor(GREEN); setfillstyle((BYTE*)"x50x55x22x20x05x55x22x02"); solidrectangle(0, 0, 19, 19); // 恢復坐標系 setorigin(0, 0); // 顯示作者 SetWorkingImage(); settextcolor(BLUE); TCHAR author[] = _T("Powered by zhaoh1987@qq.com"); outtextxy(471, 4, author); settextcolor(LIGHTBLUE); outtextxy(470, 3, author); } // 初始化游戲數據 void InitGame() { // 提示用戶輸入迷宮大小 GetMazeSize(); // 初始化參數 if (g_aryMap != NULL) { // 清理迷宮地圖占用的內存 for(int x = 0; x < g_szMap.cx + 2; x++) delete[] g_aryMap[x]; delete [] g_aryMap; } MakeMaze(g_szMap.cx, g_szMap.cy); // 創建迷宮 g_ptPlayer.x = 2; // 設置游戲者的位置 g_ptPlayer.y = 2; g_rtSight.left = 0; // 設置視野范圍 g_rtSight.top = 0; g_rtSight.right = 17; g_rtSight.bottom= 13; // 設置 GPS 顯示區 setfillcolor(BLUE); solidrectangle(522, 368, 637, 471); if (g_szMap.cx > g_szMap.cy) { g_szGPS.cx = 100; g_szGPS.cy = (int)(100.0 * g_szMap.cy / g_szMap.cx + 0.5); } else { g_szGPS.cy = 100; g_szGPS.cx = (int)(100.0 * g_szMap.cx / g_szMap.cy + 0.5); } Resize(&g_imgGPS, g_szGPS.cx, g_szGPS.cy); g_ptGPS.x = 530 + 50 - g_szGPS.cx / 2; g_ptGPS.y = 370 + 50 - g_szGPS.cy / 2; // 畫迷你地圖外框 setlinecolor(RED); rectangle(g_ptGPS.x - 1, g_ptGPS.y - 1, g_ptGPS.x + g_szGPS.cx, g_ptGPS.y + g_szGPS.cy); // 畫迷你地圖入口和出口 setlinecolor(YELLOW); moveto(g_ptGPS.x - 8, g_ptGPS.y + g_szGPS.cy / g_szMap.cy); linerel(7, 0); linerel(-3, -3); moverel(3, 3); linerel(-3, 3); moveto(g_ptGPS.x + g_szGPS.cx, g_ptGPS.y + g_szGPS.cy - g_szGPS.cy / g_szMap.cy); linerel(7, 0); linerel(-3, -3); moverel(3, 3); linerel(-3, 3); // 繪制游戲區 Paint(); } // 提示用戶輸入迷宮大小 void GetMazeSize() { g_szMap.cx = g_szMap.cy = 0; // 獲取用戶輸入的寬高 TCHAR s[4]; while(g_szMap.cx < 20 || g_szMap.cx > 200) { InputBox(s, 4, _T("請輸入迷宮的寬度 范圍:20~200"), _T("輸入"), _T("25")); g_szMap.cx = _ttoi(s); } while(g_szMap.cy < 20 || g_szMap.cx > 200) { InputBox(s, 4, _T("請輸入迷宮的高度 范圍:20~200"), _T("輸入"), _T("25")); g_szMap.cy = _ttoi(s); } // 確保寬高為奇數 if (g_szMap.cx % 2 != 1) g_szMap.cx++; if (g_szMap.cy % 2 != 1) g_szMap.cy++; } // 生成迷宮:初始化(注:寬高必須是奇數) void MakeMaze(int width, int height) { if (width % 2 != 1 || height % 2 != 1) return; int x, y; // 定義迷宮尺寸,并分配迷宮內存 g_aryMap = new BYTE*[width + 2]; for(x = 0; x < width + 2; x++) { g_aryMap[x] = new BYTE[height + 2]; memset(g_aryMap[x], MAP_WALL, height + 2); } // 定義邊界 for (x = 0; x <= width + 1; x++) g_aryMap[x][0] = g_aryMap[x][height + 1] = MAP_GROUND; for (y = 1; y <= height; y++) g_aryMap[0][y] = g_aryMap[width + 1][y] = MAP_GROUND; // 定義入口和出口 g_aryMap[1][2] = MAP_ENTRANCE; g_aryMap[width][height - 1] = MAP_EXIT; // 從任意點開始遍歷生成迷宮 TravelMaze(((rand() % (width - 1)) & 0xfffe) + 2, ((rand() % (height - 1)) & 0xfffe) + 2); // 將邊界標記為迷宮外 for (x = 0; x <= width + 1; x++) g_aryMap[x][0] = g_aryMap[x][height + 1] = MAP_OUTSIDE; for (y = 1; y <= height; y++) g_aryMap[0][y] = g_aryMap[width + 1][y] = MAP_OUTSIDE; } // 生成迷宮:遍歷 (x, y) 四周 void TravelMaze(int x, int y) { // 定義遍歷方向 int d[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; // 將遍歷方向亂序 int n, t, i; for(i = 0; i < 4; i++) { n = rand() % 4; t = d[i][0], d[i][0] = d[n][0], d[n][0] = t; t = d[i][1], d[i][1] = d[n][1], d[n][1] = t; } // 嘗試周圍四個方向 g_aryMap[x][y] = MAP_GROUND; for(i = 0; i < 4; i++) if (g_aryMap[x + 2 * d[i][0]][y + 2 * d[i][1]] == MAP_WALL) { g_aryMap[x + d[i][0]][y + d[i][1]] = MAP_GROUND; TravelMaze(x + d[i][0] * 2, y + d[i][1] * 2); // 遞歸 } } // 獲取指定坐標的迷宮元素 MAPITEM GetMazeItem(int x, int y) { return (MAPITEM)g_aryMap[x][y]; } // 繪制視野范圍內的迷宮 void Paint() { int x1, y1; // 繪制視野內的迷宮 SetWorkingImage(&g_imgSight); for(int x = g_rtSight.left; x <= g_rtSight.right; x++) for(int y = g_rtSight.top; y <= g_rtSight.bottom; y++) { x1 = (x - g_rtSight.left) * 20; y1 = (y - g_rtSight.top) * 20; putimage(x1, y1, 20, 20, &g_imgItem, GetMazeItem(x, y), 0); } // 繪制游戲者 x1 = (g_ptPlayer.x - g_rtSight.left) * 20; y1 = (g_ptPlayer.y - g_rtSight.top) * 20; putimage(x1, y1, 20, 20, &g_imgItem, MAP_PLAYER, 0); // 繪制迷你地圖 SetWorkingImage(&g_imgGPS); cleardevice(); int tx = (int)((g_ptPlayer.x - 1) * g_szGPS.cx / (double)(g_szMap.cx - 1) + 0.5); int ty = (int)((g_ptPlayer.y - 1) * g_szGPS.cy / (double)(g_szMap.cy - 1) + 0.5); setlinecolor(YELLOW); circle(tx, ty, 1); // 更新到繪圖窗口 SetWorkingImage(); putimage(150, 110, 340, 260, &g_imgSight, 10, 10); putimage(g_ptGPS.x, g_ptGPS.y, &g_imgGPS); } // 獲取用戶輸入的命令 int GetCmd() { int c = 0; if (GetAsyncKeyState(VK_LEFT) & 0x8000) c |= CMD_LEFT; if (GetAsyncKeyState(VK_RIGHT) & 0x8000) c |= CMD_RIGHT; if (GetAsyncKeyState(VK_UP) & 0x8000) c |= CMD_UP; if (GetAsyncKeyState(VK_DOWN) & 0x8000) c |= CMD_DOWN; if (GetAsyncKeyState('A') & 0x8000) c |= CMD_LEFT; if (GetAsyncKeyState('D') & 0x8000) c |= CMD_RIGHT; if (GetAsyncKeyState('W') & 0x8000) c |= CMD_UP; if (GetAsyncKeyState('S') & 0x8000) c |= CMD_DOWN; if (GetAsyncKeyState(' ') & 0x8000) c |= CMD_MARKRED; if (GetAsyncKeyState('G') & 0x8000) c |= CMD_MARKGREEN; if (GetAsyncKeyState('Y') & 0x8000) c |= CMD_MARKYELLOW; if (GetAsyncKeyState('C') & 0x8000) c |= CMD_CLEARMARK; if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) c |= CMD_QUIT; return c; } // 處理用戶輸入的命令 void DispatchCmd(int cmd) { if (cmd & CMD_UP) OnUp(); if (cmd & CMD_DOWN) OnDown(); if (cmd & CMD_LEFT) OnLeft(); if (cmd & CMD_RIGHT) OnRight(); if (cmd & CMD_MARKRED) OnMark(MAP_MARKRED); if (cmd & CMD_MARKGREEN) OnMark(MAP_MARKGREEN); if (cmd & CMD_MARKYELLOW) OnMark(MAP_MARKYELLOW); if (cmd & CMD_CLEARMARK) OnMark(MAP_GROUND); } // 向上移動 void OnUp() { if (g_ptPlayer.y > 1 && GetMazeItem(g_ptPlayer.x, g_ptPlayer.y - 1) != MAP_WALL) { g_ptPlayer.y--; if (g_ptPlayer.y - g_rtSight.top < 4 && g_rtSight.top > 0) { g_rtSight.top--; g_rtSight.bottom--; } } } // 向左移動 void OnLeft() { if (g_ptPlayer.x > 1 && GetMazeItem(g_ptPlayer.x - 1, g_ptPlayer.y) != MAP_WALL && GetMazeItem(g_ptPlayer.x - 1, g_ptPlayer.y) != MAP_ENTRANCE) { g_ptPlayer.x--; if (g_ptPlayer.x - g_rtSight.left < 5 && g_rtSight.left > 0) { g_rtSight.left--; g_rtSight.right--; } } } // 向右移動 void OnRight() { if (g_ptPlayer.x < g_szMap.cx && GetMazeItem(g_ptPlayer.x + 1, g_ptPlayer.y) != MAP_WALL) { g_ptPlayer.x++; if (g_rtSight.right - g_ptPlayer.x < 5 && g_rtSight.right <= g_szMap.cx) { g_rtSight.left++; g_rtSight.right++; } } } // 向下移動 void OnDown() { if (g_ptPlayer.y < g_szMap.cy && GetMazeItem(g_ptPlayer.x, g_ptPlayer.y + 1) != MAP_WALL) { g_ptPlayer.y++; if (g_rtSight.bottom - g_ptPlayer.y < 4 && g_rtSight.bottom <= g_szMap.cy) { g_rtSight.top++; g_rtSight.bottom++; } } } // 在地圖中做標記 void OnMark(MAPITEM value) { g_aryMap[g_ptPlayer.x][g_ptPlayer.y] = value; } // 檢查是否到出口 bool CheckWin() { if (g_ptPlayer.x == g_szMap.cx && g_ptPlayer.y == g_szMap.cy - 1) { HWND hwnd = GetHWnd(); if (MessageBox(hwnd, _T("恭喜你走出來了! 您想再來一局嗎?"), _T("恭喜"), MB_YESNO | MB_ICONQUESTION) == IDYES) { InitGame(); return false; } else return true; } return false; } // 詢問用戶是否退出游戲 bool Quit() { HWND hwnd = GetHWnd(); return (MessageBox(hwnd, _T("您確定要退出游戲嗎?"), _T("詢問"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK); }
大家趕緊去動手試試吧!
審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
游戲
+關注
關注
2文章
739瀏覽量
26288 -
C語言
+關注
關注
180文章
7601瀏覽量
136251 -
編程
+關注
關注
88文章
3596瀏覽量
93610 -
源碼
+關注
關注
8文章
633瀏覽量
29147
原文標題:C語言零基礎項目:迷宮游戲!詳細思路+源碼分享
文章出處:【微信號:cyuyanxuexi,微信公眾號:C語言編程學習基地】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
C語言零基礎項目:涂格子(點燈)游戲!詳細思路+源碼分享
點燈游戲是一個十分有趣的智力游戲:有一行N行N列的燈,開始時全部是滅的,當你點擊其中一盞燈時他的上下左右(若存在的話)狀態全部改變,現在要求你在限定的時間內以最少地步數,將全部的燈點亮。
發表于 12-16 09:47
?834次閱讀
C語言零基礎項目:俄羅斯方塊游戲!詳細思路+源碼分享
由小方塊組成的不同形狀的板塊陸續從屏幕上方落下來,玩家通過調整板塊的位置和方向,使它們在屏幕底部拼出完整的一條或幾條。這些完整的橫條會隨即消失,給新落下來的板塊騰出空間,與此同時,玩家得到分數獎勵。沒有被消除掉的方塊不斷堆積起來,一旦堆到屏幕頂端,玩家便告輸,游戲結束。
C語言零基礎項目:推箱子游戲!詳細思路+源碼分享
推箱子是一個來自日本的古老游戲,目的是在訓練你的邏輯思考能力。在一個狹小的倉庫中,要求把木箱放到指定的位置,稍不小心就會出現箱子無法移動或者通道被堵住的情況,所以需要巧妙的利用有限的空間和通道,合理安排移動的次序和位置,才能順利的完成任務。
C語言零基礎項目:黑白棋游戲!詳細思路+源碼分享
《黑白棋》也叫翻轉棋或者奧賽羅,其游戲過程是相互翻轉對方的棋子,最后以棋盤上誰的棋子多來判斷勝負。雖然規則簡單,但是變化復雜,是典型的易學難精,奧妙無窮,不信您就試試看吧!
C語言零基礎項目:對對碰(消除類)游戲!詳細思路+源碼分享
游戲中消除的對象為各種各樣的頭像,包括樹、小車、草莓和酒瓶等一些頭像。玩家通關移動這些頭像位置湊夠一定數量的相同圖標即可消除。
C語言項目:礦井逃生游戲(密室)!詳細思路+源碼分享
密室逃脫相信大部分都玩過了吧?本游戲就是一種用C語言寫的類似的游戲,因為用手電筒照明找路,所以有點像礦工的樣子,還是叫它礦井逃生吧!(以下是游戲
評論