欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

解析《啊哈C》--最终章:用C语言制作走迷宫和推箱子的小游戏

程序员文章站 2022-05-12 08:38:14
...

啊哈C语言:第8章 《游戏时间到了》-----2020/4/10

从2月底开始直到前天,当我学完二维字符数组、字典序后,翻到这一章的页面时,心情是欢喜的,我想一件坚持了很久的事情做到了最后关头,都是付出的时间、精力的成果!开心心!

而一个多月坚持独立思考的成果终于要检验了!相对于之前写过的程序,一个具有可操作性可玩性的游戏,是一种更加具象化的成果体现,也更加有成就感!!

下面就是正文啦!

第一个游戏:走迷宫!
解析《啊哈C》--最终章:用C语言制作走迷宫和推箱子的小游戏
使用井号‘#’制作迷宫的宫墙,将大写字母‘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;

游戏结束,开头让用户输入个名字,储存起来庆祝的时候用就好啦!
效果可喜庆了!

其实这个游戏十分简单,只要理解了二维字符数组有关位置的概念就什么都知道了。


推 箱 子

解析《啊哈C》--最终章:用C语言制作走迷宫和推箱子的小游戏
本章的第二个游戏,也是最后一个游戏,亦是本书最后一个程序

如果说走迷宫游戏是一瓶矿泉水,那么推箱子游戏就是一瓶果粒橙橙汁!

它建立在走迷宫的基础之上,所以我在详述完走迷宫后,关于推箱子的部分,就仅剖析最关键最重要的部分!

如上图所示,推箱子游戏的玩法和走迷宫相似,WASD控制小人S上下左右移动。不同的是,增加了小人S推动箱子O的节目。

char u[11];
    gets(u);
    char a[7][11]={"##########",
                   "##     ###",
                   "##O###   #",
                   "# S O  O #",
                   "# !!# O ##",
                   "##!!#   ##",
                   "##########",};

以上是地图

控制S推动O,直至四个箱子O都被推至四个感叹号处,游戏通关!

这个游戏最核心最关键的重点在于:

  1. 如何用WASD控制S上下左右移动
  2. S如何规避宫墙(S前方为墙时,推动无效)
  3. S如何推动1个箱子O
  4. S如何推动多个箱子O
  5. 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语言》的最终章,其实走迷宫这个例子用的非常好,推箱子这个游戏用的更妙。做完这俩游戏,学生也算是出炉了!

走迷宫游戏,作者在书中从头到尾讲了一遍。

而对于推箱子游戏,作者在介绍完游戏玩法后,便宣布本书内容的结束!

这是最骚的!

纪磊老师将这最后的程序交给了读者,他引导读者依靠自己的实力完成这个游戏,只有依靠独立思考解决的问题,才是最有成就感的!也才能激起对编程的兴趣!

全书中纪磊老师一直在引导读者培养独立思考的意识!直到最后,也映射着编程之路都是独立思考为先!

。。。码了两个小时有点累,感谢纪磊老师贡献的这本书!纪念我在这本书中,每一个逻辑挑战中,成功运行程序时,所收获的纯粹的快乐!