解析《啊哈C》--最终章:用C语言制作走迷宫和推箱子的小游戏
啊哈C语言:第8章 《游戏时间到了》-----2020/4/10
从2月底开始直到前天,当我学完二维字符数组、字典序后,翻到这一章的页面时,心情是欢喜的,我想一件坚持了很久的事情做到了最后关头,都是付出的时间、精力的成果!开心心!
而一个多月坚持独立思考的成果终于要检验了!相对于之前写过的程序,一个具有可操作性可玩性的游戏,是一种更加具象化的成果体现,也更加有成就感!!
下面就是正文啦!
第一个游戏:走迷宫!
使用井号‘#’制作迷宫的宫墙,将大写字母‘O’当作小球,作为玩家操作的对象,右侧宫墙有一处缺口是终点,通过W S A D四个按键分别控制小球进行上、下、左、右的移动。
玩法是进入游戏操作小球从起始位置移动到终点即为游戏胜利。
迷宫主体全部使用 ‘ # ’组成,井号在C语言中属于字符,这让我们联想到使用一行行的字符串打印迷宫。那就是多行字符,所以应该要用上一章刚学的二维字符数组来打印这个地图!
观察地图的行列,一共有20行30列,每行字符串末尾有一个结束标记,所以定义二维字符数组a为:char a[20][31] ……后面按照迷宫的结构,初始化迷宫,每行无 # 处用空格键隔开,注意每行细节不能错。
效果如下:
char a[50][50]={"##############################",
"#O # ## # ### ####",
"# ###### # # # # # ### ####",
"# # ## # # #### # ### ##",
"# # ## ### # # ## ####",
"##### # # ##### ## ####",
"# # ##### # # # # # #",
"# # # ## # #### ## # # ####",
"# # # ## ## # # ####",
"# # # ####### ## ###### # ##",
"# # ## # ## ###### ### #",
"# ###### # ##### # # #",
"# # # ##### ### # ",
"# ######## ##### # ### ### # #",
"# # ## ##### ### ###",
"##### # ## # ######## # #",
"# # ## ## ### # #",
"# # ### ###### ####### #",
"# # ### ## # #",
"##############################"};
注意字符串从0开始计数。之所以定义51行49列,因为方便。
而地图本身的20行30列准确定义为 a [19] [30] 中 20是行X表示20行,30是
列Y表示30列。
故理解行列为XY后,我们利用a [x] [y] 可以通过x、y来表示地图中任意位置。
故小球O 的位置是a[1][1],终点出口的位置是a[12][30]
故我们使用x=1;y=1存储小球起始位置,p=12;g=30存储终点位置
提前定义完xypg的值,还需要一个 i 来控制输出地图的for循环。
int i,x,y,p,q;
char ch;
x=1;y=1;p=12;q=30;
主要操作是控制小球移动,WASD四个按键,本质其实是输入字符WASD,所以每个循环最开始都是使用输入语句getch获取输入的字符。故应当定义一个字符变量ch来存储输入的字符。
先清屏,然后输出地图。紧接着进while循环,循环条件为1死循环。
获取字符后,用if语句判断输入的是什么字符。
for(i=0;i<=20;i++)
puts(a[i]);
while(1)
{
ch=getch();//【输入语句】
if(ch=='s')//【判断输入的字符是什么】
下面是最关键的两个内容,如何控制小球O规避宫墙 # ?以及小球O是怎么移动的呢?
我们之前理解过X和Y了,所以我们明白x+1,实际上就是增进一行!而y+1则是增进1列!xy代表着小球的位置,小球位于x行y列,故小球向左走,是
y-1,向右走是y+1,向上是x-1,向下是x+1!
一:检测用户输入了什么字符,进入了哪个if语句后,立刻开始检测“前方”是否为宫墙 # 若是则中断接下来的语句直接进入下个循环。该输入无效。
二:小球的移动过程是:原位置赋为空格——x或y值加1或减1——新位置赋为小球O
if(ch=='s')
{
if(a[x+1][y]!='#')
{
a[x][y]=' ';
x++; //想想为什么不是a[x+1][y]呢?
a[x][y]='O';
}
}
知晓了一个方向的操作,那么其他方向的操作都是相通的。
if(ch=='s')
{
if(a[x+1][y]!='#')
{
a[x][y]=' ';
x++;
a[x][y]='O';
}
}
if(ch=='w')
{
if(a[x-1][y]!='#')
{
a[x][y]=' ';
x--;
a[x][y]='O';
}
}
if(ch=='a')
{
if(a[x][y-1]!='#')
{
a[x][y]=' ';
y--;
a[x][y]='O';
}
}
if(ch=='d')
{
if(a[x][y+1]!='#')
{
a[x][y]=' ';
y++;
a[x][y]='O';
}
}
重点基本就结束啦,是不是还缺了点什么?
最后还要检测小球是否到了终点,如果是,就跳出循环并庆祝用户游戏通关!
如果不是,就重新清屏并输出一遍地图,对于已经变动过的xy值,这相当于刷新。
system("cls");
for(i=0;i<=20;i++)
puts(a[i]);
if(x==p&&y==q)
break;
while(1)
printf("%s牛逼!",u);
Sleep(3000);
return 0;
游戏结束,开头让用户输入个名字,储存起来庆祝的时候用就好啦!
效果可喜庆了!
其实这个游戏十分简单,只要理解了二维字符数组有关位置的概念就什么都知道了。
推 箱 子
本章的第二个游戏,也是最后一个游戏,亦是本书最后一个程序
如果说走迷宫游戏是一瓶矿泉水,那么推箱子游戏就是一瓶果粒橙橙汁!
它建立在走迷宫的基础之上,所以我在详述完走迷宫后,关于推箱子的部分,就仅剖析最关键最重要的部分!
如上图所示,推箱子游戏的玩法和走迷宫相似,WASD控制小人S上下左右移动。不同的是,增加了小人S推动箱子O的节目。
char u[11];
gets(u);
char a[7][11]={"##########",
"## ###",
"##O### #",
"# S O O #",
"# !!# O ##",
"##!!# ##",
"##########",};
以上是地图
控制S推动O,直至四个箱子O都被推至四个感叹号处,游戏通关!
这个游戏最核心最关键的重点在于:
- 如何用WASD控制S上下左右移动
- S如何规避宫墙(S前方为墙时,推动无效)
- S如何推动1个箱子O
- S如何推动多个箱子O
- S推动一个或多个箱子O时,如何让箱子O规避宫墙(也就是O前方为墙时S的推动无效)
1和2在走迷宫里已经解读过了
规避的宫墙
if(nb=='w')
{
if(a[x-1][y]!='#')
S向上移动
a[x][y]=' ';
x--;
a[x][y]='O';
O也是字符,让S动起来的原理也是让O动起来的原理。
关键在于O和S如何协同移动!
当S移动的方向上没有O时,S仅移动自己;当S移动的方向上有O时,推动O并移动自己!
这是一个分支选项,可以用 if 分支来判断这个问题。
输入某个按键,进入某个按键的 if 的循环时,首先应当判断前方是否为宫墙。紧接着就是判断前方是否有O!
当我们单单移动S时,我们是:原位置赋空格—朝方向进1或退1—新位置赋S
我们先回顾一下规避宫墙:倘若S前方为宫墙#,S如此操作的话,宫墙 # 会被S吞掉!
这就是当我按下W后,为什么使用if(a[x-1][y]!='#')
作为最外的 if 嵌套。来规避宫墙
故当我们对箱子O也是一个心思时,我们不想要S吞掉O,故操作S的步骤要放到【判断前方不是箱子O】这个语句内。
if(a[x-1][y]!='O')
故S前方不是O才能移动,那么S和O之间进行协同移动时,应当是O先动,S再动!
所以操作顺序明确了,先O后S。
按下某个键,进入某个if内,先判断宫墙,然后进入O的操作:
1.判断O前方是否是宫墙#
2. 如果不是就操作O向前!
以上是推动单个O!!
但是多个O呢?如何推动多个箱子?
箱子数量是未知的!故我们应当要计数
我们利用for循环,统计前方是否有O,控制for循环的整型变量 j 初始值是0,当确认前方有O时为1,进入for循环,倘若前方还有O则 j+1 并继续循环,直至前方不为O时跳出循环
此时 j 的值便是S前方的小球O的数量
我们要判断最后一个小球前方是不是宫墙 # 如果是,就不能执行推动O了
if(a[x-(j+1)][y]!='#')//【最后一个球的下一位是否是墙】
以下就是完整的一段:如何操作S推动1个或多个小球
if(nb=='w')
{
if(a[x-1][y]!='#')
{
if(a[x-1][y]=='O')
{
j++;
while(1)
{
if(a[x-(j+1)][y]=='O')//【统计有多少个球】
j++;
else
break;
}
if(a[x-(j+1)][y]!='#')//【最后一个球的下一位是否是墙】
{
while(j>=1)//【从后往前,逐步操作小球直到最后一个小球】
{
a[x-j][y]=' ';
a[x-(j+1)][y]='O';
j--;
}
}
}
if(a[x-1][y]!='O')//【验证了前方无小球后,移动S】
{
a[x][y]=' ';
x--;
a[x][y]='O';
}
}
}
本章是《啊哈C语言》的最终章,其实走迷宫这个例子用的非常好,推箱子这个游戏用的更妙。做完这俩游戏,学生也算是出炉了!
走迷宫游戏,作者在书中从头到尾讲了一遍。
而对于推箱子游戏,作者在介绍完游戏玩法后,便宣布本书内容的结束!
这是最骚的!
纪磊老师将这最后的程序交给了读者,他引导读者依靠自己的实力完成这个游戏,只有依靠独立思考解决的问题,才是最有成就感的!也才能激起对编程的兴趣!
全书中纪磊老师一直在引导读者培养独立思考的意识!直到最后,也映射着编程之路都是独立思考为先!
。。。码了两个小时有点累,感谢纪磊老师贡献的这本书!纪念我在这本书中,每一个逻辑挑战中,成功运行程序时,所收获的纯粹的快乐!
上一篇: 商品表 数据库设计
下一篇: 帖,ecshop非会员跳转