当前位置: 首页 > news >正文

集约化网站建设的函石家庄最新招聘信息

集约化网站建设的函,石家庄最新招聘信息,无锡市工程造价信息网,网站开发属于什么资产前言 大家好呀#xff0c;我是Humble#xff0c;不知不觉在CSND分享自己学过的C语言知识已经有三个多月了#xff0c;从开始的C语言常见语法概念说到C语言的数据结构今天用C语言实现贪吃蛇已经有30余篇博客的内容#xff0c;也希望这些内容可以帮助到各位正在阅读的小伙伴…前言 大家好呀我是Humble不知不觉在CSND分享自己学过的C语言知识已经有三个多月了从开始的C语言常见语法概念说到C语言的数据结构今天用C语言实现贪吃蛇已经有30余篇博客的内容也希望这些内容可以帮助到各位正在阅读的小伙伴~ 本次贪吃蛇项目是Humble继扫雷通讯录之后分享的第三个项目大约有五六百行代码的量~ 而且不出意外这应该是HumbleC语言部分的最后一篇博客了在这之后Humble未来的规划是分享C的相关语法内容C实现的数据结构与算法计算机网络操作系统以及数据库的相关知识希望未来也请各位多多关照~ 好了因为是一篇具有特殊意义的博客好像前言说的有些多了笑接下来废话不多说直接进入我们今天的贪吃蛇项目的内容把~ 游戏演示 关于贪吃蛇这个游戏我相信各位并不陌生小伙伴们也跟我一样在童年的时候都玩过吧~ 那么在正式制作之前先给大家看一下这个即将由我们自己制作的贪吃蛇游戏的演示 让各位先对它有个整体的了解之后之后的制作才会更加容易~ 当我们运行起来后首先看到的是两个初始化界面 然后下面是正式开始游戏的画面 围起来的部分是地图蛇的初始长度被设置为5个节点通过按键操作吃掉食物会获得相应得分同时蛇的节点会增加其余规则可看界面右方给的文字说明 当我们撞到墙或者自身或者按ESC键自己退出时会显示游戏结束的界面 以上就是对这个贪吃蛇小游戏简单的一次总揽更多细节上的东西我们放在下面再讲 目标 本篇博客的目标 使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇 实现基本的功能 1.初始化以及地图的创建 2.蛇与食物的初始化 3.蛇吃食物 4.撞墙检测 5.装自身检测 6.蛇的移动加速减速 7.暂停功能 8.计算得分 .... 技术要点 本次贪吃蛇项目涉及的技术要点主要有一下七点 C语言函数、枚举、结构体、动态内存管理、链表、Win32 API等   前面5点都是Humble在之前的博客都有分享过的各位小伙伴可以访问我的主页去阅读哦 今天在讲贪吃蛇这个项目之前我先对Win32 API  做个介绍 对其进行了解才能更丝滑的写接下来的贪吃蛇项目哦~ Win32 API 一.Win32 API概述 Windows这个多作业系统除了协调程序的执行、分配内存、管理资源之外它同时也是一个很大的服务中心调用这个服务中心的各种服务每一种服务就是一个函数可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的由于这些函数服务的对象是应用程序(Application)所以便称之为Application Programming Interface简称API函数 WIN32API也就是Microsoft Windows32位平台的应用程序编程接口   当然这里大家不要太在乎这个32位平台我们就把它统称为WIN32 API 二.控制台程序Console 控制台程序其实就是平常我们程序运行起来出现的界面 我们可以设置控制台窗口的长宽设置控制台窗口的大小30行100列 mode con cols100 lines30 也可以通过命令设置控制台窗口的名字 title 贪吃蛇 这些命令我们可以调用C语言函数system来执行。 代码如下 #include windows.h int main() { system(mode con cols100 lines30); system(title 贪吃蛇); return 0; } 三.控制台屏幕上的坐标COORD COORD 是Windows API中定义的一个结构体具体内容我们可以不必深究主要是为下面的几个函数服务的咱们会用就行~表示一个字符在控制台屏幕上的坐标   给坐标赋值COORD pos { 10, 15 }; 四.GetStdHandle GetStdHandle是一个Windows API函数。它用于从一个特定的标准设备标准输入、标准输出或标准错误中取得一个句柄类似权限使用这个句柄可以操作设备   它的定义如下 HANDLE GetStdHandle(DWORD nStdHandle);//返回类型是HANDLE //括号里只能是标准输入、标准输出或标准错误这些都有对应的单词比如标准输出写为STD_OUTPUT_HANDLE 我们直接看一下它怎么用吧~举个例子   HANDLE hOutput NULL;//我们用一个HANDLE的变量接收函数返回值 hOutput GetStdHandle(STD_OUTPUT_HANDLE);//括号里是标准输出 好掌握了GetStdHandle之后接下来就很简单了我们看一下下面的几个函数把使用它们可以帮我们实现对光标和虚拟键的操作 五.GetConsoleCursorInfo GetConsoleCursorInfo它是用来检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息 实例 HANDLE hOutput NULL; hOutput GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄CONSOLE_CURSOR_INFO CursorInfo;//以CONSOLE_CURSOR_INFO类型定义一个变量~ GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息 这里出现了一个CONSOLE_CURSOR_INFO是我们前面没出现的也给大家简单介绍一下~ CONSOLE_CURSOR_INFO它是结构体包含有关控制台光标的信息 它的结构如下 typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } CONSOLE_CURSOR_INFO; dwSize由光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会变化范围从完全填充单元格到单元底部的水平线条这个我们今天用不到bVisible游标的可见性。如果光标可见则此成员为true我们接下来要实现的贪吃蛇要隐藏光标所以要将bVisible设置成false所以要这样写 CONSOLE_CURSOR_INFO CursorInfo; CursorInfo.bVisible false; //隐藏控制台光标 因为上面的对光标的操作只有使用SetConsoleCursorInfo后才能真正被修改所以下面来看一下SetConsoleCursorInfo 六.SetConsoleCursorInfo SetConsoleCursorInfo的作用是设置指定控制台屏幕缓冲区的光标的大小和可见性 它有两个参数这里也不过多赘述直接看代码 HANDLE hOutput NULL; hOutput GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态 经过SetConsoleCursorInfo 函数后上面对光标的隐藏操作也就在控制台上得以实现啦~ 七.SetConsoleCursorPosition SetConsoleCursorPosition调用这个函数将光标位置设置到指定的位置   代码如下   COORD pos { 10, 5};//我们将想要设置的坐标信息放在COORD类型的pos中HANDLE hOutput NULL; hOutput GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput, pos);//设置标准输出上光标的位置为pos当然为了之后写贪吃蛇代码时使用的更加方便我们可以将这段代码封装成一个函数SetPos 这样我们之后想改变光标到我们想要的位置就会更加得心应手了~ void SetPos(int x, int y) {COORD pos { x, y};HANDLE hOutput NULL; hOutput GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput, pos);} 最后我们再看一个函数GetAsyncKeyState它是用来实现游戏的交互即获取按键情况的~ 八.GetAsyncKeyState 当我们电脑上的按键被出发时键盘上每个键的虚拟键值会传递给函数函数通过返回值来分辨按键的状态 在上一次调用 GetAsyncKeyState 函数后如果返回的16位的short数据中最高位是1说明按键的状态是按下。如果最高是0说明按键的状态是抬起如果最低位被置为1则说明该按键被按过没按过的话则为0 如果我们要判断⼀个键是否被按过可以检测GetAsyncKeyState返回值的最低值是否为1 我们可以用#define定义   #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 ) 当然关于VK虚拟键的值在Win API 的官网都有说明我们可以去翻阅来获得自己想找的值~ 说完了Win API及接下来会用到的这些函数的知识下面我们进入贪吃蛇游戏的设计与分析吧~ 贪吃蛇游戏设计与分析 一.地图 前面在演示的时候我们看过游戏的地图长这个样子~ 无论是打印墙体使用的字符□还是打印蛇使用的字符●或者打印食物使用的字符★ 它们都是名为宽字符的存在 那么什么是宽字符它与普通字符有什么区别 其实从大小上看。普通的字符是占一个字节的这类宽字符是占用2个字节的   这点很重要因为我们的地图是建立在坐标上的宽字符的x轴占了2格而y轴只占1格我们要考虑好这点再去设计比如 地图的大小以及蛇与食物随机生成的坐标的规定等等 知道了这个我们看一看宽字符是怎么打印的吧~ 宽字符的打印 #include stdio.h #includelocale.hint main() { setlocale(LC_ALL, ); //这个setlocale函数以及它包含的头文件locale.h是为了将模式切换成本地环境大家直接用就可以不用深究~wchar_t ch1 L●; wchar_t ch2 L原; wchar_t ch3 L神; wchar_t ch4 L★;printf(%c%c\n, a, b); wprintf(L%c\n, ch1);//wprintf是用来打印宽字符的w即wide宽的意思 wprintf(L%c\n, ch2);//宽字符的打印要在%前加上L别忘了哦~ wprintf(L%c\n, ch3); wprintf(L%c\n, ch4); return 0; } 打印结果如下 我们发现一个普通字符占一个字符的位置.但是打印一个宽字符占用2个字符的位置 地图坐标 我们假设实现一个棋盘27行58列的棋盘再围绕地图画出墙 如下图 二.蛇身和食物 初始化状态假设蛇的长度是5蛇身的每个节点是 ●     在固定的一个坐标处开始出现注意蛇的每个节点的x坐标必须是2个倍数否则可能会出现蛇的⼀个节点有⼀半出现在墙体中另外⼀般在墙外的现象坐标不好对⻬。关于食物就是在墙体内随机生成一个坐标x坐标必须是2的倍数坐标不能和蛇的身体重合然后打印 ★   三.数据结构设计 在游戏运行的过程中蛇每次吃一个食物蛇的身体就会变长一节如果我们使用链表存储蛇的信 息那么蛇的每一节其实就是链表的每个节点。 每个节点只要记录好蛇身节点在地图上的坐标就行 所以蛇节点结构如下 typedef struct SnakeNode { int x; int y; struct SnakeNode* next; }SnakeNode, * pSnakeNode; 要管理整条贪吃蛇我们再封装⼀个Snake的结构来维护整条贪吃蛇 typedef struct Snake { pSnakeNode _pSnake;//维护整条蛇的指针 pSnakeNode _pFood;//维护食物的指针 enum DIRECTION _Dir;//蛇头的方向 enum GAME_STATUS _Status;//游戏状态 int _Socre;//当前获得分数 int _foodWeight;//默认每食物10分 int _SleepTime;//每⾛一步休眠时间 }Snake, * pSnake; 蛇的方向可以一一列举使用枚举 //方向 enum DIRECTION {UP 1,DOWN,LEFT,RIGHT };游戏状态可以一一列举使用枚举 //游戏状态 enum GAME_STATUS {OK,//正常运行KILL_BY_WALL,//撞墙KILL_BY_SELF,//咬到自己END_NOMAL//正常结束 };四.游戏流程设计 关于游戏流程设计Humble做了一张思维导图供大家参考~ 核心逻辑实现分析 我们打开VS创建一个Snake的贪吃蛇工程 在其中创建3个文件test.c测试文件snake.c源文件snake.h头文件 在test.c中我们写游戏的主逻辑 #define _CRT_SECURE_NO_WARNINGS #include snake.hvoid test() {int ch 0;srand((unsigned int)time(NULL));do{//设置控制台的信息窗口大小窗口名system(mode con cols100 lines30);system(title 贪吃蛇);//隐藏光标HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);CursorInfo.bVisible false;SetConsoleCursorInfo(handle, CursorInfo);Snake snake { 0 };//创建贪吃蛇GameStart(snake);GameRun(snake);GameEnd(snake);SetPos(20, 15);//设置光标的位置printf(再来一局吗(Y/N):);ch getchar();getchar();//清理\n} while (ch Y);SetPos(0, 27); }int main() {//修改适配本地中文环境setlocale(LC_ALL, );test();//贪吃蛇游戏的测试return 0; } GameStart 我们先看游戏开始GameStart这个函数它包含五个函数 void GameStart(pSnake ps) {WelcomeToGame();//打印欢迎信息CreateMap(); //绘制地图InitSnake(ps); //初始化蛇CreateFood(ps);//创建食物PrintHelpInfo();//打印右侧帮助信息 } 先看第一个打印欢迎信息WelcomeToGame void WelcomeToGame() {//欢迎信息SetPos(35, 10);printf(欢迎来到贪吃蛇小游戏\n);SetPos(38, 20);system(pause);system(cls);//清空之前的界面//功能介绍信息SetPos(15, 10);printf(用 ↑ . ↓ . ← . → 来控制蛇的移动F3是加速F4是减速);SetPos(15, 11);printf(加速能得到更高的分数);SetPos(38, 20);system(pause);system(cls); } 接下来是创建地图 CreateMap #define WALL L□ //宽字符的定义前面要加上L void CreateMap() {int i 0;//上SetPos(0, 0);for (i 0; i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0, 25);for (i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (i 1; i 25; i){SetPos(0, i);wprintf(L%lc, WALL);}//右for (i 1; i 25; i){SetPos(56, i);wprintf(L%lc, WALL);}} 下面是初始化蛇InitSnake 蛇最开始为5节每节对应链表的一个节点蛇的每一个节点都自己的坐标 创建5个节点然后将每个节点存放在链表中进行管理创建完蛇身后将蛇的每一节打印在屏幕上 再设置当前游戏的状态蛇移动的速度默认的方向向右初始成绩蛇的状态每个食物的分数   #define BODY L● void InitSnake(pSnake ps) {pSnakeNode cur NULL;int i 0;//创建蛇身节点并初始化坐标//头插法for (i 0; i 5; i){//创建蛇身的节点cur (pSnakeNode)malloc(sizeof(SnakeNode));if (cur NULL){perror(InitSnake()::malloc());return;}//设置坐标cur-next NULL;cur-x POS_X i * 2;cur-y POS_Y;//头插法if (ps-_pSnake NULL){ps-_pSnake cur;}else{cur-next ps-_pSnake;ps-_pSnake cur;}}//打印蛇的身体cur ps-_pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}//初始化贪吃蛇数据ps-_SleepTime 200;ps-_Socre 0;ps-_Status OK; ps-_Dir RIGHT;ps-_foodWeight 10; }GameStart包含的第四个子函数是CreateFood 随机生成食物的坐标 下面有一些限制 x坐标必须是2的倍数食物的坐标不能和蛇身每个节点的坐标重复 #define FOOD L★ //食物打印的宽字符 void CreateFood(pSnake ps) {int x 0;int y 0; again://产生的x坐标应该是2的倍数这样才可能和蛇头坐标对齐do{x rand() % 53 2;y rand() % 25 1;} while (x % 2 ! 0);pSnakeNode cur ps-_pSnake;//获取指向蛇头的指针//食物不能和蛇身冲突while (cur){if (cur-x x cur-y y){goto again;}cur cur-next;}pSnakeNode pFood (pSnakeNode)malloc(sizeof(SnakeNode)); //创建食物if (pFood NULL){perror(CreateFood::malloc());return;}else{pFood-x x;pFood-y y;SetPos(pFood-x, pFood-y);wprintf(L%c, FOOD);ps-_pFood pFood;} } GameStart的最后一个函数是PrintHelpInfo负责打印文字信息 void PrintHelpInfo() {SetPos(64, 15);printf(不能穿墙不能咬到自己\n);SetPos(64, 16);printf(用↑.↓.←.→分别控制蛇的移动.);SetPos(64, 17);printf(F3 为加速F4 为减速\n);SetPos(64, 18);printf(ESC 退出游戏. 空格键暂停游戏.);SetPos(64, 20); } GameRun 下面来看一下游戏运行的函数GameRun吧~ void pause()//暂停 {while (1){Sleep(300);if (KEY_PRESS(VK_SPACE))//空格键break;} }void GameRun(pSnake ps) {do{SetPos(64, 10); //每次进来都要对食物分数进行修正printf(得分%d , ps-_Socre);printf(每个食物得分%d分, ps-_foodWeight);if (KEY_PRESS(VK_UP) ps-_Dir ! DOWN){ps-_Dir UP;}else if (KEY_PRESS(VK_DOWN) ps-_Dir ! UP){ps-_Dir DOWN;}else if (KEY_PRESS(VK_LEFT) ps-_Dir ! RIGHT){ps-_Dir LEFT;}else if (KEY_PRESS(VK_RIGHT) ps-_Dir ! LEFT){ps-_Dir RIGHT;}else if (KEY_PRESS(VK_SPACE)){pause();}else if (KEY_PRESS(VK_ESCAPE)){ps-_Status END_NOMAL;break;}else if (KEY_PRESS(VK_F3)){if (ps-_SleepTime 50){ps-_SleepTime - 30;ps-_foodWeight 2;}}else if (KEY_PRESS(VK_F4)){if (ps-_SleepTime 350){ps-_SleepTime 30;ps-_foodWeight - 2;if (ps-_SleepTime 350){ps-_foodWeight 1;}}}//蛇每次一定之间要休眠的时间时间短蛇移动速度就快Sleep(ps-_SleepTime);SnakeMove(ps);} while (ps-_Status OK);虽然这个是三个函数最复杂的部分但我们也是一个一个点按照设计的流程来~ 关于虚拟键检测按键状态我们封装一个宏~ #define KEY_PRESS(VK) ((GetAsyncKeyState(VK)0x1) ? 1 : 0) 下面是蛇身的移动这个很关键~ 先创建下一个节点根据移动方向和蛇头的坐标蛇移动到下⼀个位置的坐标 确定了下⼀个位置后判断下一个位置是否是食物NextIsFood 是食物就做EatFood如果不是食物NoFood 蛇身移动后判断此次移动是否会造成撞墙KillByWall或者撞上自己KillBySelf   void SnakeMove(pSnake ps) {//创建下一个节点pSnakeNode pNextNode (pSnakeNode)malloc(sizeof(SnakeNode));//确定下一个节点的坐标下一个节点的坐标根据蛇头的坐标和方向确定switch (ps-_Dir){case UP:{pNextNode-x ps-_pSnake-x;pNextNode-y ps-_pSnake-y - 1;}break;case DOWN:{pNextNode-x ps-_pSnake-x;pNextNode-y ps-_pSnake-y 1;}break;case LEFT:{pNextNode-x ps-_pSnake-x - 2;pNextNode-y ps-_pSnake-y;}break;case RIGHT:{pNextNode-x ps-_pSnake-x 2;pNextNode-y ps-_pSnake-y;}break;}if (NextIsFood(pNextNode, ps)){EatFood(pNextNode, ps);}else//如果没有食物{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps); }int NextIsFood(pSnakeNode psn, pSnake ps) {return (psn-x ps-_pFood-x) (psn-y ps-_pFood-y); } void EatFood(pSnakeNode psn, pSnake ps) {//头插法psn-next ps-_pSnake;ps-_pSnake psn;pSnakeNode cur ps-_pSnake;//打印蛇while (cur){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}ps-_Socre ps-_foodWeight;free(ps-_pFood);CreateFood(ps); } //将下⼀个节点头插⼊蛇的⾝体并将之前蛇⾝最后⼀个节点打印为空格弃掉蛇身的最后⼀个节点 //pSnakeNode psn 是下⼀个节点的地址 //pSnake ps 维护蛇的指针 void NoFood(pSnakeNode psn, pSnake ps) {//头插法psn-next ps-_pSnake;ps-_pSnake psn;pSnakeNode cur ps-_pSnake;//打印蛇while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}//最后一个位置打印空格然后释放节点SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL; }int KillByWall(pSnake ps) //判断蛇头的坐标是否和墙的坐标冲突 {if ((ps-_pSnake-x 0)|| (ps-_pSnake-x 56)|| (ps-_pSnake-y 0)|| (ps-_pSnake-y 26)){ps-_Status KILL_BY_WALL;return 1;}return 0; }int KillBySelf(pSnake ps) //判断蛇头的坐标是否和蛇⾝体的坐标冲突 {pSnakeNode cur ps-_pSnake-next;while (cur){if ((ps-_pSnake-x cur-x) (ps-_pSnake-y cur-y)){ps-_Status KILL_BY_SELF;return 1;}cur cur-next;}return 0; }呼终于将最核心的逻辑搞定了~最后来看看游戏结束的函数GameEnd吧~ GameEnd 游戏状态不再是OK的时候要告知游戏结束的原因并且释放蛇身节点   void GameEnd(pSnake ps) {pSnakeNode cur ps-_pSnake;SetPos(24, 12);switch (ps-_Status){case END_NOMAL:printf(您主动退出游戏\n);break;case KILL_BY_SELF:printf(您撞上自己了 ,游戏结束!\n);break;case KILL_BY_WALL:printf(您撞墙了,游戏结束!\n);break;}//释放蛇身的节点while (cur){pSnakeNode del cur;cur cur-next;free(del);} } 到这我们整个贪吃蛇游戏的功能就全部实现了鼓掌鼓掌 最后是Humble的参考代码分3个文件 参考代码 test.c #define _CRT_SECURE_NO_WARNINGS #include snake.hvoid test() {int ch 0;srand((unsigned int)time(NULL));do{Snake snake { 0 };//创建贪吃蛇//设置控制台的信息窗口大小窗口名system(mode con cols100 lines30);system(title 贪吃蛇);//隐藏光标HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);CursorInfo.bVisible false;SetConsoleCursorInfo(handle, CursorInfo);GameStart(snake);GameRun(snake);GameEnd(snake);SetPos(20, 15);//设置光标的位置printf(再来一局吗(Y/N):);ch getchar();getchar();//清理\n} while (ch Y);SetPos(0, 27); }int main() {//修改适配本地中文环境setlocale(LC_ALL, );test();//贪吃蛇游戏的测试return 0; } snake.h #pragma once #include stdio.h #include stdlib.h #include windows.h #include stdbool.h #include locale.h #include time.h//宽字符的定义 #define WALL L□ #define BODY L● #define FOOD L★//蛇的初始位置 #define POS_X 24 #define POS_Y 5//虚拟键 #define KEY_PRESS(VK) ((GetAsyncKeyState(VK)0x1) ? 1 : 0)//方向 enum DIRECTION {UP 1,DOWN,LEFT,RIGHT };//游戏状态 enum GAME_STATUS {OK,//正常运行KILL_BY_WALL,//撞墙结束KILL_BY_SELF,//咬到自己结束END_NOMAL//按键结束 };//蛇身节点 typedef struct SnakeNode {int x;int y;struct SnakeNode* next; }SnakeNode, * pSnakeNode;typedef struct Snake {pSnakeNode _pSnake;//维护整条蛇的指针pSnakeNode _pFood;//维护食物的指针enum DIRECTION _Dir;//蛇头的方向enum GAME_STATUS _Status;//游戏状态int _Socre;//当前获得分数int _foodWeight;//默认每个食物10分int _SleepTime;//每走一步休眠时间 }Snake, * pSnake;//设置光标的坐标 void SetPos(int x, int y);//欢迎界面 void WelcomeToGame();//创建地图 void CreateMap();//初始化蛇 void InitSnake(pSnake ps);//创建食物 void CreateFood(pSnake ps);//打印右侧界面的文字说明 void PrintHelpInfo();//暂停响应 void pause();//下一个节点是食物 int NextIsFood(pSnakeNode psn, pSnake ps);//吃食物 void EatFood(pSnakeNode psn, pSnake ps);//不吃食物 void NoFood(pSnakeNode psn, pSnake ps);//撞墙检测 int KillByWall(pSnake ps);//撞自身检测 int KillBySelf(pSnake ps);//蛇的移动 void SnakeMove(pSnake ps);//游戏开始 void GameStart(pSnake ps);//游戏运行 void GameRun(pSnake ps);//游戏结束 void GameEnd(pSnake ps);snake.c #define _CRT_SECURE_NO_WARNINGS #include snake.h//设置光标的位置的函数 void SetPos(int x, int y) {HANDLE hanlde GetStdHandle(STD_OUTPUT_HANDLE); //获得设备句柄COORD pos { x, y }; //根据句柄设置光标的位置SetConsoleCursorPosition(hanlde, pos); }void WelcomeToGame() {//欢迎信息SetPos(35, 10);printf(欢迎来到贪吃蛇小游戏\n);SetPos(38, 20);system(pause);system(cls);//清空之前的界面//功能介绍信息SetPos(15, 10);printf(用 ↑ . ↓ . ← . → 来控制蛇的移动F3是加速F4是减速);SetPos(15, 11);printf(加速能得到更高的分数);SetPos(38, 20);system(pause);system(cls); }void CreateMap() {int i 0;//上SetPos(0, 0);for (i 0; i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0, 25);for (i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (i 1; i 25; i){SetPos(0, i);wprintf(L%lc, WALL);}//右for (i 1; i 25; i){SetPos(56, i);wprintf(L%lc, WALL);}}void InitSnake(pSnake ps) {pSnakeNode cur NULL;int i 0;//创建蛇身节点并初始化坐标//头插法for (i 0; i 5; i){//创建蛇身的节点cur (pSnakeNode)malloc(sizeof(SnakeNode));if (cur NULL){perror(InitSnake()::malloc());return;}//设置坐标cur-next NULL;cur-x POS_X i * 2;cur-y POS_Y;//头插法if (ps-_pSnake NULL){ps-_pSnake cur;}else{cur-next ps-_pSnake;ps-_pSnake cur;}}//打印蛇的身体cur ps-_pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}//初始化贪吃蛇数据ps-_SleepTime 200;ps-_Socre 0;ps-_Status OK; ps-_Dir RIGHT;ps-_foodWeight 10; }void CreateFood(pSnake ps) {int x 0;int y 0; again://产生的x坐标应该是2的倍数这样才可能和蛇头坐标对齐do{x rand() % 53 2;y rand() % 25 1;} while (x % 2 ! 0);pSnakeNode cur ps-_pSnake;//获取指向蛇头的指针//食物不能和蛇身冲突while (cur){if (cur-x x cur-y y){goto again;}cur cur-next;}pSnakeNode pFood (pSnakeNode)malloc(sizeof(SnakeNode)); //创建食物if (pFood NULL){perror(CreateFood::malloc());return;}else{pFood-x x;pFood-y y;SetPos(pFood-x, pFood-y);wprintf(L%c, FOOD);ps-_pFood pFood;} }void PrintHelpInfo() {SetPos(64, 15);printf(不能穿墙不能咬到自己\n);SetPos(64, 16);printf(用↑.↓.←.→分别控制蛇的移动.);SetPos(64, 17);printf(F3 为加速F4 为减速\n);SetPos(64, 18);printf(ESC 退出游戏. 空格键暂停游戏.);SetPos(64, 20); }void pause()//暂停 {while (1){Sleep(300);if (KEY_PRESS(VK_SPACE))//空格键break;} }int NextIsFood(pSnakeNode psn, pSnake ps) {return (psn-x ps-_pFood-x) (psn-y ps-_pFood-y); }void EatFood(pSnakeNode psn, pSnake ps) {//头插法psn-next ps-_pSnake;ps-_pSnake psn;pSnakeNode cur ps-_pSnake;//打印蛇while (cur){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}ps-_Socre ps-_foodWeight;free(ps-_pFood);CreateFood(ps); }void NoFood(pSnakeNode psn, pSnake ps) {//头插法psn-next ps-_pSnake;ps-_pSnake psn;pSnakeNode cur ps-_pSnake;//打印蛇while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%c, BODY);cur cur-next;}//最后一个位置打印空格然后释放节点SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL; }int KillByWall(pSnake ps) {if ((ps-_pSnake-x 0)|| (ps-_pSnake-x 56)|| (ps-_pSnake-y 0)|| (ps-_pSnake-y 26)){ps-_Status KILL_BY_WALL;return 1;}return 0; }int KillBySelf(pSnake ps) {pSnakeNode cur ps-_pSnake-next;while (cur){if ((ps-_pSnake-x cur-x) (ps-_pSnake-y cur-y)){ps-_Status KILL_BY_SELF;return 1;}cur cur-next;}return 0; }void SnakeMove(pSnake ps) {//创建下一个节点pSnakeNode pNextNode (pSnakeNode)malloc(sizeof(SnakeNode));//确定下一个节点的坐标下一个节点的坐标根据蛇头的坐标和方向确定switch (ps-_Dir){case UP:{pNextNode-x ps-_pSnake-x;pNextNode-y ps-_pSnake-y - 1;}break;case DOWN:{pNextNode-x ps-_pSnake-x;pNextNode-y ps-_pSnake-y 1;}break;case LEFT:{pNextNode-x ps-_pSnake-x - 2;pNextNode-y ps-_pSnake-y;}break;case RIGHT:{pNextNode-x ps-_pSnake-x 2;pNextNode-y ps-_pSnake-y;}break;}if (NextIsFood(pNextNode, ps)){EatFood(pNextNode, ps);}else//如果没有食物{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps); }void GameStart(pSnake ps) {WelcomeToGame();//打印欢迎信息CreateMap(); //绘制地图InitSnake(ps); //初始化蛇CreateFood(ps);//创建食物PrintHelpInfo();//打印右侧帮助信息 }void GameRun(pSnake ps) {do{SetPos(64, 10);printf(得分%d , ps-_Socre);printf(每个食物得分%d分, ps-_foodWeight);if (KEY_PRESS(VK_UP) ps-_Dir ! DOWN){ps-_Dir UP;}else if (KEY_PRESS(VK_DOWN) ps-_Dir ! UP){ps-_Dir DOWN;}else if (KEY_PRESS(VK_LEFT) ps-_Dir ! RIGHT){ps-_Dir LEFT;}else if (KEY_PRESS(VK_RIGHT) ps-_Dir ! LEFT){ps-_Dir RIGHT;}else if (KEY_PRESS(VK_SPACE)){pause();}else if (KEY_PRESS(VK_ESCAPE)){ps-_Status END_NOMAL;break;}else if (KEY_PRESS(VK_F3)){if (ps-_SleepTime 50){ps-_SleepTime - 30;ps-_foodWeight 2;}}else if (KEY_PRESS(VK_F4)){if (ps-_SleepTime 350){ps-_SleepTime 30;ps-_foodWeight - 2;if (ps-_SleepTime 350){ps-_foodWeight 1;}}}//蛇每次一定之间要休眠的时间时间短蛇移动速度就快Sleep(ps-_SleepTime);SnakeMove(ps);} while (ps-_Status OK);//游戏状态是OK则继续游戏}void GameEnd(pSnake ps) {pSnakeNode cur ps-_pSnake;SetPos(24, 12);switch (ps-_Status){case END_NOMAL:printf(您主动退出游戏\n);break;case KILL_BY_SELF:printf(您撞上自己了 ,游戏结束!\n);break;case KILL_BY_WALL:printf(您撞墙了,游戏结束!\n);break;}//释放蛇身的节点while (cur){pSnakeNode del cur;cur cur-next;free(del);} } 结语 好了今天的这个贪吃蛇游戏的实现分享就到这里了 作为C语言部分的最后一篇博客大概虽然心情复杂但不知道该说些什么 总之还是那句话在学习编程的道路上Humble与各位同行,加油吧各位 希望大家动动小手帮我点个免费的赞或者关注感谢感谢也欢迎大家订阅我的专栏呀~ 让我们在接下来的时间里一起成长一起进步吧
http://www.w-s-a.com/news/887779/

