上节我们用方向控制函数写了个小画图程序,它虽然简单好玩,但我们不应该止步于此。革命尚未成功,同志还需努力。

开始撸代码之前,我们先理清一下思路。和前面画图程序不同,贪吃蛇可以有很多节,可以用一个足够大的结构体数组来储存它。 还需要一个食物坐标。定义如下:

typedef struct Position  //坐标结构
{int x;int y;
}Pos;Pos array;                         //移动方向向量
Pos snake[300000] = {};  //蛇的结构体数组,谁能够无聊到吃299999个食物~_~long len=1;                      //蛇的长度Pos egg; //食物坐标

之前的画图程序是四个方向都可以走,可蛇是不能倒着走的,所以方向控制函数要改成这样:

void command()                              //获取键盘命令
{if (_kbhit())       //如果有键盘消息switch (_getch())      /*这里不能用getchar()*/{case 'a':if (array.x != 1 || array.y != 0) {//如果命令不是倒着走,就修正方向向量,否则不做改变,下同。array.x = -1;array.y = 0;}break;case 'd':if (array.x != -1 || array.y != 0) {array.x = 1;array.y = 0;}break;case 'w':if (array.x != 0 || array.y != 1) {array.x = 0;array.y = -1;}break;case 's':if (array.x != 0 || array.y != -1) {array.x = 0;array.y = 1;}break;}
} 

蛇可能不止一节,所以移动函数需要做出改变。仔细一想就知道,走了一步之后,除了头结点外,每个节点的下一个坐标为它前一个结点之前的坐标,而头节点的坐标等于它本身坐标加上移动向量(这里是 方向向量*10)

还有个问题是蛇走过的痕迹需要擦除,每走一步,它留下的痕迹应该是走这一步之前蛇的最末一个结点的坐标,我们需要擦除掉它。

结果如下:

void move()    //修改各节点坐标以达到移动的目的
{setcolor(BLACK);        //覆盖尾部走过的痕迹rectangle(snake[len-1].x - 5, snake[len-1].y - 5, snake[len-1].x + 5, snake[len-1].y + 5);for (int i = len-1; i >0; i--)    //除了头结点外,每个节点的下一个坐标为它前一个结点当前的坐标{snake[i].x = snake[i - 1].x;snake[i].y = snake[i - 1].y;}snake[0].x += array.x*10;             //头节点的坐标等于它本身坐标加上移动向量(这里是 方向向量*10)snake[0].y += array.y*10;
}

另外,我们的蛇是有穿墙术的~~~它的实现方法非常简单:

void break_wall()
{if (snake[0].x >= 640)             //如果越界,从另一边出来snake[0].x = 0;else if (snake[0].x <= 0)snake[0].x = 640;else if (snake[0].y >= 480)snake[0].y = 0;else if (snake[0].y <= 0)snake[0].y = 480;
}

接下来是食物相关函数,这个算是重点。

1. 食物生成

我们希望食物每次出现的位置都是随机的, 可以这样实现。

1         srand((unsigned)time(NULL));
2         egg.x = rand() % 80 * 5 + 100;    //头节点位置随机化
3         egg.y = rand() % 50 * 5 + 100;

而且食物不能与蛇重合,最好也不要离蛇太近。综合起来就是这样:(srand在初始化中会被调用,所以这里略去了)

