oclassic 发表于 2007-4-23 18:33

[求助][贪吃蛇]源程序,请教其中一个问题。

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

oclassic 发表于 2007-4-26 16:30

晕.没人回答啊/[em03]

zj860713 发表于 2007-5-20 11:32

<P>LZ我运行了下,好像没有食物啊![em06]<BR><BR></P>

页: [1]

编程论坛