鱼C论坛

 找回密码
 立即注册
查看: 3115|回复: 30

[已解决]一个贪吃蛇的小问题,百思不得骑姐

[复制链接]
发表于 2018-8-2 03:09:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 sswy 于 2018-8-2 03:14 编辑
  1. //头文件需要用的函数
  2. #include <stdio.h>//标准输入输出的库函数
  3. #include <time.h>//要用随机数所以用time函数
  4. #include <Windows.h>//需要,控制DOS界面,要在DOS界面中设置文字颜色,获取坐标位置
  5. #include <stdlib.h>//宏定义和通用工具函数
  6. #include <conio.h>//接收键盘输入输出

  7. //宏定义用来定义上下左右方向,把方向定义成整型的数字,方便在后面代码中进行逻辑运算
  8. #define U 1
  9. #define D 2
  10. #define L 3
  11. #define R 4

  12. //全局变量
  13. typedef struct Snake   //蛇身的一个节点
  14. {
  15.         int x;                           //用来存放节点X坐标
  16.         int y;                           //用来存放节点Y坐标
  17.         struct Snake *next;//蛇身的下一个节点
  18. }SNAKE;



  19. int score = 0, add = 10;//总得分,每次吃食物得分

  20. int HighScore = 0;//游戏最高分

  21. int sleeptime = 200;//sleeptime每次运行的时间间隔

  22. int status; //方向

  23. SNAKE *head, *food;//蛇头指针和食物指针

  24. SNAKE *q;//便利蛇身

  25. int endgamestatus = 0;//表示游戏状态结束的情况,因为有3种情况,咬到自己,撞到墙,主动退出

  26. HANDLE hOut;//为了使用windows函数,建立句柄,它本身是void *


  27.                         /*************函数声明**************/
  28. void gotoxy(int x, int y);//光标位置函数
  29. int color(int c);        //设置文字颜色
  30. void printsnake();        //开始界面蛇绘制
  31. void welcometogame();     //开始界面
  32. void creatMap();          //绘制游戏地图
  33. void scoreandtips();      //游戏界面右侧的得分和小提示
  34. void initsnake();         //初始化蛇身,绘制蛇身
  35. void createfood();        //创建并随机出现食物
  36. int biteself();                  //判断是否咬到了自己
  37. void cantcrosswall();     //设置蛇撞墙情况
  38. void speedup();                          //加速
  39. void speeddown();                  //减速
  40. void snakemove();                  //控制蛇前进方向
  41. void keyboardControl();   //控制键盘按键
  42. void lostdraw();                  //游戏结束界面
  43. void endgame();                          //游戏结束
  44. void choose();                          //游戏失败后的选择
  45. void File_out();                  //存储最高分进文件
  46. void File_in();                          //在文件种读取最高分
  47. void explation();                  //游戏说明


  48. //设置颜色函数
  49. int color(int c)
  50. {

  51.         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);//设置颜色


  52.         return 0;
  53. }

  54. //控制台移动函数
  55. void gotoxy(int x, int y)
  56. {
  57.         COORD c;//通过修改pos.X和pos.Y的值就可以实现光标的位置控制。
  58.         c.X = x;
  59.         c.Y = y;
  60.         SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);//控制光标位置
  61. }

  62. //在界面中绘制蛇
  63. void printsnake()
  64. {
  65.         //利用建立好的移动函数和颜色函数绘制图形

  66.         color(6);//用颜色函数给字体上色
  67.         gotoxy(35, 1);//移动光标到合适位置,打印出图案
  68.         printf("/^\\/^\");//注意哦C语言中要答应出\需要多加一个\

  69.         gotoxy(34, 2);//移动光标到第二行,打印出图案
  70.         printf("|_| o|");
  71.         gotoxy(33, 2);
  72.         color(2);
  73.         printf("_");

  74.         gotoxy(25, 3);
  75.         color(12);
  76.         printf("\\/");                      //蛇信

  77.         gotoxy(31, 3);
  78.         color(2);
  79.         printf("/");

  80.         gotoxy(37, 3);
  81.         color(6);
  82.         printf(" \\_/");                     //蛇眼睛

  83.         gotoxy(41, 3);
  84.         color(10);
  85.         printf(" \");

  86.         gotoxy(26, 4);
  87.         color(12);
  88.         printf("\\____");                   //舌头

  89.         gotoxy(32, 4);
  90.         printf("_________/");

  91.         gotoxy(31, 4);
  92.         color(2);
  93.         printf("|");

  94.         gotoxy(43, 4);
  95.         color(10);
  96.         printf("\");

  97.         gotoxy(32, 5);
  98.         color(2);
  99.         printf("\\_______");     //蛇嘴

  100.         gotoxy(44, 5);
  101.         color(10);
  102.         printf("\");

  103.         gotoxy(39, 6);
  104.         printf("|     |                  \");  //下面都是画蛇身

  105.         gotoxy(38, 7);
  106.         printf("/      /                   \");

  107.         gotoxy(37, 8);
  108.         printf("/      /                    \\ \");

  109.         gotoxy(35, 9);
  110.         printf("/      /                       \\ \");

  111.         gotoxy(34, 10);
  112.         printf("/     /                          \\  \");

  113.         gotoxy(33, 11);
  114.         printf("/     /             _----_         \\   \");

  115.         gotoxy(32, 12);
  116.         printf("/     /           _-~      ~-_         |  |");

  117.         gotoxy(31, 13);
  118.         printf("(      (        _-~    _--_    ~-_     _/  |");

  119.         gotoxy(32, 14);
  120.         printf("\\     ~-____-~    _-~    ~-_    ~-_-~    /");

  121.         gotoxy(33, 15);
  122.         printf("~-_           _-~          ~-_       _-~");

  123.         gotoxy(35, 16);
  124.         printf("~--______-~                ~-___-~");







  125. }

  126. //欢迎界面
  127. void welcometogame()
  128. {
  129.         int n;
  130.         int i, j = 1;
  131.         color(11);//设置"贪吃蛇大作战"字体颜色
  132.                           //gotoxy(43, 18);//调整光标位置
  133.                           //printf("贪 吃 蛇 大 作 战");//打印


  134.         color(14);//设置边框颜色


  135.         for (i = 20; i <= 26; i++)//移动纵横坐标光标,打印边框
  136.         {

  137.                 for (j = 27; j < 74; j++)
  138.                 {
  139.                         gotoxy(j, i);//移动光标 x不停移动j就是x

  140.                         if (i == 20 || i == 26)//横向定位打印范围      打印横边框
  141.                         {
  142.                                 printf("-");
  143.                         }
  144.                         else if (j == 27 || j == 73)//横向定位2条边的位置才打印    打印竖边框
  145.                         {
  146.                                 printf("|");
  147.                         }
  148.                 }
  149.         }

  150.         //打印选择文字
  151.         color(12);
  152.         gotoxy(35, 22);
  153.         printf("1.开始游戏");
  154.         gotoxy(55, 22);
  155.         printf("2.游戏说明");
  156.         gotoxy(35, 24);
  157.         printf("3.退出游戏");


  158.         //打印下方小文字并根据输入进入函数
  159.         color(3);
  160.         gotoxy(29, 27);
  161.         printf("请选择[1 2 3]:[ ]\b\b");//  \b就是光标退格


  162.         color(14);//输入选择的文字
  163.         scanf("%d", &n);//输入选择

  164.         switch (n)
  165.         {
  166.         case 1:
  167.                 system("cls");//发出DOS命令,清屏
  168.                 creatMap();


  169.                 initsnake();
  170.                 createfood();

  171.                 break;
  172.         case 2:
  173.                 break;

  174.         case 3: exit(0);
  175.                 break;

  176.         default:
  177.                 printf("乱输入我就退出\n");
  178.                 break;
  179.         }

  180. }

  181. //创建地图
  182. void creatMap()
  183. {
  184.         int i, j;

  185.         //打印上下边框(外围)
  186.         for (i = 0; i < 58; i += 2)//因为小方括占用2个字符,所以是i+=2
  187.         {
  188.                 color(5);//边框颜色

  189.                 gotoxy(i, 0);//上坐标
  190.                 printf("●");

  191.                 gotoxy(i, 26);//下坐标
  192.                 printf("●");
  193.         }

  194.         //打印左右竖边框(外围)
  195.         for (i = 1; i < 26; i++)
  196.         {
  197.                 gotoxy(0, i);//打印左边竖边框
  198.                 printf("●");

  199.                 gotoxy(56, i);//打印右边竖边框
  200.                 printf("●");
  201.         }


  202.         //打印棋盘内部
  203.         for (i = 2; i < 56; i += 2)
  204.         {
  205.                 for (j = 1; j < 26; j++)
  206.                 {
  207.                         gotoxy(i, j);
  208.                         color(3);
  209.                         printf("●\n\n");
  210.                 }

  211.         }






  212. }

  213. //创建地图右侧信息
  214. void scoreandtips()//此函数应该在键盘控制的函数中调用,因为每次按键,如果蛇吃到食物,得分都会变化
  215. {
  216.         //File_out();//读取游戏最高分函数

  217.         //打印最高记录和当前得分信息
  218.         color(11);
  219.         gotoxy(64, 4);
  220.         printf("最高记录:%d", HighScore);
  221.         color(11);
  222.         gotoxy(64, 8);
  223.         printf("得分:%d", score);


  224.         //打印小提示
  225.         color(13);//设置颜色
  226.         gotoxy(73, 11);//移动光标
  227.         printf("小提示");//打印

  228.         color(6);//设置颜色
  229.         gotoxy(60, 13);//移动光标
  230.         printf("------------------------------------");//打印
  231.         gotoxy(60, 25);//移动光标
  232.         printf("------------------------------------");//打印

  233.         color(3);
  234.         gotoxy(64, 14);
  235.         printf("每个食物得分:%d分", add);
  236.         gotoxy(64, 16);
  237.         printf("不能撞墙,不能咬到自己");
  238.         gotoxy(64, 18);
  239.         printf("用↑ ↓ ← →分别控制蛇的移动");
  240.         gotoxy(64, 20);
  241.         printf("F1 为加速,F2 为减速");
  242.         gotoxy(64, 22);
  243.         printf("SPACE:暂停游戏");
  244.         gotoxy(64, 24);
  245.         printf("ESC :退出游戏");



  246. }

  247. //读取文本中最高分
  248. void File_in()
  249. {
  250.         FILE *fp;
  251.         fp = fopen("save.txt", "a+");//a+以附加的方式,打开文件,文件不存在创建文件
  252.         fscanf(fp, "%d", &HighScore);//把读取文件中数据给全局变量
  253.         fclose(fp);
  254. }

  255. //绘制蛇身,其实就是定位蛇的初始位置,调整光标位置,打印结构体
  256. void initsnake()
  257. {
  258.         SNAKE *tail;//蛇身
  259.         int i;
  260.         tail = (SNAKE *)malloc(sizeof(SNAKE));//创建蛇尾
  261.         tail->x = 24;//蛇尾坐标定义
  262.         tail->y = 5;
  263.         tail->next = NULL;


  264.         for (i = 1; i <= 4; i++)//分配蛇的光标位置
  265.         {
  266.                 head = (SNAKE *)malloc(sizeof(SNAKE));//创建蛇头
  267.                 head->next = tail;//指向蛇身
  268.                 head->x = 24 + 2 * i;//2代表一个格子
  269.                 head->y = 5;//纵向坐标y,y不动和尾巴在同一排
  270.                 tail = head;//类似头插法
  271.         }

  272.        

  273.         //打印蛇身
  274.         while (tail != NULL)//因为tail = head,所以tail在for结束后是头指针
  275.         {
  276.                 gotoxy(tail->x, tail->y);//根据每一个结构体坐标调整光标位置,并打印出来
  277.                 color(14);
  278.                 printf("★");
  279.                 tail = tail->next;
  280.         }
  281. }

  282. //创建并随机出现食物
  283. void createfood()
  284. {
  285.         SNAKE *food_1=NULL;//创建食物指针


  286.         srand((unsigned)time(NULL));//随机种子

  287.         food_1 = (SNAKE*)malloc(sizeof(SNAKE));//给食物内存
  288.         food_1->next = NULL;

  289.         while ((food_1->x % 2) != 0)//限制食物只会出现在棋盘中的坐标,准备把坐标给到移动光标,绘制食物           %2这里余2是要求食物在棋盘格中间
  290.         {
  291.                 food_1->x = rand() % 25 + 2;//棋盘格子宽度是52  让食物出现在X轴最小限制2-52之间   2因为是2个字符为一个格子


  292.         }
  293.         food_1->y = 24 + 1;//棋盘格子长度是24 让食物出现在Y轴最小限制1-24之间     1因为是纵向1个字符为1列


  294.         q = head;//取得蛇头头指针
  295.        

  296.         //int num = 20;//递归返回的时候可以记录进入递归之前的值,但是如果是指针,无法记录之前的
  297.         char ch = 'n';
  298.         while ( q != NULL)//蛇任何一个部分都不能和食物重叠
  299.         {
  300.                 //num -= 1;
  301.                 if (q->x == food_1->x && q->y == food_1->y)//如果随机出现的食物坐标和蛇初始化坐标重叠,删除这个食物内容,重新创建
  302.                 {
  303.                         free(food_1);//释放当前食物内容

  304.                         /*
  305.                         food_1 = (SNAKE*)malloc(sizeof(SNAKE));
  306.                         while ((food_1->x % 2) != 0)
  307.                         {
  308.                                 food_1->x = rand() % 52 + 2;
  309.                                 food_1->y = 24 + 1;
  310.                                 q = head;
  311.                         }
  312.                         */
  313.                         ch = 'y';
  314.                         createfood();//递归重新创建食物坐标,但是这里注意递归进去后,循环q到NULL运行完毕,函数返回来位置在if(ch=='y'),q坐标已经被移动到NULL了,指针无法记录之前的
  315.                        


  316.                 }
  317.                 if (ch == 'y')
  318.                 {
  319.                         food_1 = food;
  320.                         return;
  321.                 }
  322.                 q = q->next;//蛇身上任何坐标不能和食物重合

  323.                 if (q == NULL)
  324.                 {
  325.                         break;
  326.                 }
  327.         }

  328.         gotoxy(food_1->x, food_1->y);//把随机好的食物坐标给到移动光标里,并绘制出来
  329.         free(food);
  330.         food = food_1;//把食物指针给出去全局指针

  331.        

  332.         color(12);//食物颜色

  333.         printf("●");//绘制食物

  334. }

  335. //判断蛇咬到自己
  336. int biteself()
  337. {
  338.         SNAKE *self;
  339.         q = head;
  340.         self = head;



  341.         while (q ->next!= NULL)//任何一个点碰到身体算失败
  342.         {
  343.                 q = q->next;
  344.                 if (self->x == q->x && self->y == q->y)
  345.                 {
  346.                         return 1;//返回1表示蛇咬到了自己
  347.                 }


  348.         }
  349.         return 0;
  350. }

  351. //判断蛇是否撞墙
  352. void cantcrosswall()
  353. {
  354.         if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
  355.         {
  356.                 endgamestatus = 1;//撞墙情况的失败界面,给全局
  357.                 printf("撞墙失败");
  358.                 exit(1);
  359.                 return;
  360.         }

  361. }

  362. //蛇加速前进
  363. void speedup()
  364. {
  365.         if (sleeptime >= 50)//限制50的刷新率,
  366.         {
  367.                 sleeptime = sleeptime - 10; //时间间隔 - 10  刷新更快了
  368.                 add = add + 2;//同时每吃一个食物的得分+2,可叠加再吃到14再吃到16   add全局基础得分
  369.         }

  370. }

  371. //蛇减速减速
  372. void speeddown()
  373. {
  374.         if (sleeptime < 350)//限制时间间隔小于350不能太慢了哈
  375.         {
  376.                 sleeptime = sleeptime + 30;//加大刷新间隔,速度就慢了


  377.                 add = add - 2;//减速了游戏就很容易,所以降低基础分

  378.                 if (sleeptime == 350)//当游戏最慢的时候,基础分为1
  379.                 {
  380.                         add = 1;
  381.                 }
  382.         }

  383. }

  384. //不按键时蛇前进,蛇的动力都在这里,这个程序就类似,1帧一个执行,1帧一个执行,可以这样想象,用程序执行间隔Sleep控制蛇的运行速度
  385. void snakemove()
  386. {
  387.         //这个动力其实就是把新的结构体节点,根据当前蛇头位置移动一个位置,然后不断捕捉键盘方向,来循环移动

  388.         SNAKE *nexthead;//表示蛇头下一个位置,新的头指针,代表新的位置,类似移动了一步
  389.         cantcrosswall();//判断蛇是否撞墙
  390.         nexthead = (SNAKE*)malloc(sizeof(SNAKE));//为下一步开辟一个空间

  391.        

  392.         if (status == U)//向上移动一个格子,其实就是根据头指针位置放一个新结构体,再删除最后的尾巴
  393.         {
  394.                 //不断向上前进
  395.                 nexthead->x = head->x;   //新节点保持当前横向坐标不变 ,因为我们要上移一格,所以直接改Y就好了
  396.                 nexthead->y = head->y - 1; //新节点,上移动一个光标位置,因为y是间隔1个字符,所以-1
  397.                 nexthead->next = head;   //链接老蛇头,并把当前地址设成最新蛇头
  398.                 head = nexthead;

  399.                 q = head;//给一个全局傀儡方便控制

  400.                 if (nexthead->x == food->x && nexthead->y == food->y)
  401.                 {
  402.                        

  403.                         while (q != NULL)//当上一移动位置和食物位置重叠,就把当前位置画出来,并不删除尾巴上的
  404.                         {
  405.                                 gotoxy(q->x, q->y);
  406.                                 color(14);
  407.                                 printf("★");
  408.                                 q = q->next;
  409.                         }
  410.                         score = score + add;//食物吃到后加10分

  411.                         speedup();//加速 速度初始200  并且提高下次吃到食物的基础分数

  412.                         createfood();//重新生成食物
  413.                 }
  414.                 else//如果没有吃到食物就把痕迹删除
  415.                 {
  416.                        

  417.                         while (q->next->next != NULL)//当上一移动位置和食物位置没有重叠,就打印当前蛇,但是要把最后一个痕迹删除
  418.                         {
  419.                                 gotoxy(q->x, q->y);
  420.                                 color(14);
  421.                                 printf("★");
  422.                                 q = q->next;
  423.                         }

  424.                         gotoxy(q->next->x, q->next->y);  //清除蛇尾巴,因为移动了一个位置,就要把后面的去除并还原棋盘格
  425.                         color(3);
  426.                         printf("■");
  427.                         free(q->next);        //释放尾巴结构体
  428.                         q->next = NULL;       //当前结构体,指向空
  429.                 }
  430.         }


  431.         if (status == D)//向上移动一个格子,其实就是根据头指针位置放一个新结构体,再删除最后的尾巴
  432.         {
  433.                 //不断向上前进
  434.                 nexthead->x = head->x;   //新节点保持当前横向坐标不变 ,因为我们要上移一格,所以直接改Y就好了
  435.                 nexthead->y = head->y+1; //新节点,上移动一个光标位置,因为y是间隔1个字符,所以-1
  436.                 nexthead->next = head;   //链接老蛇头,并把当前地址设成最新蛇头
  437.                 head = nexthead;

  438.                 q = head;//给一个全局傀儡方便控制

  439.                 if (nexthead->x == food->x && nexthead->y == food->y)
  440.                 {
  441.                

  442.                         while (q != NULL)//当上一移动位置和食物位置重叠,就把当前位置画出来,并不删除尾巴上的
  443.                         {
  444.                                 gotoxy(q->x, q->y);
  445.                                 color(14);
  446.                                 printf("★");
  447.                                 q = q->next;
  448.                         }
  449.                         score = score + add;//食物吃到后加10分

  450.                         speedup();//加速 速度初始200  并且提高下次吃到食物的基础分数

  451.                         createfood();//重新生成食物
  452.                 }
  453.                 else//如果没有吃到食物就把痕迹删除
  454.                 {
  455.                

  456.                         while (q->next->next != NULL)//当上一移动位置和食物位置没有重叠,就打印当前蛇,但是要把最后一个痕迹删除
  457.                         {
  458.                                 gotoxy(q->x, q->y);
  459.                                 color(14);
  460.                                 printf("★");
  461.                                 q = q->next;
  462.                         }

  463.                         gotoxy(q->next->x, q->next->y);  //清除蛇尾巴,因为移动了一个位置,就要把后面的去除并还原棋盘格
  464.                         color(3);
  465.                         printf("■");
  466.                         free(q->next);        //释放尾巴结构体
  467.                         q->next = NULL;       //当前结构体,指向空
  468.                 }
  469.         }


  470.         if (status == L)//向上移动一个格子,其实就是根据头指针位置放一个新结构体,再删除最后的尾巴
  471.         {
  472.                 //不断向上前进
  473.                 nexthead->x = head->x-2;   //新节点保持当前横向坐标不变 ,因为我们要上移一格,所以直接改Y就好了
  474.                 nexthead->y = head->y; //新节点,上移动一个光标位置,因为y是间隔1个字符,所以-1
  475.                 nexthead->next = head;   //链接老蛇头,并把当前地址设成最新蛇头
  476.                 head = nexthead;

  477.                 q = head;//给一个全局傀儡方便控制

  478.                 if (nexthead->x == food->x && nexthead->y == food->y)
  479.                 {
  480.                

  481.                         while (q != NULL)//当上一移动位置和食物位置重叠,就把当前位置画出来,并不删除尾巴上的
  482.                         {
  483.                                 gotoxy(q->x, q->y);
  484.                                 color(14);
  485.                                 printf("★");
  486.                                 q = q->next;
  487.                         }
  488.                         score = score + add;//食物吃到后加10分

  489.                         speedup();//加速 速度初始200  并且提高下次吃到食物的基础分数

  490.                         createfood();//重新生成食物
  491.                 }
  492.                 else//如果没有吃到食物就把痕迹删除
  493.                 {
  494.                

  495.                         while (q->next->next != NULL)//当上一移动位置和食物位置没有重叠,就打印当前蛇,但是要把最后一个痕迹删除
  496.                         {
  497.                                 gotoxy(q->x, q->y);
  498.                                 color(14);
  499.                                 printf("★");
  500.                                 q = q->next;
  501.                         }

  502.                         gotoxy(q->next->x, q->next->y);  //清除蛇尾巴,因为移动了一个位置,就要把后面的去除并还原棋盘格
  503.                         color(3);
  504.                         printf("■");
  505.                         free(q->next);        //释放尾巴结构体
  506.                         q->next = NULL;       //当前结构体,指向空
  507.                 }
  508.         }


  509.         if (status == R)//向上移动一个格子,其实就是根据头指针位置放一个新结构体,再删除最后的尾巴
  510.         {
  511.                 //不断向上前进
  512.                 nexthead->x = head->x + 2;   //新节点保持当前横向坐标不变 ,因为我们要上移一格,所以直接改Y就好了
  513.                 nexthead->y = head->y; //新节点,上移动一个光标位置,因为y是间隔1个字符,所以-1
  514.                 nexthead->next = head;   //链接老蛇头,并把当前地址设成最新蛇头
  515.                 head = nexthead;

  516.                 q = head;//给一个全局傀儡方便控制

  517.                 if (nexthead->x == food->x && nexthead->y == food->y)
  518.                 {
  519.                

  520.                         while (q != NULL)//当上一移动位置和食物位置重叠,就把当前位置画出来,并不删除尾巴上的
  521.                         {
  522.                                 gotoxy(q->x, q->y);
  523.                                 color(14);
  524.                                 printf("★");
  525.                                 q = q->next;
  526.                         }
  527.                         score = score + add;//食物吃到后加10分

  528.                         speedup();//加速 速度初始200  并且提高下次吃到食物的基础分数

  529.                         createfood();//重新生成食物
  530.                 }
  531.                 else//如果没有吃到食物就把痕迹删除
  532.                 {
  533.        


  534.                         while (q->next->next != NULL)//当上一移动位置和食物位置没有重叠,就打印当前蛇,但是要把最后一个痕迹删除
  535.                         {
  536.                                 gotoxy(q->x, q->y);
  537.                                 color(14);
  538.                                 printf("★");
  539.                                 q = q->next;
  540.                         }

  541.                         gotoxy(q->next->x, q->next->y);  //清除蛇尾巴,因为移动了一个位置,就要把后面的去除并还原棋盘格
  542.                         color(3);
  543.                         printf("■");
  544.                         free(q->next);        //释放尾巴结构体
  545.                         q->next = NULL;       //当前结构体,指向空
  546.                 }
  547.         }








  548.         if (biteself() == 1)//判断是否吃到自己    为什么先判断撞墙呢,因为要判断当前蛇头位置是否和最开始的边沿重合   

  549.                                             //而吃到自己是要在自己移动后判断是否蛇头和身体重合
  550.         {
  551.                 endgamestatus = 2;
  552.         }


  553. }

  554. //控制键盘按键
  555. void keyboardControl()
  556. {
  557.         status = R;//设置初始移动方向为右

  558.         while (1)//可以一直按键所以设置循环
  559.         {
  560.                 scoreandtips();//游戏右侧得分小提示

  561.                 if (GetAsyncKeyState(VK_UP) && status != D)//运行方向不是向下,就可以记录上
  562.                 {
  563.                         status = U;
  564.                 }
  565.                 else if (GetAsyncKeyState(VK_DOWN) && status != U)
  566.                 {
  567.                         status = D;
  568.                 }
  569.                 else if (GetAsyncKeyState(VK_LEFT) && status != R)
  570.                 {
  571.                         status = L;
  572.                 }
  573.                 else if (GetAsyncKeyState(VK_RIGHT)  && status != L)
  574.                 {
  575.                         status = R;
  576.                 }


  577.                 if (GetAsyncKeyState(VK_SPACE))//如果按下空格键,暂停游戏300毫秒
  578.                 {
  579.                         Sleep(300);
  580.                         if (GetAsyncKeyState(VK_SPACE))
  581.                         {
  582.                                 break;

  583.                         }
  584.                 }
  585.                 else if (GetAsyncKeyState(VK_ESCAPE))//如果按了ESC键就退出游戏
  586.                 {
  587.                         endgamestatus = 3;
  588.                         break;
  589.                 }
  590.                 else if (GetAsyncKeyState(VK_F1))//如果按了F1键就加速
  591.                 {

  592.                         speedup();
  593.                 }
  594.                 else if (GetAsyncKeyState(VK_F2))//如果按了F1键就加速
  595.                 {
  596.                         speeddown();
  597.                 }

  598.                 Sleep(sleeptime);//控制刷新率

  599.                 snakemove();
  600.         }
  601. }





  602. int main(void)//每一个函数解决一个单一问题,进行组合,在以后编程中也要这样
  603. {
  604.         system("mode con cols=100 lines=30");//让C语言发一个DOS命令,设置窗口宽度高度
  605.         printsnake();//输出绘制图案


  606.         welcometogame();//输出边框和文
  607.         //File_in();//把文件中最高分读取进来

  608.        
  609.         keyboardControl();


  610.         return 0;
  611. }
复制代码






代码有点长,但是只需要看 <创建并随机出现食物函数>   那里就好了。   
问题是这样的:在游戏初始化的时候,随机出现食物,代码如下,并且食物如果随机出现的坐标和蛇身坐标重合,就重新定位食物坐标。
实现方式我用了递归和常规2种方式,常规的没有问题,但是递归的在游戏运行的时候就会卡死,关键是我找了很久很久问题所在都觉得是正确的,但是程序就是要卡死。希望老师们能看看这个隐藏问题,当研究研究玩耍,但是请b21老师绕道,哈哈哈




while ( q != NULL)//蛇任何一个部分都不能和食物重叠
        {
                //num -= 1;
                if (q->x == food_1->x && q->y == food_1->y)//如果随机出现的食物坐标和蛇初始化坐标重叠,删除这个食物内容,重新创建
                {
                        free(food_1);//释放当前食物内容

                        /*
                        food_1 = (SNAKE*)malloc(sizeof(SNAKE));
                        while ((food_1->x % 2) != 0)
                        {
                                food_1->x = rand() % 52 + 2;
                                food_1->y = 24 + 1;
                                q = head;
                        }
                        */
                        ch = 'y';
                        createfood();//递归重新创建食物坐标,但是这里注意递归进去后,循环q到NULL运行完毕,函数返回来位置在if(ch=='y'),q坐标已经被移动到NULL了,指针无法记录之前的
                       


                }
                if (ch == 'y')
                {
                        food_1 = food;
                        return;
                }
                q = q->next;//蛇身上任何坐标不能和食物重合

                if (q == NULL)
                {
                        break;
                }
        }





最佳答案
2018-8-2 13:28:39
y坐标一直是24 + 1
一直是25
x坐标虽然是随机的,但是很难超过20
如果蛇占用了这些位置,那就一直递归

(, 下载次数: 0)
(, 下载次数: 0)
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-8-2 14:49:59 | 显示全部楼层
无符号整形 发表于 2018-8-2 08:35
407行那个赋值坏了事,把ch又还原了。
另外我的vs2013编译通过不了你用的是vc6还是cb?

vs2017 嘻嘻

点评

……哎~  发表于 2018-8-2 14:50
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 14:52:36 | 显示全部楼层

谢谢老师,太牛了,您应该当版主
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 14:59:46 | 显示全部楼层

老师,您好,因为那个Y坐标,我也是故意不随机的,希望食物经常和身体重合,但是用DBUG调试,照理说一直递归,就别跳出来嘛,结果用DBUG调试就不会一直递归,而且感觉没问题,但是一运行程序才显现问题
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 15:03:14 | 显示全部楼层
人造人 发表于 2018-8-2 13:28
y坐标一直是24 + 1
一直是25
x坐标虽然是随机的,但是很难超过20

我觉得问题可能不是在这里,因为照理说,食物和身体重合,递归进去,X坐标还是会随机,一直随机到不在身体上为止,不会因为说食物和身体重合,就一直递归。。。。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 16:15:25 | 显示全部楼层
人造人 发表于 2018-8-2 15:27
种子值一样,得到的随机值就一样
这就是伪随机

醍醐灌顶,请问老师如此隐蔽的问题,老师您是怎么发现的?之前遇上过这样的问题?
太感谢人造人老师了,谢谢谢谢谢谢,太谢谢了

我其实找这个问题至少找了8小时,真的百思不得其解,没想到是这个随机数问题,我开始以为是内存堆栈溢

出,或者是内存没释放干净,或者是内存污染,太没想到了,按正常思维,根本想不到是伪随机数,再次感谢人造人老师!

~~而且这个问题DBUG根本不会报错,递归还有去有回,程序还每一步执行的好好的,太烧人了,还好有老

师解答,要不这个问题不知道什么时候我才会明白
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 16:16:35 | 显示全部楼层
人造人 发表于 2018-8-2 15:27
种子值一样,得到的随机值就一样
这就是伪随机

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 16:49:33 | 显示全部楼层
人造人 发表于 2018-8-2 15:52
你能确定这里是25吗?
还是说你把52写成了25?

这里不是25老师,是52或者53我记不清楚了,但是这里是因为我故意把x位置调小,让程序多出错,我好方便看为什么
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 16:53:03 | 显示全部楼层
人造人 发表于 2018-8-2 16:38
这是在调试,需要一个合适的速度,太快了没办法调试,太慢了也不行

然后就是调试运行

也就是说DBUG需要一个合适的速度?。。。。。这个这个这。。。。什么速度比较合适,。。。。。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 17:03:20 | 显示全部楼层
人造人 发表于 2018-8-2 16:38
这是在调试,需要一个合适的速度,太快了没办法调试,太慢了也不行

然后就是调试运行

合适的速度,是否是调试的时候多试试Sleep呢?我就没有这个提示
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 20:04:35 | 显示全部楼层
人造人 发表于 2018-8-2 18:14
录了个视频,18分钟,耐心看完
不得不说一下百度云的上传速度
230MB的文件花了半个多小时

太谢谢老师了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 20:16:00 | 显示全部楼层
人造人 发表于 2018-8-2 18:14
录了个视频,18分钟,耐心看完
不得不说一下百度云的上传速度
230MB的文件花了半个多小时

必须耐心每一个秒,每一帧都要看
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-2 22:26:24 | 显示全部楼层

谢谢老师,视频我已经反复观看并学习,虽然老师玩游戏撞了几次墙,但是耐心解答,让我想起了一首歌
<好人一生平安>

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-11-5 08:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表