void creat_egg()
{while (true){int ok = 0;   //这是个标记,用于判断函数是否进入了某一分支egg.x = rand() % 80 * 5 + 100;    //头节点位置随机化egg.y = rand() % 50 * 5 + 100;for (int i = 0; i < len; i++)     //判断是否离蛇太近
        {if (snake[i].x == 0 && snake[i].y == 0)continue;if (fabs(snake[i].x - egg.x) <= 10 && fabs(snake[i].y - egg.y) <= 10)ok = -1;   //如果,进入此分支,改变标记break;}if (ok == 0)    //如果不重合了,跳出函数return;}
}

2. 吃到食物

如果吃到食物,那么需要消除被吃掉的食物,生成新食物,蛇也要增长一节。

我觉得这里最麻烦的就是蛇变长的实现:是在蛇头添加一节,还是在蛇尾?添加在蛇头(尾)的上下左右哪一边?

想来想去,只有在蛇头位置,我们可以根据当前方向向量,在移动方向上新添一节。这对应的代码如下:

        //add snake nodelen += 1;for (int i = len - 1; i > 0; i--)    //所有数据后移一个单位,腾出snake[0]给新添的一节{snake[i].x = snake[i - 1].x;snake[i].y = snake[i - 1].y;}snake[0].x += array.x * 10;             //这就是新添的这一节的位置snake[0].y += array.y * 10;

吃到食物的完整代码如下:

void eat_egg()
{if (fabs(snake[0].x - egg.x) <= 5 && fabs(snake[0].y - egg.y) <= 5)    //判断是否吃到食物,因为食物位置有点小偏差,只好使用范围判定~~{setcolor(BLACK);          //hide old eggcircle(egg.x, egg.y, 5);creat_egg();            //create new egg//add snake nodelen += 1;for (int i = len - 1; i >0; i--){snake[i].x = snake[i - 1].x;snake[i].y = snake[i - 1].y;}snake[0].x += array.x * 10;             //每次移动10pixsnake[0].y += array.y * 10;}
}

游戏结束判定

最后,我们还差一个死亡判定,因为自带穿墙术,所以实际的死亡判定只有一个,就是咬到自己,代码如下:

void eat_self()
{if (len == 1)             //只有一节当然吃不到自己~~return;for (int i = 1; i < len; i++)if (fabs(snake[i].x - snake[0].x) <= 5 && fabs(snake[i].y - snake[0].y) <= 5)            //如果咬到自己(为了不出bug,使用了范围判定)
        {outtextxy(250, 200, "GAME OVER!");  //你的蛇死了~Sleep(3000);      //3s时间让你看看你的死相~~
            closegraph();exit(0);     //退出
        }
}

当然,你也可以直接丢掉这个函数,然后开心地狂咬自己—_—||

最后:画图函数

画出食物和蛇,其实蛇没必要全部画出来,只要画蛇头就可以了,但这之中有些小问题,谁有兴趣可以自己玩玩,我是懒得动了~

void draw()     //画出蛇和食物
{setcolor(BLUE);for (int i = 0; i < len; i++){rectangle(snake[i].x - 5, snake[i].y - 5, snake[i].x + 5, snake[i].y + 5);}setcolor(RED);        //画蛋(怎么感觉怪怪的~)circle(egg.x, egg.y, 5);Sleep(100);
}

到这里,游戏大功告成~~  什么?你说运行不起来?那是因为少了初始化函数,和游戏循环啦~~这几个都比较简单,就直接放下面了:

void init()              //初始化
{initgraph(640, 480);                    //初始化图形界面srand((unsigned)time(NULL));            //初始化随机函数snake[0].x = rand() % 80 * 5 + 100;    //头节点位置随机化snake[0].y = rand() % 50 * 5 + 100;array.x = pow(-1,rand());        //初始化方向向量,左或者右array.y = 0;creat_egg();
}int main()
{init();while (true){command();      //获取键盘消息move();         //修改头节点坐标-蛇的移动
        eat_egg();draw();         //作图
        eat_self();}return 0;
}

好了,这是真的大功告成了。给你们看看死亡方式之自尽:

完整代码如下:

  1 #include<graphics.h>
  2 #include<conio.h>
  3 #include<time.h>
  4 #include<math.h>
  5
  6 typedef struct Position  //坐标结构
  7 {
  8     int x;
  9     int y;
 10 }Pos;
 11
 12 Pos snake[300000] = {};
 13 Pos array;
 14 Pos egg;
 15 long len=1;
 16
 17 void creat_egg()
 18 {
 19     while (true)
 20     {
 21         int ok = 0;
 22         srand((unsigned)time(NULL));            //初始化随机函数
 23         egg.x = rand() % 80 * 5 + 100;    //头节点位置随机化
 24         egg.y = rand() % 50 * 5 + 100;
 25         for (int i = 0; i < len; i++)
 26         {
 27             if (snake[i].x == 0 && snake[i].y == 0)
 28                 continue;
 29             if (fabs(snake[i].x - egg.x) <= 10 && fabs(snake[i].y - egg.y) <= 10)
 30                 ok = -1;
 31                 break;
 32         }
 33         if (ok == 0)
 34             return;
 35     }
 36 }
 37
 38 void init()              //初始化
 39 {
 40     initgraph(640, 480);                    //初始化图形界面
 41     srand((unsigned)time(NULL));            //初始化随机函数
 42     snake[0].x = rand() % 80 * 5 + 100;    //头节点位置随机化
 43     snake[0].y = rand() % 50 * 5 + 100;
 44     array.x = pow(-1,rand());        //初始化方向向量
 45     array.y = 0;
 46     creat_egg();
 47 }
 48
 49 void command()                              //获取键盘命令
 50 {
 51     if (_kbhit())       //如果有键盘消息
 52         switch (_getch()/*这里不能用getchar()*/)
 53         {
 54         case 'a':
 55             if (array.x != 1 || array.y != 0) {//如果不是反方向
 56                 array.x = -1;
 57                 array.y = 0;
 58             }
 59             break;
 60         case 'd':
 61             if (array.x != -1 || array.y != 0) {
 62                 array.x = 1;
 63                 array.y = 0;
 64             }
 65             break;
 66         case 'w':
 67             if (array.x != 0 || array.y != 1) {
 68                 array.x = 0;
 69                 array.y = -1;
 70             }
 71             break;
 72         case 's':
 73             if (array.x != 0 || array.y != -1) {
 74                 array.x = 0;
 75                 array.y = 1;
 76             }
 77             break;
 78         }
 79 }
 80
 81 void move()    //修改各节点坐标以达到移动的目的
 82 {
 83     setcolor(BLACK);        //覆盖尾部走过的痕迹
 84     rectangle(snake[len-1].x - 5, snake[len-1].y - 5, snake[len-1].x + 5, snake[len-1].y + 5);
 85
 86     for (int i = len-1; i >0; i--)
 87     {
 88         snake[i].x = snake[i - 1].x;
 89         snake[i].y = snake[i - 1].y;
 90     }
 91     snake[0].x += array.x*10;             //每次移动10pix
 92     snake[0].y += array.y*10;
 93
 94     if (snake[0].x >= 640)             //如果越界,从另一边出来
 95         snake[0].x = 0;
 96     else if (snake[0].x <= 0)
 97         snake[0].x = 640;
 98     else if (snake[0].y >= 480)
 99         snake[0].y = 0;
100     else if (snake[0].y <= 0)
101         snake[0].y = 480;
102 }
103
104 void eat_egg()
105 {
106     if (fabs(snake[0].x - egg.x)<=5 && fabs(snake[0].y - egg.y)<=5)
107     {
108         setcolor(BLACK);          //shade old egg
109         circle(egg.x, egg.y, 5);
110         creat_egg();
111         //add snake node
112         len += 1;
113         for (int i = len - 1; i >0; i--)
114         {
115             snake[i].x = snake[i - 1].x;
116             snake[i].y = snake[i - 1].y;
117         }
118         snake[0].x += array.x * 10;             //每次移动10pix
119         snake[0].y += array.y * 10;
120     }
121 }
122
123 void draw()     //画出蛇和食物
124 {
125     setcolor(BLUE);
126     for (int i = 0; i < len; i++)
127     {
128         rectangle(snake[i].x - 5, snake[i].y - 5, snake[i].x + 5, snake[i].y + 5);
129     }
130     setcolor(RED);
131     circle(egg.x, egg.y, 5);
132     Sleep(100);
133 }
134
135 void eat_self()
136 {
137     if (len == 1)
138         return;
139     for (int i = 1; i < len; i++)
140         if (fabs(snake[i].x - snake[0].x) <= 5 && fabs(snake[i].y - snake[0].y) <= 5)
141         {
142             Sleep(1000);
143             outtextxy(250, 200, "GAME OVER!");
144             Sleep(3000);
145             closegraph();
146             exit(0);
147         }
148 }
149
150 int main()
151 {
152     init();
153     while (true)
154     {
155         command();      //获取键盘消息
156         move();         //修改头节点坐标-蛇的移动
157         eat_egg();
158         draw();         //作图
159         eat_self();
160     }
161
162     return 0;
163 }

snakey

可能还有若干bug留存,欢迎大家指正~~

甲铁城镇~

转载于:https://www.cnblogs.com/kirito-c/p/5596160.html

贪吃蛇—C—基于easyx图形库(下):从画图程序到贪吃蛇【自带穿墙术】相关推荐

  1. 用easyx画电子钟_基于EasyX图形库的多线程绘图应用

    本文<基于EasyX图形库的多线程绘图应用>由手机部落整理,仅供参考.如果觉得很不错,欢迎点评和分享-感谢你的阅读与支持! 张煜昕 摘要:EasyX 是C++语言进行图形化编程和游戏编程的 ...

  2. linux使用gcc实现扫雷,基于linux环境下扫雷应用程序

    基于linux环境下扫雷应用程序 (16页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 <网络操作系统>报告(应用程序开发) ...

  3. C++写的是男人就下一百层小游戏,基于EasyX图形库(本人菜鸟)

    是男人就下一百层 小游戏 游戏整体源代码已打包,在最下面 首先建立一个board类: #pragma once #ifndef BOARD_H_ #define BOARD_H_ const int ...

  4. C语言之五子棋项目 基于EasyX图形库

    C语言之五子棋 前言 一.EasyX图形库下载与安装 1.EasyX图形库下载 2.VS2019设置EasyX图形库 二.五子棋中用到的图形库知识 1.初始化页面 2.文字显示 3.鼠标操作 4.棋盘 ...

  5. c语言/c++大作业基于easyx图形库自制RPG类型小游戏代码(附源码)

    目录 一.游戏玩法 二.完整代码 三.部分细节 透明化人物背景 关于easyx库中怎样贴出透明图片 地图的链表实现 移动检测 碰撞检测 总结 前言: 花两天边看easyx文档边学边写的期末小作业. 学 ...

  6. Linux上运行扫雷,基于linux环境下扫雷应用程序.docx

    总俶斜技誓魄 <网络操作糸统>掖告 (应用程序开发丿 题 目: 基于I inux平台GCC环境下扫雷应用程 序开发 姓 名: 李磊 学 院: 理学院 专 业: 网络工程 班 级: 092 ...

  7. 基于VB环境下的语音识别程序开发方法

    摘要:语音识别技术的发展和广泛应用,使用户与计算机的对话方式不再仅仅局限在使用键盘或鼠标发送指令的方式.本文在visual basic 编程环境下使用Microsoft Speech SDK中的语音接 ...

  8. 【C语言游戏】太空大战 | SpaceWar(基于EasyX图形库,FPS优化,碰撞判断,drawAlpha绘制透明贴图,音乐播放,源码素材免费分享)

    1. 数据结构介绍 //飞船的数据结构(包括己方战机和敌机) struct aircraft { int x;//横坐标 int y;//纵坐标 int HP;//飞船血量 int spead;//飞 ...

  9. 基于EasyX图形库的C/C++实战项目——西南大学大一C语言程序设计|课程设计《多功能应用平台》

    目录 一.扫雷 二.迷宫 三.通讯录 四.核心代码 一.扫雷 功能简介:1.   棋盘设置 2.    设置模式 3.   红旗标志 4.  递归展开(DFS) 扫雷 二.迷宫 功能介绍: 1.   ...

最新文章

  1. mysql图形化及命令行操作用户权限
  2. 为什么选择格鲁圣教之Go程序版
  3. docker java 最小镜像_docker构建JDK最小镜像
  4. mysql数据库崩_mysql数据库崩溃_MySQL
  5. Android获取Linux图像信息,Android系统信息获取 之十三:Linux内核版本信息获取
  6. python操作数据库
  7. 国外数学奇才称:“平行线可相交”,到死未被认可,12年后被证实
  8. tensorflows十五 再探Momentum和Nesterov's accelerated gradient descent 利用自动控制PID概念引入误差微分控制超参数改进NAGD,速度快波动小
  9. Linux静态库与动态库
  10. 类中添加log4j日志
  11. 普元EOS在运算逻辑里面调用HttpServletRequest ,HttpServletResponse
  12. Spring java excel_SpringBoot之导入导出Excel(Java8实现)
  13. 语句摘抄——第26周
  14. pc机之间的通信和点阵汉字的字模读取与显示
  15. jQuery实现购物车计算价格统计功能
  16. python爬取学校题库_Python爬虫实战-获取某网站题库
  17. mac下怎么将终端命令安装的软件加进系统环境变量中
  18. win7关机快捷键_总说win7最好用,不知这些强大的功能,怎知你的win10好不好用?...
  19. 鼠标事件 onmouseover、onmouseenter、onmouseleave和onmouseout
  20. 【JAVA】LeetCode力扣 第199场周赛 题解+代码

热门文章

  1. python保存、读取.mat文件
  2. 桌面图标出现蓝底怎么办
  3. 通过浏览器直接打开android应用程序,直接通过浏览器打开Android App 应用
  4. 8. vma操作概述
  5. 如何制作ROM刷机包
  6. JDK安装和Java开发环境变量配置(详细)
  7. 用Python一晚上爬取P站几万张图片的详细教程
  8. Warning: The Copy Bundle Resources build phase contains this target's Info.plist file 'x/info.plist'
  9. opencv缩小图片的方法
  10. 闭包相关面试题(非原创,整合网上资源)