利用深度优先搜索做的随机生成地图的迷宫小游戏

来源:互联网 发布:留学新加坡 知乎 编辑:程序博客网 时间:2024/05/23 07:23

好久没有发布作品写博客了。CSDN代码排版还是那么蛋疼。。

上个星期老师留的作业,做一个迷宫的小游戏。那时候刚刚会自己画地图来做迷宫。

后来觉得好麻烦好麻烦就想要他随机生成地图。

而后就在网上找了很多资料进行研究实验学习。(也有些精华借鉴)

如今做出还不完美,界面奇丑的迷宫小游戏~大家凑合看哈~


文件我分成了三个部分,头文件labyrinth.h、函数文件fun.c和主函数文件main.c


具体都做了很多注释可自行研究。


环境:visual studio 2013


下面是头文件代码

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <time.h>#include <windows.h>#define MAZE_MAX 100//最大上限#define UPWARD 0//上,下,左,右#define DOWN 1#define LEFT 2#define RIGHT 3enum bool{false, true};char map[MAZE_MAX + 2][MAZE_MAX + 2];//+2是因为在绘制地图前,会将图周围置零防止围墙被挖断。//所以要+2来弥补扔掉的外围一圈墙。且因为用了宽字符来输出字符,所以为2倍长度unsigned int size;//地图大小  随意设置UINT x, y;//用于人物控制的坐标变量void WriteChar(int Wide, int High, char* pszChar);//坐标函数void menu_ui(void);//菜单界面int menu_s(void);//菜单选择void print_maze();//打印地图void make_maze();//地图绘制int search_path(int x, int y);//寻路void init_wall();//填充墙int control();//控制void person(UCHAR dirct_flag, int coords);void console();//设置控制台大小的动画


下面是 函数文件