相关文章:

  • 桂林学校网站制作2018年网站设计公司
  • 建网站不想用怎样撤销搜狗收录提交入口网址
  • 做简单网站需要学什么软件有哪些南通优普网站建设
  • 网站排版尺寸湖北交投建设集团集团网站
  • 南京网站设计公司有哪些公司看动漫是怎么做视频网站
  • vs做网站怎么做窗体怎么在电脑上自己做网站吗
  • 做网站应该学什么网站编程 外包类型
  • 双鱼儿 网站建设站群系统哪个好用
  • 怎样自己做刷赞网站电商设计需要学什么软件有哪些
  • 关注城市建设网站居众装饰
  • 网站建设的语言优化企业网站
  • 成都旅游网站建设规划女性门户资讯类网站织梦dedecms模板
  • 二手车为什么做网站网站建设合作合同范文
  • 网站建设维护和网页设计做网站都需要服务器吗
  • 成都网站设计报告书系统平台
  • 怎样进行网站推广wordpress微博图床
  • 做一个平台 网站服务器搭建网架公司股价
  • 链家在线网站是哪个公司做的一个虚拟主机做2个网站
  • 网站开发实训报告模板学校网站建设计划
  • 免费手机网站制作方法什么事网站开发
  • 我们的爱情网站制作阿里云wordpress配置
  • 电脑网站页面怎么调大小唐山网站建设技术外包
  • 科威网络做网站怎么样wordpress分页样式
  • 泰安公司网站建设自助建站程序
  • 网站建设工程设计图建网站怎样往网站传视频
  • 做网站月入企业网站建设运营
  • 网站建设中的ftp地址公众号微官网
  • 手机wap网站开发与设计app开发公司电话
  • 网站页脚代码大沥网站开发
  • 重庆网站制作公司 广州天成网络技术有限公司