最近資料結構已經邁入第三個作業了,所以在這邊我也把之前做的東西跟一些參考資料給放上來~
本篇這個版本是使用easyx這套繪圖引擎來幫忙製作的,這套繪圖引擎我很推薦大家使用,主要是因為使用上簡單,而且很適合教學!
程式碼的部分感覺起來好像很長,但其實還好有問題在留言即可~我想程式碼應該很好理解!在這邊說明一下這個程式碼是論壇中某位大大寫的,我再稍微修改一下裡面的內容~
運行環境VC2010
下載:
載點1 載點2
程式碼:
#include "graphics.h"
#include <conio.h>
#include <time.h>
//////////////////////////////////////////////////////
// 定義全局變量
//
BYTE** g_imgMap = 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(int* c); // 獲取用戶輸入的命令
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( !((GetCmd(&c) == CMD_QUIT) && Quit()) )
{
DispatchCmd(c);
Paint();
if (CheckWin())
break;
// 延時
Sleep(100);
}
// 清理迷宮地圖占用的內存
for(int x = 0; x < g_szMap.cx + 2; x++)
delete[] g_imgMap[x];
delete [] g_imgMap;
// 關閉圖形模式
closegraph();
}
// 繪製遊戲界面
void Welcome()
{
// 繪製漸變色外框
for(int i=0; i<128; i++)
{
setcolor(RGB((127 - i) << 1, 0, 0));
rectangle(149 - i, 109 - (i >> 1), 490 + i, 370 + (i >> 1));
}
// 設置字體樣式
setcolor(WHITE);
setbkmode(TRANSPARENT);
// 繪製標題
setfont(36, 0, _T("宋體"));
outtextxy(248, 40, _T("迷 宮"));
// 繪製操作說明
setfont(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);
setfillstyle(YELLOW);
setcolor(YELLOW);
fillellipse(2, 2, 17, 17);
setcolor(BLACK);
line(7, 7, 7, 8);//眼睛
line(12, 7, 12, 8);
arc(5, 6, 14, 14, 3.34, 6.08);//嘴巴
// 繪製墻壁
setorigin(MAP_WALL, 0);
setfillstyle(BROWN, PATTERN_FILL, "\x20\x20\x20\xff\x04\x04\x04\xff");
setcolor(BROWN);
bar(1, 1, 18, 18);
rectangle(0, 0, 19, 19);
// 繪製紅色標記
setorigin(MAP_MARKRED, 0);
setcolor(RED);
moveto(5, 15);
linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10);
// 繪製綠色標記
setorigin(MAP_MARKGREEN, 0);
setcolor(GREEN);
moveto(5, 15);
linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10);
// 繪製黃色標記
setorigin(MAP_MARKYELLOW, 0);
setcolor(YELLOW);
moveto(5, 15);
linerel(0, -10); linerel(5, 5); linerel(5, -5); linerel(0, 10);
// 繪製入口
setorigin(MAP_ENTRANCE, 0);
setcolor(GREEN);
setfont(12, 0, _T("宋體"));
outtextxy(4, 4, _T("入"));
// 繪製出口
setorigin(MAP_EXIT, 0);
outtextxy(4, 4, _T("出"));
// 繪製迷宮外面的空地
setorigin(MAP_OUTSIDE, 0);
setfillstyle(GREEN, PATTERN_FILL, "\x50\x55\x22\x20\x05\x55\x22\x02");
bar(0, 0, 19, 19);
// 恢復坐標系
setorigin(0, 0);
// 顯示作者
SetWorkingImage();
setcolor(BLUE);
TCHAR author[] = _T("Powered by qaz320232@gmail.com");
outtextxy(471, 4, author);
setcolor(LIGHTBLUE);
outtextxy(470, 3, author);
}
// 初始化遊戲數據
void InitGame()
{
// 提示用戶輸入迷宮大小
GetMazeSize();
// 初始化參數
if (g_imgMap != NULL)
{ // 清理迷宮地圖占用的內存
for(int x = 0; x < g_szMap.cx + 2; x++)
delete[] g_imgMap[x];
delete [] g_imgMap;
}
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 顯示區
setfillstyle(BLUE);
bar(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;
// 畫迷你地圖外框
setcolor(RED);
rectangle(g_ptGPS.x - 1, g_ptGPS.y - 1, g_ptGPS.x + g_szGPS.cx, g_ptGPS.y + g_szGPS.cy);
// 畫迷你地圖入口和出口
setcolor(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("請輸入迷宮的寬度\n範圍:20~200"), _T("輸入"), _T("25"));
g_szMap.cx = _ttoi(s);
}
while(g_szMap.cy < 20 || g_szMap.cx > 200)
{
InputBox(s, 4, _T("請輸入迷宮的高度\n範圍: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_imgMap = new BYTE*[width + 2];
for(x = 0; x < width + 2; x++)
{
g_imgMap[x] = new BYTE[height + 2];
memset(g_imgMap[x], MAP_WALL, height + 2);
}
// 定義邊界
for (x = 0; x <= width + 1; x++)
g_imgMap[x][0] = g_imgMap[x][height + 1] = MAP_GROUND;
for (y = 1; y <= height; y++)
g_imgMap[0][y] = g_imgMap[width + 1][y] = MAP_GROUND;
// 定義入口和出口
g_imgMap[1][2] = MAP_ENTRANCE;
g_imgMap[width][height - 1] = MAP_EXIT;
// 從任意點開始遍歷生成迷宮
TravelMaze(((rand() % (width - 1)) & 0xfffe) + 2, ((rand() % (height - 1)) & 0xfffe) + 2);
// 將邊界標記為迷宮外
for (x = 0; x <= width + 1; x++)
g_imgMap[x][0] = g_imgMap[x][height + 1] = MAP_OUTSIDE;
for (y = 1; y <= height; y++)
g_imgMap[0][y] = g_imgMap[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_imgMap[x][y] = MAP_GROUND;
for(i = 0; i < 4; i++)
if (g_imgMap[x + 2 * d[i][0]][y + 2 * d[i][1]] == 0)
{
g_imgMap[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_imgMap[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);
setcolor(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)
{
*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_imgMap[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("恭喜你走出來了!\n您想再來一局嗎?"), _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);
}
相關文章:
1.資料結構-老鼠走迷宮








沒有留言:
張貼留言
俗話說
凡走過必留下痕跡,凡住過必留下鄰居
凡爬過必留下樓梯,凡來過必留下IP
看過文章之後歡迎留下您寶貴的意見喔!