源程序如下: 我的问题是,调节游戏速度时,数字为什么越大时,有时候竟然越快?
#define N 200
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#define LEFT 0x4b00 /* 将这些特殊字符的ACSII值(这里主要的是扩展的)定义宏,来方便使用 */
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
int i,key;
int score=0;/*得分*/
int gamespeed=60000;/*游戏速度自己调整 这个值应该是越小蛇运动的越快,但是我在Win-TC1.9.1运行时,当我把gamespeed增大时,在某些值下会反而会增快,不知道为什么*/
struct Food
{
int x;/*食物的横坐标*/
int y;/*食物的纵坐标*/
int yes;/*判断是否要出现食物的变量*/
}food;/*食物的结构体*/
struct Snake
{
int x[N];
int y[N];
int node;/*蛇的节数*/
int direction;/*蛇移动方向*/
int life;/* 蛇的生命,0活着,1死亡*/
}snake;
void Init(void);/*图形驱动*/
void Close(void);/*图形结束*/
void DrawK(void);/*开始画面*/
void GameOver(void);/*结束游戏*/
void GamePlay(void);/*玩游戏具体过程*/
void PrScore(void);/*输出成绩*/
/*主函数*/
void main(void)
{
Init();/*图形驱动*/
DrawK();/*开始画面*/
GamePlay();/*玩游戏具体过程*/
Close();/*图形结束*/
}
/*图形驱动*/
void Init(void)
{
int gd=DETECT,gm;
initgraph(&gd,&gm,"d:\\tc\program"); /* 初始化图形系统, d:\\tc\program 为EGA VGA.bgi所在路径 */
cleardevice(); /* 清除屏幕函数 */
}
/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙,不过画完后围墙的内圈是(60,50)(600,450)*/
void DrawK(void)
{
/*setbkcolor(LIGHTGREEN);*/ /* 设置背景颜色,可以添加 */
setcolor(11);/* 函数setcolor()设置当前绘图颜色(或称做前景色)。 */
setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型 为画线函数设置当前线型,包括线型、线图样和线宽。此处为实线加宽 */
for(i=50;i<=600;i+=10)/*画围墙*/
{
rectangle(i,40,i+10,49); /*上边 画矩形函数用当前绘图色、线型及线宽,画一个给定左上角与右下角的矩形 */
rectangle(i,451,i+10,460);/*下边 此函数调用方式为void rectangle(int left,int top,int right,int bottom); */
}/* 以一个小格为一个单位来画围墙的上下两行 */
for(i=40;i<=450;i+=10)
{
rectangle(50,i,59,i+10); /*左边*/
rectangle(601,i,610,i+10);/*右边*/
}/* 以一个小格为一个单位来画围墙的左右两行 */
}
/*玩游戏具体过程*/
void GamePlay(void)
{
randomize();/*随机数发生器*/
food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/
snake.life=0;/*活着*/
snake.direction=1;/*方向往右*/
snake.x[0]=100;snake.y[0]=100;/*蛇头 初始化位置*/
snake.x[1]=110;snake.y[1]=100;
snake.node=2;/*节数*/
PrScore();/*输出得分*/
while(1)/*可以重复玩游戏,压ESC键结束*/
{
while(!kbhit())/*检查当前按下的键 在没有按键的情况下,蛇自己移动身体*/
{/* 关于kbhit()的返回值,查找有些地方都说检查到按键返回1没有检查到返回0但本人在Win-TC1.9.1上测试为检查到返回-1没检查到返回0 */
/* 所以kbhit()没检查到时返回0检查到返回非0相对准确些 */
/* 再说一点,该函数只是检查当前是否有按键信息,却不捕获该信息。也就是说你按下一个'Q'它知道你有按下键,后面如果有捕获按键信息的函数,那么那个函数仍然可以捕获这个'Q'信息的 */
if(food.yes==1) /*需要出现新食物*/
{
food.x=rand()%400+60;/* rand()产生随机数。rand()%400+60这个表达式说明产生的随机数范围是[60,460) */
food.y=rand()%350+60;
while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到,因为作者把每个小格的大小定义为10*10,所以蛇头的位置必然在横(列)中是10的整数倍 */
food.x++;
while(food.y%10!=0)
food.y++;
food.yes=0;/*画面上有食物了*/
}
if(food.yes==0)/*画面上有食物了就要显示*/
{
setcolor(GREEN);
rectangle(food.x,food.y,food.x+10,food.y-10);/* 根据刚才设置的食物的位置画出食物来 */
}
for(i=snake.node-1;i>0;i--)/*蛇的每个环节往前移动,也就是贪吃蛇的关键算法*/
{
snake.x[i]=snake.x[i-1];
snake.y[i]=snake.y[i-1];
}
/*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/
switch(snake.direction)
{
case 1:snake.x[0]+=10;break; /* 向右 */
case 2: snake.x[0]-=10;break; /* 向左 */
case 3: snake.y[0]-=10;break; /* 向上 */
case 4: snake.y[0]+=10;break; /* 向下 */
}
for(i=3;i<snake.node;i++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/
{
if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])
{
GameOver();/*显示失败*/
snake.life=1;
break;
}
}
if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||snake.y[0]>455)/*蛇是否撞到墙壁这里的数字都是内壁与外壁的中点,来判断蛇头是否超过了内壁*/
{
GameOver();/*本次游戏结束*/
snake.life=1; /*蛇死*/
}
if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内循环,重新开始*/
break;
if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/
{
setcolor(0);/*把画面上的食物东西去掉*/
rectangle(food.x,food.y,food.x+10,food.y-10);
snake.x[snake.node]=-20;snake.y[snake.node]=-20;
/*新的一节先放在看不见的位置,下次循环就取前一节的位置,此时虽然这节没有显示出来,不过蛇结构确实已经有了这节的数据*/
snake.node++;/*蛇的身体长一节*/
food.yes=1;/*画面上需要出现新的食物*/
score+=10;
PrScore();/*输出新得分*/
}
setcolor(4);/*画出蛇 这里4是红色 */
for(i=0;i<snake.node;i++)
rectangle(snake.x[i],snake.y[i],snake.x[i]+10,snake.y[i]-10);
delay(gamespeed);/* 将程序的执行暂停一段时间(毫秒) void delay(unsigned milliseconds); 程序暂停就是蛇在停止 */
setcolor(0);/*用黑色(作者说是黑色不过我测试的结果为setcolor(0)是设置成背景色,也就是说不管你的背景色设置成什么颜色,该函数都会使得绘图色于背景色一样,从而实现"不显色"蛇最后一节,但setbkcolor(0)确实将背景色设置为黑色)去除蛇的的最后一节*/
rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+10,snake.y[snake.node-1]-10); /* 当程序休息过,先去掉蛇的最后一节,因为在重新画蛇的时候(for语句)并没有去掉蛇尾巴的过程 */
} /*end:while(!kbhit)*/
if(snake.life==1)/*如果蛇死就跳出循环*/
break;
key=bioskey(0);/*接收按键函数bioskey()的原型为: int bioskey(int cmd); */
/* 当cmd==0时,bioskey()返回按健的键值,该值是2 个字节的整型数。当按下时,若返回值的低8 位为非零,则表示为普通键,其值代表该键的ASCII 码。若返回值的低8 位为0,则高8 位表示为扩展的ASCII码,表示按下的是特殊功能键*/
/* 由于while(!kbhit())的“再说一点”所以这里bioskey()函数仍然能捕获这个按键的信息。 */
if(key==ESC)/*按ESC键退出*/
break;
else if(key==UP&&snake.direction!=4)
/*判断是否往相反的方向移动,如果不是相反方向才确认新的方向*/
snake.direction=3;
else if(key==RIGHT&&snake.direction!=2)
snake.direction=1;
else if(key==LEFT&&snake.direction!=1)
snake.direction=2;
else if(key==DOWN&&snake.direction!=3)
snake.direction=4;
}/*end:while(1)*/
}
/*游戏结束*/
void GameOver(void)
{
cleardevice(); /* 清除整个屏幕,并且将当前位置移到屏幕原点。该函数类似于文本模式下的函数clrscr(),但clrscr()函数不能在图形方式下工作;同样cleardevice()函数不能在文本模式下工作。 */
PrScore();
setcolor(15); /* 以下三个函数见PrScore()中说明 */
settextstyle(0,0,4);
outtextxy(200,200,"GAME OVER");
getch();
}
/*输出成绩*/
void PrScore(void)
{
char str[10];
setfillstyle(SOLID_FILL,14); /* 为各种图形函数设置填充图样和颜色 */
bar(50,15,220,35); /* 用当前填充图样和填充色(注意不是给图色)画出一个指定上左上角与右下角的实心长条形(长方块或正方块),但没有四条边线 */
/* bar()函数调用方式为void bar(int left,int top,int right,int bottom);调用此函数前,可用setfillstyle()或setfillpattern()设置当前填充图样和填充色。 */
setcolor(6); /* 函数setcolor()设置当前绘图颜色(或称做前景色)。voids setcolor(int color);在低分辨率显示模式(320X200)下,选取的color是调色板颜色号,不是实际色彩值。 */
settextstyle(0,0,2); /* 为图形输出设置当前的文本属性 void far settextstyle (int font, int direction, char size); 设置图形文本当前字体、文本显示方向(水平显示或垂直显示)以及字符大小。 */
sprintf(str,"score:%d",score); /* score已经被定义成了全局变量,score内容格式化到str */
outtextxy(55,20,str); /* 在(x,y)处显示字符串 */
}
/*图形结束*/
void Close(void)
{
getch();
closegraph(); /* 关闭图形系统 */
}
[求助][贪吃蛇]源程序,请教其中一个问题。