一个C游戏(BoxMan)代码的分析


    

一个C游戏(BoxMan)代码的分析

分类: C/C++/linux 1296人阅读 评论(2) 收藏 举报

前两天同学发来一个C语言编的小游戏,BoxMan,不知是否叫做搬运工。我认真读了,运行了好几次,发现里面写得挺有意思的!程序代码如下,代码来源于网上!

 

#include  < stdio.h >
#include 
< bios.h >
#include 
< conio.h >


#define  ESC   0x011b
#define  UP    0x4800
#define  DOWN  0x5000
#define  LEFT  0x4b00
#define  RIGHT 0x4d00

#define  MAXSIZE 10

typedef 
struct
... {
    
int x;
    
int y;
}
point;

point des[MAXSIZE];

char  map[ 10 ][ 10 =
... {
    
"        ",
    
"    ####",
    
"  ### @#",
    
"  #  b #",
    
" ## # ###",
    
" #  # #*#",
    
" # #  b*#",
    
" # b   *#",
    
" ########",
    
"         "
}
;

void  DrawMan( int  x,  int  y)
... {
    gotoxy(x
+10, y+5);
    textcolor(YELLOW);
    putch(
2);
    printf(
"");
}


void  DrawSpace( int  x,  int  y)
... {
    gotoxy(x
+10, y+5);
    printf(
" ");
}


void  DrawBox( int  x,  int  y)
... {
    gotoxy(x
+10, y+5);
    textcolor(CYAN);
    putch(
'@');
}


void  DrawDes( int  x,  int  y)
... {
    gotoxy(x
+10, y+5);
    textcolor(YELLOW);
    putch(
'*');
}


void  DrawBoxIn( int  x,  int  y)
... {
    gotoxy(x
+10, y+5);
    textcolor(YELLOW);
    putch(
'@');
}


void  DrawMap(point  * pman)
... {
    
int x = 0, y = 0;
    
int i = 0;
    
for (; y < 10++y)
    
...{
        
for (x=0; x < 10++x)
        
...{
            
if (map[y][x] == '#')
            
...{
                textcolor(GREEN);
                gotoxy(x
+10, y+5);
                putch(
219);
            }

            
else if (map[y][x] == '*')
            
...{
                DrawDes(x, y);
                des[i].x 
= x;
                des[i].y 
= y;
                
++i;
            }

            
else if (map[y][x] == '@')
            
...{
                pman
->= x;
                pman
->= y;
                DrawMan(x, y);
                map[y][x] 
= ' ';
            }

            
else if (map[y][x] == 'b')
            
...{
                DrawBox(x, y);
            }

            
else if (map[y][x] == 'i')
            
...{
                DrawBoxIn(x, y);
                des[i].x 
= x;
                des[i].y 
= y;
                
++i;
            }

            des[i].x 
= -1;
        }

        gotoxy(
486);
        printf(
"Welcome to come to BoxMan!!");
        gotoxy(
488);
        printf(
"Press direct key to move the man!");
        gotoxy(
4810);
        printf(
"Press ESC to quit the game!");
        gotoxy(
4812);
        printf(
"Enjoy yourself in this game!");
        gotoxy(
362);
        textcolor(RED);
        putch(
'B');
        putch(
'o');
        putch(
'x');
        putch(
'M');
        putch(
'a');
        putch(
'n');
    }

}


int  main()
... {
    point man 
= ...{11};
    
int key = 0;
    
int i = 0, count = 0;
    clrscr();
    DrawMap(
&man);

    
while (key != ESC)
    
...{
        
while (bioskey(1== 0);
        key 
= bioskey(0);

        
switch (key)
        
...{
        
case UP:
            
if (map[man.y - 1][man.x] == '#')
            
...{
                
break;
            }

            
else if (map[man.y - 1][man.x] == 'b' || map[man.y - 1][man.x] == 'i')
            
...{
                
switch (map[man.y - 2][man.x])
                
...{
                
case 'b':
                
case '#':
                
case 'i':
                    
break;
                
case ' ':
                    
/**//*move box*/
                    
if (map[man.y - 1][man.x] == 'i')
                    
...{
                        map[man.y 
- 1][man.x] = '*';
                    }

                    
else
                    
...{
                        map[man.y 
- 1][man.x] = ' ';
                    }


                    map[man.y 
- 2][man.x] = 'b';
                    DrawBox(man.x, man.y 
- 2);


                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
--man.y;
                    DrawMan(man.x, man.y);
                    
break;
                
case '*':
                    
/**//*move box in*/
                    
if (map[man.y - 1][man.x] == 'i')
                    
...{
                        map[man.y 
- 1][man.x] = '*';
                    }

                    
else
                    
...{
                        map[man.y 
- 1][man.x] = ' ';
                    }


                    map[man.y 
- 2][man.x] = 'i';
                    DrawBoxIn(man.x, man.y 
- 2);


                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
--man.y;
                    DrawMan(man.x, man.y);
                    
break;
                defalut:
                    
break;
                }


                
break;
            }

            
else
            
...{
                
if (map[man.y][man.x] == '*')
                
...{
                    DrawDes(man.x, man.y);
                }

                
else
                
...{
                    DrawSpace(man.x, man.y);
                }


                
--man.y;
                DrawMan(man.x, man.y);
                
break;
            }


        
case DOWN:
            
if (map[man.y + 1][man.x] == '#')
            
...{
                
break;
            }

            
else if (map[man.y + 1][man.x] == 'b' || map[man.y + 1][man.x] == 'i')
            
...{
                
switch (map[man.y + 2][man.x])
                
...{
                
case 'b':
                
case '#':
                
case 'i':
                    
break;
                
case ' ':
                    
/**//*move box*/
                    
if (map[man.y + 1][man.x] == 'i')
                    
...{
                        map[man.y 
+ 1][man.x] = '*';
                    }

                    
else
                    
...{
                        map[man.y 
+ 1][man.x] = ' ';
                    }

                    
                    map[man.y 
+ 2][man.x] = 'b';
                    DrawBox(man.x, man.y 
+ 2);
                    
                    
                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
++man.y;
                    DrawMan(man.x, man.y);
                    
break;
                
case '*':
                    
/**//*move box in*/
                    
if (map[man.y + 1][man.x] == 'i')
                    
...{
                        map[man.y 
+ 1][man.x] = '*';
                    }

                    
else
                    
...{
                        map[man.y 
+ 1][man.x] = ' ';
                    }


                    map[man.y 
+ 2][man.x] = 'i';
                    DrawBoxIn(man.x, man.y 
+ 2);


                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
++man.y;
                    DrawMan(man.x, man.y);
                    
break;
                
default:
                    
break;
                }


                
break;
            }

            
else
            
...{
                
if (map[man.y][man.x] == '*')
                
...{
                    DrawDes(man.x, man.y);
                }

                
else
                
...{
                    DrawSpace(man.x, man.y);
                }


                
++man.y;
                DrawMan(man.x, man.y);
                
break;
            }

        
case LEFT:
            
if (map[man.y][man.x - 1== '#')
            
...{
                
break;
            }

            
else if (map[man.y][man.x - 1== 'b' || map[man.y][man.x - 1== 'i')
            
...{
                
switch (map[man.y][man.x - 2])
                
...{
                
case 'b':
                
case '#':
                
case 'i':
                    
break;
                
case ' ':
                    
/**//*move box*/
                    
if (map[man.y][man.x - 1== 'i')
                    
...{
                        map[man.y][man.x 
- 1= '*';
                    }

                    
else
                    
...{
                        map[man.y][man.x 
- 1= ' ';
                    }


                    map[man.y][man.x 
- 2= 'b';
                    DrawBox(man.x 
- 2, man.y);


                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
--man.x;
                    DrawMan(man.x, man.y);
                    
break;
                
case '*':
                    
/**//*move box in*/
                    
if (map[man.y][man.x - 1== 'i')
                    
...{
                        map[man.y][man.x 
- 1= '*';
                    }

                    
else 
                    
...{
                        map[man.y][man.x 
- 1= ' ';
                    }

                    
                    map[man.y][man.x 
- 2= 'i';
                    DrawBoxIn(man.x 
- 2, man.y);
                    
                    
                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
--man.x;
                    DrawMan(man.x, man.y);
                    
break;
                
default:
                    
break;
                }


                
break;
            }

            
else
            
...{
                
if (map[man.y][man.x] == '*')
                
...{
                    DrawDes(man.x, man.y);
                }

                
else
                
...{
                    DrawSpace(man.x, man.y);
                }

                
--man.x;
                DrawMan(man.x, man.y);
                
break;
            }

        
case RIGHT:
            
if (map[man.y][man.x + 1== '#')
            
...{
                
break;
            }

            
else if (map[man.y][man.x + 1== 'b' || map[man.y][man.x + 1== 'i')
            
...{
                
switch (map[man.y][man.x + 2])
                
...{
                
case 'b':
                
case '#':
                
case 'i':
                    
break;
                
case ' ':
                    
/**//*move box*/
                    
if (map[man.y][man.x + 1== 'i')
                    
...{
                        map[man.y][man.x 
+ 1= '*';
                    }

                    
else
                    
...{
                        map[man.y][man.x 
+ 1= ' ';
                    }

                    
                    map[man.y][man.x 
+ 2= 'b';
                    DrawBox(man.x 
+ 2, man.y);
                    
                    
                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
++man.x;
                    DrawMan(man.x, man.y);
                    
break;
                
case '*':
                    
/**//*move box in*/
                    
if (map[man.y][man.x + 1== 'i')
                    
...{
                        map[man.y][man.x 
+ 1= '*';
                    }

                    
else
                    
...{
                        map[man.y][man.x 
+ 1= ' ';
                    }

                    
                    map[man.y][man.x 
+ 2= 'i';
                    DrawBoxIn(man.x 
+ 2, man.y);
                    
                    
                    
if (map[man.y][man.x] == '*')
                    
...{
                        DrawDes(man.x, man.y);
                    }

                    
else
                    
...{
                        DrawSpace(man.x, man.y);
                    }


                    
++man.x;
                    DrawMan(man.x, man.y);
                    
break;
                
default:
                    
break;
                }


                
break;
            }

            
else
            
...{
                
if (map[man.y][man.x] == '*')
                
...{
                    DrawDes(man.x, man.y);
                }

                
else
                
...{
                    DrawSpace(man.x, man.y);
                }

                DrawSpace(man.x, man.y);
                
++man.x;
                DrawMan(man.x, man.y);
                
break;
            }

        defualt:
            
break;
        }


        
for (i=0, count=0; des[i].x != -1++i)
        
...{
            
if (map[des[i].y][des[i].x] == '*')
            
...{
                
++count;
            }

        }

        
if (count == 0)    
        
...{
            gotoxy(
353);
            printf(
"Ok! you win!");
            getch();
            key 
= ESC;
        }

    }


    
return 0;
}

 

相信很多没有用C语言开发过小项目的朋友们肯定会对里面出现的函数吃惊。我们平时用的函数只不过是printf、scanf和自己编写的小函数。为了让大家能方便读懂上面的程序,对程序中出现的函数作简要的说明。

putch函数:

putch()向屏幕输出字符的函数
使用方式:
 ① putch('转义字符');
 ② putch('单个字符');
 ③ putch(字符变量);
注:③需先定义 char 字符变量='单个字符';
头文件:conio.h

在上面的函数中出现如下的语句:

putch(2);

putch('@');

putch('*');

它们都是向屏幕输出指定的字符。

boiskey

函数原型:int bioskey (int cmd)
说明:bioskey()的函数原型在bios.h中 bioskey()完成直接键盘操作,cmd的值决定执行什么操作。
cmd = 0:
  当cmd是0,bioskey()返回下一个在键盘键入的值(它将等待到按下一个键)。它返回一个16位的二进制数,包括两个不同的值。当按下一个普通键时,它的低8位数存放该字符的ASCII码;对于特殊键(如方向键、F1~F12等等),低8位为0,高8位字节存放该键的扫描码。
cmd = 1:
  当cmd是1,bioskey()查询是否按下一个键,若按下一个键则返回非零值,否则返回0。
cmd = 2:
  当cmd是2,bioskey()返回Shift、Ctrl、Alt、ScrollLock、NumLock、CapsLock、Insert键的状态。各键状态存放在返回值的低8位字节中。 字节位 含义 0 右边Shift键状态 1 左边Shift键状态 3 Ctrl键状态 4 Alt键状态 5 ScrollLock键状态 6 NumLock键状态 7 CapsLock键状态 8 Insert

bioskey函数在游戏开发中很有用的一个函数,基本都是用它来处理用户的输入。scanf函数用来接受用户的输出入,直到用户输入后才返回。而bioskey不同的,它可以获取此时用户是否输入,如果输入,可以获取用户的输入值,只要设置函数的入口参数cmd即可。

在本游戏中它出现的代码只有两句,代码虽小,但它解决了用户的输入功能,可谓神通广大。

while (bioskey(1) == 0);
  key = bioskey(0);

查看用户是否按下某个键,如没有按下则返回0,继续等待用户按键事件(中断)(第一句),如用户有按键,则返回用户的按下的键值(第二句)

函数clrscr()与gotoxy()

这两个函数相当简单,clrscr()负责清屏,而gotoxy()负责把光标定位在指定的坐标中。

textcolor函数

void textcolor(int color)

在文本模式中选择新的字符颜色 ,参数color指定字符颜色。

好了,有了这些函数的说明与参考,我们可以分析游戏了!

先看看宏定义吧:

#define ESC   0x011b
#define UP    0x4800
#define DOWN  0x5000
#define LEFT  0x4b00
#define RIGHT 0x4d00

有相当编程经验的朋友很容易是看出上面定义的是退出键、上箭头、下箭头、左箭头和右箭头的标识符。我们再对比一下bioskey函数的返回说明,四个方向的箭头均为特殊键,因此若按下这些键,那16位的返回值低8位为0,高8位为它所对应的扫描码,上面的几个宏定义刚好是定义各个键对应bioskey函数的返回,用户判断用户按下了哪个键。

typedef struct
{
 int x;
 int y;
}point;

定义Point结构体,用来描述一个点。

point des[MAXSIZE];

定义一个点数组,用来存放箱子的位置,最后一个以.x为-1表示结束数组,后面的数据不再检验,因此在游戏最多有9个箱子。

char map[10][10] =
{
 "        ",
 "    ####",
 "  ### @#",
 "  #  b #",
 " ## # ###",
 " #  # #*#",
 " # #  b*#",
 " # b   *#",
 " ########",
 "         "
};

这个一个二维字符数组,用来表示游戏的情景状态,在游戏运行过程中情景会由用户输入而改变,要动态更新。

其中,#表示墙,@表示man,b表示盒子,*表示箱子(内还没有装上盒子),i表示装上盒子的箱子(在后面代面中会出现)。

在屏幕显示时候,根据当前状态进行输出,且体输出内容是与上状态不一样的,状态用于程序决策作用,下一步是否可走,是否能推动箱子等等。而显示则是输入相应的画面给用户。每种物体的输出都定义了相应的输入函数,且体如下:

void DrawMan(int x, int y)
{
 gotoxy(x+10, y+5);
 textcolor(YELLOW);
 putch(2);
 printf("/b");
}

显示man

void DrawSpace(int x, int y)
{
 gotoxy(x+10, y+5);
 printf(" ");
}

显示空格

void DrawBox(int x, int y)
{
 gotoxy(x+10, y+5);
 textcolor(CYAN);
 putch('@');
}

显示盒子

void DrawDes(int x, int y)
{
 gotoxy(x+10, y+5);
 textcolor(YELLOW);
 putch('*');
}

显示箱子(没有装盒子的)

void DrawBoxIn(int x, int y)
{
 gotoxy(x+10, y+5);
 textcolor(YELLOW);
 putch('@');
}

显示装上盒子后的箱子

上述函数用于在屏幕输出相应的物体,如墙壁,人、盒子和箱子等等……

void DrawMap(point *pman)
{
 int x = 0, y = 0;
 int i = 0;
 for (; y < 10; ++y)
 {
  for (x=0; x < 10; ++x)
  {
   if (map[y][x] == '#')
   {
    textcolor(GREEN);
    gotoxy(x+10, y+5);
    putch(219);
   }
   else if (map[y][x] == '*')
   {
    DrawDes(x, y);
    des[i].x = x;
    des[i].y = y;
    ++i;
   }
   else if (map[y][x] == '@')
   {
    pman->x = x;
    pman->y = y;
    DrawMan(x, y);
    map[y][x] = ' ';
   }
   else if (map[y][x] == 'b')
   {
    DrawBox(x, y);
   }
   else if (map[y][x] == 'i')
   {
    DrawBoxIn(x, y);
    des[i].x = x;
    des[i].y = y;
    ++i;
   }
   des[i].x = -1;
  }
  gotoxy(48, 6);
  printf("Welcome to come to BoxMan!!");
  gotoxy(48, 8);
  printf("Press direct key to move the man!");
  gotoxy(48, 10);
  printf("Press ESC to quit the game!");
  gotoxy(48, 12);
  printf("Enjoy yourself in this game!");
  gotoxy(36, 2);
  textcolor(RED);
  putch('B');
  putch('o');
  putch('x');
  putch('M');
  putch('a');
  putch('n');
 }
}
该函数用于输入第一个游戏画面,把提示文字和游戏部分都显示在屏幕中。

其中:

else if (map[y][x] == '*')
   {
    DrawDes(x, y);
    des[i].x = x;
    des[i].y = y;
    ++i;
   }

用于统计箱子的位置和个数,用于判断用户每次输入后是否获胜。

下面是洲戏规则的重要部分了:

clrscr();
 DrawMap(&man);

先清屏,再把游戏的画面和提示输出到屏幕中去。

然后接收用户的输入,判断用户输入的是否是退出键、四个方向键,如是其中之一,则运行相应的代码段对游戏情景和画面进行调整。

对用户的输入处理在switch语句中实现,说到底是对游戏规则的处理而已,那么大家可以想想这个游戏规格则喔!下面只分析用户按下上箭头键的处理过程(分析在注释中):

 

case  UP:
   
if  (map[man.y  -   1 ][man.x]  ==   ' # ' )
   
... {//如果man的上方是墙壁,那不能向上走,处理完毕

    
break;
   }

   
else   if  (map[man.y  -   1 ][man.x]  ==   ' b '   ||  map[man.y  -   1 ][man.x]  ==   ' i ' )
   
... {//如果man上方为盒子或箱子(有盒子放在里面了),则要看它前上方情况如果才能做决定
    switch (map[man.y - 2][man.x])
    
...{//如果前上方为盒子或墙壁或箱子(有盒子放在里面),则man肯定不能推动它前方的b或i
    case 'b':
    
case '#':
    
case 'i':
     
break;
    
case ' ' //前上方为空的情况(即可以放东西),则可推东西进此
     /**//*move box*/
     
if (map[man.y - 1][man.x] == 'i')
     
...{//上方是箱子(装着盒子),把盒子推上去,箱子不能动。
      map[man.y - 1][man.x] = '*';
     }

     
else
     
...{//上方是盒子,则把盒子推上去
      map[man.y - 1][man.x] = ' ';
     }


     map[man.y 
- 2][man.x] = 'b';
     DrawBox(man.x, man.y 
- 2);//更新画面,把推上去的盒子画出来


     
if (map[man.y][man.x] == '*')
     
...{
      DrawDes(man.x, man.y);
//如果man站的位置是箱子的位置,man向上走一步后,还要箱子的显示
     }

     
else
     
...{
      DrawSpace(man.x, man.y);
//否则man走开后,画上空白,没有物体在此处。
     }


     
--man.y;//人向上走一个位置,下句把人画出来。
     DrawMan(man.x, man.y);
     
break;
    
case '*'//如果前上方为箱子(没有装到盒子)
     /**//*move box in*/
     
if (map[man.y - 1][man.x] == 'i')
     
...{//上方为盒子,把盒子推到箱子中去,那么箱子变有装着盒子的箱子了
      map[man.y - 1][man.x] = '*';
     }

     
else
     
...{//如果上方为箱子(装着盒子),应把盒子从下箱子推往上箱子,上箱子将装着盒子,而下箱子没有
      map[man.y - 1][man.x] = ' ';
     }


     map[man.y 
- 2][man.x] = 'i';  //前上方的箱子装着盒子,所以状态为i
     DrawBoxIn(man.x, man.y - 2);

    
//由于man要向上走一个位置,要画出man向上走后,原来位置的物体(为空或空箱子)
     if (map[man.y][man.x] == '*')
     
...{
      DrawDes(man.x, man.y);
     }

     
else
     
...{
      DrawSpace(man.x, man.y);
     }


     
--man.y;
     DrawMan(man.x, man.y);
     
break;
    defalut:
     
break;
    }


    
break;
   }

   
else // 如果man的上方为箱子(未装盒子)或空白,则man可以直接走到
    ... {
    
if (map[man.y][man.x] == '*')
    
...{
     DrawDes(man.x, man.y);
//如果man原来站的位置为箱子,man离开后要复原,否为空白(else部分)
    }

    
else
    
...{
     DrawSpace(man.x, man.y);
    }


    
--man.y;
    DrawMan(man.x, man.y);
    
break;
   }

 

最后一部分用户每次输入后,判断用户是否获胜的过程:

 

for  (i = 0 , count = 0 ; des[i].x  !=   - 1 ++ i)
        {
            
if  (map[des[i].y][des[i].x]  ==   ' * ' )
            {
                
++ count; // 统计有多少个箱子还没有放上盒子
            }
        }
        
if  (count  ==   0 )    
        {
// 如果所有箱子都放上盒子,则用户获胜,游戏结束。
            gotoxy( 35 3 );
            printf(
" Ok! you win! " );
            getch();
            key 
=  ESC;
        }

 

以上是对该程序的一点分析,对里面重要的部分作了一些说明。如果要看懂代码,还要需参考运行的程序作为对比,我在行运时,还发现一个小小的bug。至于对用户的输入进行处理的那部分代码是很难懂的,首先要懂得游戏规则,我在此没有写出来,是因为大家都会玩这个游戏,没有必要写出来。依我之见,另外三个按的代码处理过程与上箭头键的处理完理一样的,只是man.y-1和man.y-2要变成相应的坐标。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值