走迷宫程序含自动迷宫生成.doc
-迷宫程序。执行效果如下:程序间有足够多的注释,就不多作介绍了。代码如下:/ 程序名称:迷宫游戏/ 编译环境:Visual C+ 6.0 / 2010,Easy* 2011惊蛰版/ 作者:krissi <zhaoh1987qq.>/ 最后修改:2011-3-12/#include <graphics.h>#include <conio.h>#include <time.h>/ 定义全局变量/BYTE*g_imgMap = NULL;/ 迷宫地图SIZEg_szMap;/ 迷宫地图的尺寸IMAGEg_imgSight(360, 280);/ 游戏的视野RECTg_rtSight;/ 游戏的视野的围IMAGEg_imgItem(180, 20);/ 地图元素IMAGEg_imgGPS;/ 迷你地图,用于显示游戏者在地图中的位置POINTg_ptGPS;/ 迷你地图的显示位置SIZEg_szGPS;/ 迷你地图的尺寸POINTg_ptPlayer;/ 游戏者的位置/ 枚举地图元素,兼做元素位置的 * 坐标enum MAPITEM MAP_WALL = 0, MAP_PLAYER = 20, MAP_GROUND = 40, MAP_MARKRED = 60, MAP_MARKGREEN = 80, MAP_MARKYELLOW = 100, MAP_ENTRANCE = 120, MAP_E*IT = 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 ;/ 函数声明/voidWele();/ 绘制游戏界面voidInitImage();/ 初始化游戏图片voidInitGame();/ 初始化游戏数据voidGetMazeSize();/ 提示用户输入迷宫大小voidMakeMaze(int width, int height);/ 生成迷宫:初始化注:宽高必须是奇数voidTravelMaze(int *, int y);/ 生成迷宫:遍历 (*, y) 四周MAPITEMGetMazeItem(int *, int y);/ 获取指定坐标的迷宫元素voidPaint();/ 绘制视野围的迷宫intGetCmd(int* c);/ 获取用户输入的命令voidDispatchCmd(int cmd);/ 处理用户输入的命令voidOnUp();/ 向上移动voidOnLeft();/ 向左移动voidOnRight();/ 向右移动voidOnDown();/ 向下移动voidOnMark(MAPITEM value);/ 在地图中做标记boolCheckWin();/ 检查是否到出口boolQuit();/ 询问用户是否退出游戏/ 函数定义/ 主程序void main()/ 初始化initgraph(640, 480);/ 创立绘图窗口srand(unsigned)time(NULL);/ 设置随机种子/ 显示主界面Wele();/ 初始化InitImage();InitGame();/ 游戏过程int c;while( !(GetCmd(&c) = CMD_QUIT) && Quit() )DispatchCmd(c);Paint();if (CheckWin()break;/ 延时Sleep(100);/ 清理迷宫地图占用的存for(int * = 0; * < g_szMap.c* + 2; *+)delete g_imgMap*;delete g_imgMap;/ 关闭图形模式closegraph();/ 绘制游戏界面void Wele()/ 绘制渐变色外框for(int i=0; i<128; i+)setcolor(RGB(0, 0, (127 - i) << 1);rectangle(149 - i, 109 - (i >> 1), 490 + i, 370 + (i >> 1);/ 设置字体样式setcolor(WHITE);setbkmode(TRANSPARENT);/ 绘制标题setfont(36, 0, _T("宋体");outte*t*y(248, 40, _T("迷宫");/ 绘制操作说明setfont(12, 0, _T("宋体");outte*t*y(50, 382, _T("控制说明:");outte*t*y(74, 400, _T("方向键或 A/S/D/W:移动");outte*t*y(74, 418, _T("空格、Y、G:在地图上做红、黄、绿色 M 标记");outte*t*y(74, 436, _T("C:去除地图上的标记");outte*t*y(74, 454, _T("ESC:退出程序");/ 初始化游戏图片void InitImage()/ 预绘制游戏图片到 IMAGE 缓存可以修改为加载图片以获得更好效果SetWorkingImage(&g_imgItem);cleardevice();/ 绘制 PLAYERsetorigin(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, "*20*20*20*ff*04*04*04*ff");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("宋体");outte*t*y(4, 4, _T("入");/ 绘制出口setorigin(MAP_E*IT, 0);outte*t*y(4, 4, _T("出");/ 绘制迷宫外面的空地setorigin(MAP_OUTSIDE, 0);setfillstyle(GREEN, PATTERN_FILL, "*50*55*22*20*05*55*22*02");bar(0, 0, 19, 19);/ 恢复坐标系setorigin(0, 0);/ 显示作者SetWorkingImage();setcolor(BLUE);TCHAR author = _T("Powered by zhaoh1987qq.");outte*t*y(471, 4, author);setcolor(LIGHTBLUE);outte*t*y(470, 3, author);/ 初始化游戏数据void InitGame()/ 提示用户输入迷宫大小GetMazeSize();/ 初始化参数if (g_imgMap != NULL)/ 清理迷宫地图占用的存for(int * = 0; * < g_szMap.c* + 2; *+)delete g_imgMap*;delete g_imgMap;MakeMaze(g_szMap.c*, g_szMap.cy);/ 创立迷宫g_ptPlayer.*= 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.c* > g_szMap.cy)g_szGPS.c* = 100; g_szGPS.cy = (int)(100.0 * g_szMap.cy / g_szMap.c* + 0.5);elseg_szGPS.cy = 100; g_szGPS.c* = (int)(100.0 * g_szMap.c* / g_szMap.cy + 0.5);Resize(&g_imgGPS, g_szGPS.c*, g_szGPS.cy);g_ptGPS.* = 530 + 50 - g_szGPS.c* / 2;g_ptGPS.y = 370 + 50 - g_szGPS.cy / 2;/ 画迷你地图外框setcolor(RED);rectangle(g_ptGPS.* - 1, g_ptGPS.y - 1, g_ptGPS.* + g_szGPS.c*, g_ptGPS.y + g_szGPS.cy);/ 画迷你地图入口和出口setcolor(YELLOW);moveto(g_ptGPS.* - 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.* + g_szGPS.c*, 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.c* = g_szMap.cy = 0;/ 获取用户输入的宽高TCHAR s4;while(g_szMap.c* < 20 | g_szMap.c* > 200)InputBo*(s, 4, _T("请输入迷宫的宽度n围:20200"), _T("输入"), _T("25");g_szMap.c* = _ttoi(s);while(g_szMap.cy < 20 | g_szMap.c* > 200)InputBo*(s, 4, _T("请输入迷宫的高度n围:20200"), _T("输入"), _T("25");g_szMap.cy = _ttoi(s);/ 确保宽高为奇数if (g_szMap.c* % 2 != 1) g_szMap.c*+;if (g_szMap.cy % 2 != 1) g_szMap.cy+;/ 生成迷宫:初始化注:宽高必须是奇数void MakeMaze(int width, int height)if (width % 2 != 1 | height % 2 != 1)return;int *, y;/ 定义迷宫尺寸,并分配迷宫存g_imgMap = new BYTE*width + 2;for(* = 0; * < width + 2; *+)g_imgMap* = new BYTEheight + 2;memset(g_imgMap*, MAP_WALL, height + 2);/ 定义边界for (* = 0; * <= width + 1; *+)g_imgMap*0 = g_imgMap*height + 1 = MAP_GROUND;for (y = 1; y <= height; y+)g_imgMap0y = g_imgMapwidth + 1y = MAP_GROUND;/ 定义入口和出口g_imgMap12 = MAP_ENTRANCE;g_imgMapwidthheight - 1 = MAP_E*IT;/ 从任意点开场遍历生成迷宫TravelMaze(rand() % (width - 1) & 0*fffe) + 2, (rand() % (height - 1) & 0*fffe) + 2);/ 将边界标记为迷宫外for (* = 0; * <= width + 1; *+)g_imgMap*0 = g_imgMap*height + 1 = MAP_OUTSIDE;for (y = 1; y <= height; y+)g_imgMap0y = g_imgMapwidth + 1y = MAP_OUTSIDE;/ 生成迷宫:遍历 (*, y) 四周void TravelMaze(int *, int y)/ 定义遍历方向int d42 = 0, 1, 1, 0, 0, -1, -1, 0;/ 将遍历方向乱序int n, t, i;for(i = 0; i < 4; i+)n = rand() % 4;t = di0, di0 = dn0, dn0 = t;t = di1, di1 = dn1, dn1 = t;/ 尝试周围四个方向g_imgMap*y = MAP_GROUND;for(i = 0; i < 4; i+)if (g_imgMap* + 2 * di0y + 2 * di1 = 0)g_imgMap* + di0y + di1 = MAP_GROUND;TravelMaze(* + di0 * 2, y + di1 * 2);/ 递归/ 获取指定坐标的迷宫元素MAPITEM GetMazeItem(int *, int y)return (MAPITEM)g_imgMap*y;/ 绘制视野围的迷宫void Paint()int *1, y1;/ 绘制视野的迷宫SetWorkingImage(&g_imgSight);for(int * = g_rtSight.left; * <= g_rtSight.right; *+)for(int y = g_rtSight.top; y <= g_rtSight.bottom; y+)*1 = (* - g_rtSight.left) * 20;y1 = (y - g_rtSight.top) * 20;putimage(*1, y1, 20, 20, &g_imgItem, GetMazeItem(*, y), 0);/ 绘制游戏者*1 = (g_ptPlayer.* - g_rtSight.left) * 20;y1 = (g_ptPlayer.y - g_rtSight.top) * 20;putimage(*1, y1, 20, 20, &g_imgItem, MAP_PLAYER, 0);/ 绘制迷你地图SetWorkingImage(&g_imgGPS);cleardevice();int t* = (int)(g_ptPlayer.* - 1) * g_szGPS.c* / (double)(g_szMap.c* - 1) + 0.5);int ty = (int)(g_ptPlayer.y - 1) * g_szGPS.cy / (double)(g_szMap.cy - 1) + 0.5);setcolor(YELLOW);circle(t*, ty, 1);/ 更新到绘图窗口SetWorkingImage();putimage(150, 110, 340, 260, &g_imgSight, 10, 10);putimage(g_ptGPS.*, g_ptGPS.y, &g_imgGPS);/ 获取用户输入的命令int GetCmd(int *c)*c = 0;if (GetAsyncKeyState(VK_LEFT)& 0*8000)*c |= CMD_LEFT;if (GetAsyncKeyState(VK_RIGHT)& 0*8000)*c |= CMD_RIGHT;if (GetAsyncKeyState(VK_UP)& 0*8000)*c |= CMD_UP;if (GetAsyncKeyState(VK_DOWN)& 0*8000)*c |= CMD_DOWN;if (GetAsyncKeyState('A')& 0*8000)*c |= CMD_LEFT;if (GetAsyncKeyState('D')& 0*8000)*c |= CMD_RIGHT;if (GetAsyncKeyState('W')& 0*8000)*c |= CMD_UP;if (GetAsyncKeyState('S')& 0*8000)*c |= CMD_DOWN;if (GetAsyncKeyState(' ')& 0*8000)*c |= CMD_MARKRED;if (GetAsyncKeyState('G')& 0*8000)*c |= CMD_MARKGREEN;if (GetAsyncKeyState('Y')& 0*8000)*c |= CMD_MARKYELLOW;if (GetAsyncKeyState('C')& 0*8000)*c |= CMD_CLEARMARK;if (GetAsyncKeyState(VK_ESCAPE)& 0*8000)*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.*, 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.* > 1 && GetMazeItem(g_ptPlayer.* - 1, g_ptPlayer.y) != MAP_WALL && GetMazeItem(g_ptPlayer.* - 1, g_ptPlayer.y) != MAP_ENTRANCE)g_ptPlayer.*-;if (g_ptPlayer.* - g_rtSight.left < 5 && g_rtSight.left > 0)g_rtSight.left-;g_rtSight.right-;/ 向右移动void OnRight()if (g_ptPlayer.* < g_szMap.c* && GetMazeItem(g_ptPlayer.* + 1, g_ptPlayer.y) != MAP_WALL)g_ptPlayer.*+;if (g_rtSight.right - g_ptPlayer.* < 5 && g_rtSight.right <= g_szMap.c*)g_rtSight.left+;g_rtSight.right+;/ 向下移动void OnDown()if (g_ptPlayer.y < g_szMap.cy && GetMazeItem(g_ptPlayer.*, 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_imgMapg_ptPlayer.*g_ptPlayer.y = value;/ 检查是否到出口bool CheckWin()if (g_ptPlayer.* = g_szMap.c* && g_ptPlayer.y = g_szMap.cy - 1)HWND hwnd = GetHWnd();if (MessageBo*(hwnd, _T("恭喜你走出来了!n您想再来一局吗?"), _T("恭喜"), MB_YESNO | MB_ICONQUESTION) = IDYES)InitGame();return false;elsereturn true;return false;/ 询问用户是否退出游戏bool Quit()HWND hwnd = GetHWnd();return (MessageBo*(hwnd, _T("您确定要退出游戏吗?"), _T("询问"), MB_OKCANCEL | MB_ICONQUESTION) = IDOK);. z.