前两天同学发来一个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要变成相应的坐标。