#include "labyrinth.h"/*// 打印字符到控制台指定位置// 参数1 : 宽度 X// 参数2 : 高度 Y// 参数3 : 打印的字符*/void WriteChar(int x, int y, char* pszChar){CONSOLE_CURSOR_INFO cci;cci.dwSize = 1;cci.bVisible = FALSE;  // 是否显示光标SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);COORD loc;loc.X = x;loc.Y = y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), loc);printf(pszChar);}//菜单UIvoid menu_ui(void){printf("\n\n\n\n");printf("\t\t╔----------------------------------------------╗\n");printf("\t\t |\t\t欢迎来到迷宫游戏!\t\t|\n");printf("\t\t |\t\t\t\t\t\t|\n");printf("\t\t |\t\t   进入游戏\t\t\t|\n");printf("\t\t |\t\t   退出游戏\t\t\t|\n");printf("\t\t |\t\t\t\t\t\t|\n");printf("\t\t |\t\t 注:用方向键选择\t\t|\n");printf("\t\t |\t\t\t\t\t\t|\n");printf("\t\t╚----------------------------------------------╝\n");}/*** 菜单选择** Y = 7 & 8** X = 33 & 34** 参数返回:菜单选择状态**上光标:72**下光标:80**左光标:75**右光标:77*/int menu_s(void){char select = 0;unsigned int y = 7;unsigned int x = 33;WriteChar(x, y, "-");//是指示标“->”初始位置WriteChar(x + 1, y, ">");while (1){if (_kbhit()){select = _getch();if (select == 0x48)//若按上键,指示标向上移动{WriteChar(x, y, " ");//清除WriteChar(x + 1, y, " ");--y;if (y < 7){y = 8;}WriteChar(x, y, "-");WriteChar(x + 1, y, ">");}else if (select == 0x50)//若按下键,指示标向下移动{WriteChar(x, y, " ");WriteChar(x + 1, y, " ");++y;if (y > 8){y = 7;}WriteChar(x, y, "-");WriteChar(x + 1, y, ">");}else//若为回车,当前菜单功能码{if (select == 0x0D){return y >> 2;//计算出菜单选择码}}}}}//打印地图void print_maze(){unsigned int z1, z2;for (z1 = 0; z1 <= size * 2 + 2; ++z1){for (z2 = 0; z2 <= size * 2 + 2; ++z2){fputs(map[z1][z2] == 0 ? "  " : "※", stdout);}putchar(10);//换行}printf("\n\n");printf("注:方向键控制人物移动.ESC退出游戏。\n");printf("    F1重设地图大小,F2重新生成地图\n");}//地图绘制void make_maze(){map[2][1] = 0;//设置出入口map[size * 2][size * 2 + 1] = 0;//加一是后来补充的一层墙srand((unsigned)time(NULL));search_path(rand() % size + 1, rand() % size + 1);//初始随机选点挖洞}//寻路int search_path(int y, int x){int dir[4][2] = { { 0, 1 },//方向坐标目录{ 1, 0 },{ 0, -1 },{ -1, 0 } };int xx = x * 2;int yy = y * 2;int turn = rand() % 2 ? 1 : 3;//奇数都可,若为偶数则会出现相同int next = rand() % 4;//初始随机方向map[yy][xx] = 0;//挖洞起点for (int i = 0; i < 4; ++i, next = (next + turn) % 4)//next每次在0,1,2,3范围循环变换{if (map[yy + 2 * dir[next][0]][xx + 2 * dir[next][1]])//探测间接结点是否已开通{map[yy + dir[next][0]][xx + dir[next][1]] = 0;//挖洞search_path(y + dir[next][0], x + dir[next][1]);}}return 0;}//填充墙体void init_wall(){unsigned int z1, z2;for (z1 = 0; z1 < size * 2 + 2; ++z1)//填充墙体{for (z2 = 0; z2 < size * 2 + 2; ++z2){map[z1][z2] = 1;}}for (z1 = 0, z2 = size * 2 + 2; z1 <= z2; ++z1)//设置边框{//防止挖开围墙map[z1][0] = 0;//因为寻路是根据间接点来判断map[z1][z2] = 0;map[0][z1] = 0;map[z2][z1] = 0;}}//控制int control(){char key_flag = 0;//按键状态x = 1;//横坐标y = 2;//纵坐标WriteChar(2 * x, y, "♀");//设置起始人物位置及终点标记WriteChar(size * 4 + 2, size * 2, "★");//*4为宽字符原因while (1){key_flag = _getch();if (key_flag != 0x1B){key_flag = _getch();}switch (key_flag){case 0x48://上person(UPWARD, -1);break;case 0x50://下person(DOWN, 1);break;case 0x4B://左person(LEFT, -1);break;case 0x4D://右person(RIGHT, 1);break;case 0x3B://F1键:重设地图大小return 0;case 0x3C://F2键:重新生成地图return 1;case 0x1B://ESC键:回到主界面return 2;}if ((x == size * 2 + 1) && (y == size * 2)){system("cls");WriteChar(size * 2, size, "恭喜你!已经通关!");WriteChar(size * 2, size + 1, "按任意键退出!");while (1){if (_kbhit()){exit(0);}}}}return -1;}//人物移动void person(UCHAR dirct_flag, int coords){switch (dirct_flag){case UPWARD://上case DOWN://下if ((map[y + coords][x] != 1)){WriteChar(x * 2, y, " ");//擦除上个位置y += coords;WriteChar(x * 2, y, "♀");//写入下一位置}break;case RIGHT://左case LEFT://右if ((map[y][x + coords] != 1) && (x + coords != 0)){WriteChar(x * 2, y, " ");//擦除上个位置x += coords;WriteChar(x * 2, y, "♀");//写入下一位置}break;}}//设置控制台窗口大小的动画void console(){int x, y;x = 0;y = 1;HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出设备句柄PCONSOLE_SCREEN_BUFFER_INFO bInfo = (PCONSOLE_SCREEN_BUFFER_INFO)malloc(sizeof(CONSOLE_SCREEN_BUFFER_INFO));//窗口缓冲区信息for (; y < 40; x+=4, ++y){COORD size = { x, y };SMALL_RECT rc = { 0, 0, x - 1, y - 1 };//重置窗口位置和大小SetConsoleWindowInfo(hOut, true, &rc);Sleep(50);}}


下面是 主函数文件

#include "labyrinth.h"int main(){int mfalg = 0;int ctrl_flag = 0;//用来接收控制字符状态console();//设置控制台窗口srand((unsigned)time(NULL));system("cls");system("color 2");menu_ui();//调出界面mfalg = menu_s();//获取菜单选择码while (1){if (mfalg == 1)//通过菜单码执行相应功能,1为开始游戏{switch (ctrl_flag)//通过控制状态来执行相应功能{case 0://初始默认/F1键:重设地图大小system("cls");printf("地图为正方形,请输入一条边长\n");printf("请输入要设置的地图大小(小于50):");do{scanf_s("",);} while (size > 50);fflush(stdin);case 1://F2键:重新生成地图system("cls");init_wall();//填充墙体make_maze();//绘制print_maze();//打印ctrl_flag = control();//控制人物及各种功能break;case 2://ESC键:回到主界面system("cls");system("color 2");menu_ui();//调出界面mfalg = menu_s();//获取菜单选择码ctrl_flag = 0;//初始化控制状态break;}}else{system("cls");return 0;}}}


好了,就是这样的~其中数据层迷宫和显示层迷宫数据对应的调试有些困难。


下面是效果图




0 0
原创粉丝点击