基于C语言实现迷宫游戏的示例代码
C语言迷宫游戏
这篇文章是给学完并学懂了C语言的分支(选择和循环)结构和二维数组的朋友看的。
要做一个游戏或者程序先要想好有那些要求,以下是我认为一个迷宫必带的要求:
- 迷宫要先打印出来(要设置墙、空气、小球的起点),是墙就不能,是空气就可以走。
- 每次输入'w'、'a'、's'、'd'为上、左、下、右,并每次输入后,不用按回车或任意键继续就能输出,每次走一步(按键盘的键走)后,先清屏再输出现在迷宫以及小球现在在哪里。
- 要有起点和终点的X、Y轴,如果小球与终点的位置相同了,就提示胜利并退出游戏。
定义地图
首先我们要打印出地图,因为地图有长和宽的长度,所以我们要用二维数组来定义一个地图,代码如下:
char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) };
打印地图方法一
定义完二维数组,就要把它打印出来,代码如下:
int i,j; for(i=0;i<6;i++)//i循环用来控制打印地图的行数 { for(j=0;j<6;j++)//j循环用来控制打印地图的列数 { printf("%c",map[i][j]);//打印每次i和j的行数和列数 } printf("\n");//一行打印完毕需要换行 }
打印地图方法二
上面这段代码是通过双重循环打印出地图的每行每列。
如果学过puts函数来输出字符数组的朋友可以这样写,代码如下:
int i; for(i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串
是不是简单了许多,不懂puts函数的朋友也没关系,你用第一种方法就行,对于puts函数你只需要知道:
- 使用 puts() 显示字符串时,系统会自动在其后添加一个换行符。
- 只有遇到 '\0' 也就是字符串结束标志符才会停止。
定义起点和终点位置
然后再定义起点和终点的X、Y轴位置(当然上面定义二维数组时已经看得出来了),代码如下:
?int x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 x=1;y=1;//x为竖轴初始位置为1,y为初始横轴位置为1 p=1;q=5;//p为竖轴结束位置为1,q为结束横轴位置为5
总结以上代码
目前为止,我们做了定义地图、打印地图、定义起点终点的X、Y轴,目前全部代码如下:
#include<stdio.h>//printf("");的头文件 #include<stdlib.h>//system("");的头文件 #include<Windows.h>//Sleep();的头文件 int m1ain(void) { char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) }; int i,x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 int ch;//申请需要输入的字符(名称是ch),当移动(w,a,s,d) x=1;y=1;p=1;q=5;//x为竖轴初始位置为1,y为初始横轴位置为1 //p为竖轴结束位置为1,q为结束横轴位置为5 for(i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串 Sleep(5000);//上面代码全部执行完毕后过五秒自动关闭程序 return 0; }
现在我们就要想办法控制小球了,这里利用键盘上的'w''s''a''d'四个键来控制这个小球进行上、下、左、右移动,当然你如果喜欢,也可以用别的按键。
第一步:先来控制小球向下移动,也就是当你按下's'键时,小球向下移动一步。
那么如何获得's'这个按键呢,换句话说:当你按下's'键时,我们的程序怎样知道你按的是's'键呢?
实现读取按键
很简单,因为你按下's'键时,本质上是输入了1个字符's',我们只需要读取这个字符's'就可以了,读取一个字符有4种方法:
char ch; scanf("%c",&ch);//读取一个字符,输入后等待用户按"Enter"键结束(带回显) ch=getchar;//读取一个字符,输入后等待用户按"Enter"键结束(带回显) ch=getche;//读取一个字符,输入后立即获取字符,不用按"Enter"键结束(带回显) ch=getch;//读取一个字符,输入后立即获取字符,不用按"Enter"键结束(不带回显)
而我们并不想显示输入的字符,并且希望输入的字符可以立即被程序获得,而不用在敲击一个字符后再敲击一个"Enter"键。
因此我们选用最后一个语句ch=getch();。
实现小球下向下移动一步
接下来,我们要把在键盘上敲击的字符存储在字符变量ch中,再接下来实现当敲击's'时。让小球向下移动一步,代码如下:
?if(ch=='s')//判断你是否输入(按)'s'这个字符 { if(map[x+1][y]!='#')//确认输入(按)的是's'时,就执行[x+1][y](往下走,x为竖轴,+1为往下,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O' } }
在上面代码中,我们通过if语句来判断敲击的字符是否是字符's',如果是字符's',我们就让小球向下移动一步,但在小球向下移动之前,需要首先判断下面一步是否能移动,只有下一步不是墙'#'时小球才能移动。
也就是说当if(map[x+1][y]!='#')条件成立时,就表示下一步不是墙,小球可以移动。
可能有些朋友会问:为什么[x+1][y]就表示向下走一部的格子呢?
其实很简单:向下移动时,小球当然还在当前这个列,不过不在这一行,而是在下一行,因此向下移动是y不变,x加1。
如果是向右边移动,很显然还是在同一行,所以x不变,但是小球已经不在刚才那一竖列了,而在右边的一个竖列,因此y需要加1。
总结小球移动规律
- 向下移动是y不变,x加1。
- 向上移动是y不变,x减1。
- 向左移动是x不变,y减1。
- 向右移动是x不变,y加1。
接下来我们来讲解下面这3句话的意思:
map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O'
让小球向下移动,就是让小球原本位置上的'O'变成空格,而让下一个空格变成'O'。
第一句:map[x][y]=' ';(注意此处两个单引号之间中间有一个空格)就是让小球的当前位置变为空格,
第二句:x++;这句话非常重要,它表示更改小球的位置,因为小球向下运动只需要x++就可以了,y不变。
第三句:a[x][y]='O';语句就是将小球新位置上的内容替换为小球'O'。
请注意上面一个代码,可不能写成:
map[x][y]=' '; map[x+1][y]='O';
至于为什么,大家自己去想想吧!
实现重新打印地图
因为小球的位置有了变化,因此还需要将新迷宫的状态重新打印一次,在打印之前记得要将之前的屏幕清屏,代码如下:
int i; system("cls");//每次移动了小球就清屏一次 for(i=0;i<6;i++)//清屏了再次循环输出新的地图 puts(map[i]);//清屏了再次输出新的地图
总结以上代码
?#include<stdio.h>//printf("");的头文件 #include<stdlib.h>//system("");的头文件 #include<Windows.h>//Sleep();的头文件 #include<conio.h>//getch();的头文件 int main(void) { char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) }; int i,x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 int ch;//申请需要输入的字符(名称是ch),当移动(w,a,s,d) x=1;y=1;p=1;q=5;//x为竖轴初始位置为1,y为初始横轴位置为1 //p为竖轴结束位置为1,q为结束横轴位置为5 for(i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串 ch=getch();//这语句表示给ch变量输入的字符可以立即被程序获取(不用按任意键继续),也不会回显 if (ch=='s')//判断你是否输入(按)'s'这个字符 { if (map[x+1][y]!='#')//确认输入(按)的是's'时,就执行[x+1][y](往下走,x为竖轴,+1为往下,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O' } } system("cls");//每次移动了小球就清屏一次 for(i=0;i<6;i++)//清屏了再次循环输出新的地图 puts(map[i]);//清屏了再次输出新的地图 Sleep(5000);//上面代码全部执行完毕后过五秒自动关闭程序 return 0; }
运行一下,然后按一下's'键,是不是已经可以看到小球向下移动了一步了呢?
但是你只能移动一步,如何实现连续移动呢?
实现连续移动
很简单,实现连续移动我们可以通过while循环来解决问题:
#include<stdio.h>//printf("");的头文件 #include<stdlib.h>//system("");的头文件 #include<Windows.h>//Sleep();的头文件 #include<conio.h>//getch();的头文件 int m1ain(void) { char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) }; int i,x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 int ch;//申请需要输入的字符(名称是ch),当移动(w,a,s,d) x=1;y=1;p=1;q=5;//x为竖轴初始位置为1,y为初始横轴位置为1 //p为竖轴结束位置为1,q为结束横轴位置为5 for(i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串 while(1)//暂时无限循环 { ch=getch();//这语句表示给ch变量输入的字符可以立即被程序获取(不用按任意键继续),也不会回显 if(ch=='s')//判断你是否输入(按)'s'这个字符 { if(map[x+1][y]!='#')//确认输入(按)的是's'时,就执行[x+1][y](往下走,x为竖轴,+1为往下,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O' } } system("cls");//每次移动了小球就清屏一次 for(i=0;i<6;i++)//清屏了再次循环输出新的地图 puts(map[i]);//清屏了再次输出新的地图 } Sleep(5000);//上面代码全部执行完毕后过五秒自动关闭程序 return 0; }
暂时先使用while(1)无限循环来解决这个问题,好了,运行一下吧。
此时小球是不是可以连续移动了?
当然,目前小球还只能朝一个方向运动,接下来我们来实现小球向其它3个方向的运动。
实现小球下向上下左右移动
向其它3个方向移动其实和"向下移动"是差不多的,只要注意是x在变化还是y在变化,是加1还是减1就可以了。无限移动4个方向代码如下:
#include<stdio.h>//printf("");的头文件 #include<stdlib.h>//system("");的头文件 #include<Windows.h>//Sleep();的头文件 #include<conio.h>//getch();的头文件 int m1ain(void) { char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) }; int i,x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 int ch;//申请需要输入的字符(名称是ch),当移动(w,a,s,d) x=1;y=1;p=1;q=5;//x为竖轴初始位置为1,y为初始横轴位置为1 //p为竖轴结束位置为1,q为结束横轴位置为5 for (i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串 while(1)//暂时无限循环 { ch=getch();//这语句表示给ch变量输入的字符可以立即被程序获取(不用按任意键继续),也不会回显 if(ch=='s')//判断你是否输入(按)'s'这个字符 { if(map[x+1][y]!='#')//确认输入(按)的是's'时,就执行[x+1][y](往下走,x为竖轴,+1为往下,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O' } } if(ch=='w')//判断你是否输入(按)'w'这个字符 { if(map[x-1][y]!='#')//确认输入(按)的是'w'时,就执行[x-1][y](往上走,x为竖轴,-1为往上,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往上走不是墙时,把当前的'O'输出成' ' x--;//为向上走 map[x][y]='O';//确认往上走不是墙时,把下一步的' '输出成'O' } } if(ch=='a')//判断你是否输入(按)'a'这个字符 { if(map[x][y-1]!='#')//确认输入(按)的是'a'时,就执行[x][y-1](往左走,y为横轴,-1为往左,x不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往左走不是墙时,把当前的'O'输出成' ' y--;//为向左走 map[x][y]='O';//确认往左走不是墙时,把下一步的' '输出成'O' } } if(ch=='d')//判断你是否输入(按)'d'这个字符 { if(map[x][y+1]!='#')//确认输入(按)的是'd'时,就执行[x][y-1](往右走,y为横轴,+1为往右,x不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往右走不是墙时,把当前的'O'输出成' ' y++;//为向右走 map[x][y]='O';//确认往右走不是墙时,把下一步的' '输出成'O' } } system("cls");//每次移动了小球就清屏一次 for(i=0;i<6;i++)//清屏了再次循环输出新的地图 puts(map[i]);//清屏了再次输出新的地图 } Sleep(5000);//上面代码全部执行完毕后过五秒自动关闭程序 return 0; }
好了,你是不是已经成功走出了迷宫?
可是貌似程序并没有让你很惊喜,因为没有判定你已经成功走出迷宫。
最后我们来写一个"获胜"的检测部分,其实只需要将我们之前写的while(1)改为while(x!=p||y!=q)就可以了。
实现小球走到终点就胜利
还记得吗,之前我们用p和q分别存储了迷宫出口的坐标位置,当然了,在最后我们需要打印"你获胜了"。完整代码如下:
#include<stdio.h>//printf("");的头文件 #include<stdlib.h>//system("");的头文件 #include<Windows.h>//Sleep();的头文件 #include<conio.h>//getch();的头文件 int m1ain(void) { printf("欢迎来到迷宫小游戏\n");//介绍这个迷宫游戏 printf("操作方式:\nw为往上走\ns为往下走\na为往左走\nd为往右走\n");//介绍操作方式 char map[50][50]={ "######",//申请50*50的二维字符串当迷宫地图,但这里是6*6的地图 "#O # ",//'#'是墙(不可以走的地方) "# ## #",//'O'是起点(可控制) "# # #",//' '是空气(可以走的地方) "## #", "######",//横竖都是012345,012345(数组下标从0开始) }; int i,x,y,p,q;//x,y为小球(起点"O")初始位置竖横轴 //p,q为空白(终点" ")结束位置竖横轴 int ch;//申请需要输入的字符(名称是ch),当移动(w,a,s,d) x=1;y=1;p=1;q=5;//x为竖轴初始位置为1,y为初始横轴位置为1 //p为竖轴结束位置为1,q为结束横轴位置为5 for(i=0;i<6;i++)//从0到5,共进行了6次循环,依次输出迷宫的第0至5行 puts(map[i]);//表示输出每一行的字符串 while (x!=p||y!=q)//只要x的值不等p或y的值不等q就无限循环 { ch=getch();//这语句表示给ch变量输入的字符可以立即被程序获取(不用按任意键继续),也不会回显 if(ch=='s')//判断你是否输入(按)'s'这个字符 { if(map[x+1][y]!='#')//确认输入(按)的是's'时,就执行[x+1][y](往下走,x为竖轴,+1为往下,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往下走不是墙时,把当前的'O'输出成' ' x++;//为向下走 map[x][y]='O';//确认往下走不是墙时,把下一步的' '输出成'O' } } if(ch=='w')//判断你是否输入(按)'w'这个字符 { if(map[x-1][y]!='#')//确认输入(按)的是'w'时,就执行[x-1][y](往上走,x为竖轴,-1为往上,y不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往上走不是墙时,把当前的'O'输出成' ' x--;//为向上走 map[x][y]='O';//确认往上走不是墙时,把下一步的' '输出成'O' } } if(ch=='a')//判断你是否输入(按)'a'这个字符 { if(map[x][y-1]!='#')//确认输入(按)的是'a'时,就执行[x][y-1](往左走,y为横轴,-1为往左,x不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往左走不是墙时,把当前的'O'输出成' ' y--;//为向左走 map[x][y]='O';//确认往左走不是墙时,把下一步的' '输出成'O' } } if(ch=='d')//判断你是否输入(按)'d'这个字符 { if(map[x][y+1]!='#')//确认输入(按)的是'd'时,就执行[x][y-1](往右走,y为横轴,+1为往右,x不变),提前是还要判断往下走是否为'#'(墙) { map[x][y]=' ';//确认往右走不是墙时,把当前的'O'输出成' ' y++;//为向右走 map[x][y]='O';//确认往右走不是墙时,把下一步的' '输出成'O' } } system("cls");//每次移动了小球就清屏一次 for(i=0;i<6;i++)//清屏了再次循环输出新的地图 puts(map[i]);//清屏了再次输出新的地图 } system("cls");//最后通关后清屏 printf("恭喜你赢了!\n");//最后通关后提示输出语句 Sleep(5000);//上面代码全部执行完毕后过五秒自动关闭程序 return 0; }