您的位置:首页 > 编程语言

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

2014-07-05 16:06 417 查看


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

分类:
C/C++/linux 2007-01-11 15:45
1296人阅读 评论(2)
收藏
举报

游戏ccmdinsertstructup

前两天同学发来一个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 = 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');


}


}




int main()




...{




point man = ...{1, 1};


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(35, 3);


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要变成相应的坐标。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: