建湖网站建设价格精品网站建设教程

bicheng/2026/1/16 17:16:10/文章来源:
建湖网站建设价格,精品网站建设教程,郑州英语网站建设,内容营销公司我们这篇会使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇 实现基本的功能#xff1a; 结果如下: 1.一些Win32 API知识 本次实现呢我们会用到一些Win32 API的知识(WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口): 1)控制窗口大小 我们可以使用…我们这篇会使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇 实现基本的功能 结果如下: 1.一些Win32 API知识 本次实现呢我们会用到一些Win32 API的知识(WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口): 1)控制窗口大小 我们可以使用cmd命令来设置控制台窗口的长宽设置控制台窗口的大小,设置控制台窗口的名字: mode con cols100 lines30//设置窗口大小为100列,30行 title 贪吃蛇//设置窗口名称为贪吃蛇我们在C语言中可以用函数system来执行,入上面这两个,我们可以这么写: system(mode con cols100 lines30); system(title 贪吃蛇); 2)控制台屏幕上的坐标 Windows API中存在这么一个结构体,叫做COORD,表示⼀个字符在控制台屏幕上的坐标 typedef struct _COORD {SHORT X;SHORT Y; } COORD, *PCOORD; 给坐标赋值 COORD pos { 10, 15 }; 3)GetStdHandle GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备标准输入、标准输出或标准错误中取得⼀个句柄用来标识不同设备的数值),使用这个句柄可以操作设备。 HANDLE GetStdHandle(DWORD nStdHandle); 4)GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息 BOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ); 实例 HANDLE hOutput NULL; //获取标准输出的句柄(⽤来标识不同设备的数值) hOutput GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息 5)CONSOLE_CURSOR_INFO 这个结构体包含有关控制台光标的信息 typedef struct _CONSOLE_CURSOR_INFO {DWORD dwSize;BOOL bVisible; } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; dwSize由光标填充的字符单元格的百分比。 此值介于1到100之间。 光标外观会变化范围从完全填充单元格到单元底部的水平线条。 bVisible游标的可见性。 如果光标可见则此成员为 TRUE。 CursorInfo.bVisible false; //隐藏控制台光标   6)SetConsoleCursorInfo 设置指定控制台屏幕缓冲区的光标的大小和可见性。 BOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo ); 实例  HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE); //影藏光标操作 CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息 CursorInfo.bVisible false; //隐藏控制台光标 SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态 7)SetConsoleCursorPosition 设置指定控制台屏幕缓冲区中的光标位置我们将想要设置的坐标信息放在COORD类型的pos中调用SetConsoleCursorPosition函数将光标位置设置到指定的位置 BOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD pos ); 示例: COORD pos { 10, 5};HANDLE hOutput NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos); 用上面的这些函数我们就可以封装⼀个设置光标位置的函数 void SetPos(short x, short y) {COORD pos { x, y };HANDLE hOutput NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos); } 8)GetAsyncKeyState GetAsyncKeyState用来获取按键情况 SHORT GetAsyncKeyState(int vKey ); 将键盘上每个键的虚拟键值传递给函数函数通过返回值来分辨按键的状态。 GetAsyncKeyState 的返回值是short类型在上⼀次调用  GetAsyncKeyState 函数后如果 返回的16位的short数据中最高位是1说明按键的状态是按下如果最⾼是0说明按键的状态是抬起如果最低位被置为1则说明该按键被按过否则为0 如果我们要判断⼀个键是否被按过可以检测GetAsyncKeyState返回值的最低值是否为1 : 示例: #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 ) 2.游戏的逻辑 在做这个游戏前,我们应该先想好怎么做,游戏每个阶段该做什么. 这里我做了一个图: 3. 贪吃蛇的整体维护和地图绘制 整体维护我们创建一个结构体来维护整体运行 typedef struct Snake {pSnakeNode pSnake;//维护整条蛇的指针是指向蛇头pSnakeNode pFood;//指向食物的指针int Score;//当前累积的分数int FoodWeight;//一个食物的分数int SleepTime;//蛇休眠的时间休眠的时间越短蛇的速度越快休眠的时间越长蛇的速度越慢enum GAME_STATUS status;//游戏当前的状态enum DIRECTION dir;//蛇当前走的方向 }Snake, * pSnake;我们顺便将蛇,目标,墙用宽字符定义了 #define WALL L□ #define BODY L● #define FOOD L★窗口大小,名字,以及隐藏光标,我们都解决了,现在我们来解决打印贪吃蛇地图的问题 这里不得不讲⼀下控制台窗口的⼀些知识如果想在控制台的窗口中指定位置输出信息我们得知道该位置的坐标所以首先介绍⼀下控制台窗口的坐标知识.控制台窗口的坐标如下所示横向的是X轴从左向右依次增长纵向是Y轴从上到下依次增长。 在游戏地图上我们打印墙使用宽字符□打印蛇使用宽字符●打印食物使用宽字符★ 普通的字符是占一个字节的这类宽字符是占用2个字节。 过去C语言并不适合非英语国家地区使用。 C语言最初假定字符都是但自己的。但是这些假定并不是在世界的任何地方都适用。 C语言字符默认是采用ASCII编码的ASCII字符集采用的是单字节编码且只使用了单字节中的低7 位最高位是没有使用的可表示为0xxxxxxxx可以看到ASCII字符集共包含128个字符在英语国家中128个字符是基本够用的但是在其他国家语言中比如在法语中字母上方有注音符号它就无法用ASCII码表示。于是⼀些欧洲国家就决定利用字节中闲置的最高位编入新的符号。比如法语中的é的编码为130⼆进制10000010。这样⼀来这些欧洲国家使用的编码体系可以表示最多256个符号。但是这里又出现了新的问题。不同的国家有不同的字母因此哪怕它们都使用256个符号的编码方式代表的字母却不⼀样。比如130在法语编码中代表了é在希伯来语编码中却代表了字⺟Gimel在俄语编码中又会代表另⼀个符号。但是不管怎样所有这些编码方式中0--127表⽰的符号是⼀样的不⼀样的只是128--255的这⼀段。至于亚洲国家的文字使用的符号就更多了汉字就多达10万左右。⼀个字节只能表示256种符号肯定是不够的就必须使用多个字节表达⼀个符号。比如简体中文常见的编码方式是 GB2312使用两个字节表示⼀个汉字所以理论上最多可以表示 256 x 256 65536 个符号。 后来为了使C语言适应国际化C语⾔的标准中不断加入了国际化的支持。比如加入和宽字符的类型wchar_t 和宽字符的输入和输出函数加入locale.h头文件其中提供了允许程序员针对特定地区通常是国家或者说某种特定语言的地理区域调整程序行为的函数。 1)locale.h头文件 选自clocale locale.h - C参考 (cplusplus.com) 2)setlocale 函数 setlocale 函数用于修改当前地区可以针对⼀个类项修改也可以针对所有类项。 setlocale 的第一个参数可以是前⾯说明的类项中的⼀个那么每次只会影响⼀个类项如果第⼀个参数是LC_ALL就会影响所有的类项。 C标准给第二个参数仅定义了2种可能取值C和 。 在任意程序执行开始都会隐藏式执行调用: setlocale(LC_ALL, C); 当地区设置为C时库函数按正常方式执行小数点是⼀个点。 当程序运行起来后想改变地区就只能显示调用setlocale函数。用 作为第2个参数调用setlocale 函数就可以切换到本地模式这种模式下程序会适应本地环境。比如切换到我们的本地模式后就支持宽字符汉字的输出等。 setlocale(LC_ALL, );//切换到本地环境 在切换到我们的本地环境后就可以打印宽字符了 示例 #include stdio.h #includelocale.h int main() {setlocale(LC_ALL, );wchar_t ch1 L●;char ch2 ;wprintf(L%c, ch1);printf(%c\n, ch2);printf(%c, ch2);return 0; } 运行结果 经过对比我们发现⼀个普通字符占⼀个字符的位置 但是打印⼀个宽字符占用2个字符的位置那么我们如果要在贪吃蛇中使用宽字符就得处理好地图上坐标的计算。 3地图坐标 我们假设实现⼀个棋盘27行58列的棋盘行和列可以根据自己的情况修改再围绕地图画出墙 图在上面代码如下 #define WALL L□ void createmap() {//上SetPos(0, 0);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0, 26);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (int i 1; i 25; i){SetPos(0, i);wprintf(L%lc, WALL);}//右for (int i 1; i 25; i){SetPos(56, i);wprintf(L%lc, WALL);} } 4.有关蛇的定义 我们创建一个结构体来维护蛇身的节点 typedef struct SnakeNode {int x;int y;struct SnakeNode* next; }SnakeNode, * pSnakeNode;顺带我们枚举蛇的运动方向 enum DIRECTION {UP,DOWN,LEFT,RIGHT }; 5.GameStart() 接下来我们开始按照流程来,现在是游戏前的准备 1设置窗口大小、设置窗口名字、隐藏光标 void setwindows() {system(title 贪吃蛇);system(mode con cols100 lines30); } void hidcursor() {//获得设备句柄HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);//定义控制台相关光标的结构体CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false;//光标可见性关闭SetConsoleCursorInfo(handle, CursorInfo);//设置控制台光标状态 }void SetPos(int x, int y) {//获得设备句柄HANDLE hanlde GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos { x, y };//设置控制台光标状态SetConsoleCursorPosition(hanlde, pos); } 2欢迎词 前面我们运行的时候都会有欢迎来到XXX,所以我们也做一个 void welcome() {//欢迎信息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); } (35,10)是我设计的打印时的光标位置你也可以自行修改。cls是清屏 3地图的创建与贪吃蛇的初始化 地图创建前面我讲过了这里就展示一下代码 void createmap() {//上SetPos(0, 0);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0, 26);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (int i 1; i 25; i){SetPos(0, i);wprintf(L%lc, WALL);}//右for (int i 1; i 25; i){SetPos(56, i);wprintf(L%lc, WALL);} }贪吃蛇的初始化包括蛇的出实话以及各种信息的初始化。 我们使用单链表将蛇的身体一节一节连起来最后用头插把蛇头接上蛇身 代码示例 pSnakeNode cur NULL;int i 0;for (i 0; i 3; i){cur (pSnakeNode)malloc(sizeof(SnakeNode));if (cur NULL){perror(InitSnake():malloc());return;}cur-x POS_X 2 * i;cur-y POS_Y;cur-next NULL;//头插法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%lc, BODY);cur cur-next;} 这样我们的蛇就初始化完了接下来我们把其他信息也初始化 //贪吃蛇的其他信息初始化ps-dir RIGHT;ps-FoodWeight 10;ps-pFood NULL;ps-Score 0;ps-SleepTime 200;ps-status OK; 最后把这三段拼在一起就是贪吃蛇的初始化了 //初始化贪吃蛇 void InitSnake(pSnake ps) {pSnakeNode cur NULL;int i 0;for (i 0; i 3; i){cur (pSnakeNode)malloc(sizeof(SnakeNode));if (cur NULL){perror(InitSnake():malloc());return;}cur-x POS_X 2 * i;cur-y POS_Y;cur-next NULL;//头插法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%lc, BODY);cur cur-next;}//贪吃蛇的其他信息初始化ps-dir RIGHT;ps-FoodWeight 10;ps-pFood NULL;ps-Score 0;ps-SleepTime 200;ps-status OK; } 4食物的创建 既然我们完成了蛇的初始化在游戏没开始的时候食物不也是创建好了吗所以我们接下来写事物的创建但是我们食物的创建存在一定的条件对吧。 存在以下两个条件 1.食物不能与蛇重叠 2.食物不能生成在墙上 代码示例 //创建食物 void Createfood(pSnake ps) {int x 0;int y 0;again:do{x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);//坐标和蛇的身体的每个节点的做坐标比较pSnakeNode cur ps-pSnake;while (cur){if (x cur-x y cur-y){goto again;}cur cur-next;}//创建食物pSnakeNode pFood (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood NULL){perror(CreateFood()::malloc());return;}pFood-x x;pFood-y y;ps-pFood pFood;SetPos(x, y);wprintf(L%lc, FOOD); } 注意考虑空间开辟失败的情况。 4打印帮助信息 我们在运行游戏时右边有一个帮助信息这个也是提前打好的 代码示例 //打印帮助信息 void PrintHelpInfo() {SetPos(59, 15);printf(1.不要撞到墙);SetPos(59, 16);printf(2.不要撞到自己);SetPos(59, 17);printf(3.用 ↑ . ↓ . ← . → 来控制蛇的移动);SetPos(59, 18);printf(4.F3加速F4减速,加速能得到更高的分数);SetPos(59, 19);printf(5.ESC退出,space暂停);SetPos(59, 20);printf(Dream_Snowar所作); }5整合 最后我们将代码整合起来就是我们的要的函数 //游戏初始化 void GameStart(pSnake ps) {setwindows();welcome();hidcursor();createmap();InitSnake(ps);Createfood(ps);PrintHelpInfo(); }6.GameRun() 这里我们需要完成蛇的移动蛇吃食物各个按键的使用 首先我们写一下函数的结构以及判断各个按键 代码示例 void GameRun(pSnake ps) { do{//当前的分数SetPos(59, 10);printf(总分:%d\n, ps-Score);SetPos(59, 11);printf(分数倍率:%02d\n, ps-FoodWeight);//检测按键,↑ . ↓ . ← . → . ESC . F3 . F4 . spaceif (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_ESCAPE)){ps-status ESC;break;}else if (KEY_PRESS(VK_SPACE)){//游戏暂停pause();}else if (KEY_PRESS(VK_F3)){if (ps-SleepTime 80){ps-SleepTime - 30;ps-FoodWeight 2;}}else if (KEY_PRESS(VK_F4)){if (ps-FoodWeight 2){ps-SleepTime 30;ps-FoodWeight - 2;}}//休眠Sleep(ps-SleepTime);//走一步Snakemove(ps);KillBySelf(ps);KillByWall(ps);} while (ps-status OK);}按键检测我们前面已经定义过了 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 )1暂停pause() void pause() {while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}} }2判断下一个坐标是否是食物 int Nextblock(pSnake ps, pSnakeNode pNext) {if (ps-pFood-x pNext-x ps-pFood-y pNext-y){return 1;}else{return 0;} }1是食物 void IsFood(pSnake ps, pSnakeNode pNext) {pNext-next ps-pSnake;ps-pSnake pNext;pSnakeNode cur ps-pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}ps-Score ps-FoodWeight;free(ps-pFood);Createfood(ps); } 2不是食物 void NotFood(pSnake ps, pSnakeNode pNext) {pNext-next ps-pSnake;ps-pSnake pNext;pSnakeNode cur ps-pSnake;while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL; }3是否撞到墙 void 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;} } 4是否撞到自己 //是否撞自己 void KillBySelf(pSnake ps) {pSnakeNode cur ps-pSnake-next;//从第二个节点开始while (cur){if (cur-x ps-pSnake-x cur-y ps-pSnake-y){ps-status KILL_BY_SELF;return;}cur cur-next;} } 5蛇移动 void Snakemove(pSnake ps) {pSnakeNode pNext (pSnakeNode)malloc(sizeof(SnakeNode));if (pNext NULL){perror(CreateFood()::malloc());return;}pNext-next NULL;switch (ps-dir){case UP:pNext-x ps-pSnake-x;pNext-y ps-pSnake-y - 1;break;case DOWN:pNext-x ps-pSnake-x;pNext-y ps-pSnake-y 1;break;case LEFT:pNext-x ps-pSnake-x - 2;pNext-y ps-pSnake-y;break;case RIGHT:pNext-x ps-pSnake-x 2;pNext-y ps-pSnake-y;break;}//判断下一个坐标是都是食物if (Nextblock(ps, pNext)){IsFood(ps, pNext);}else{NotFood(ps, pNext);} }7.GameEnd() 完成上面的内容游戏已经可以游玩了,只是缺少了一些结束的提示但是我们要记得最后将开辟的空间释放。 代码示例 void GameEnd(pSnake ps) {SetPos(15, 12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_WALL:printf(撞墙了游戏结束\n);break;case KILL_BY_SELF:printf(咬到自己了游戏结束\n);break;}//释放贪吃蛇的链表资源pSnakeNode cur ps-pSnake;pSnakeNode del NULL;while (cur){del cur;cur cur-next;free(del);}free(ps-pFood);ps NULL; } 8.整合程序 void test() {//创建贪吃蛇Snake snake { 0 };GameStart(snake);//游戏前的初始化GameRun(snake);GameEnd(snake); } int main() {setlocale(LC_ALL, );test();//贪吃蛇游戏的测试SetPos(0, 27);return 0; } 这样贪吃蛇就完成了 9.代码展示: //snake.h #pragma once #define _CRT_SECURE_NO_WARNINGS #includestdio.h #include locale.h #includestdlib.h #includestdbool.h #includeWindows.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 )//设置控制台窗口 void setwindows(); //隐藏光标 void hidcursor(); //欢迎内容 void welcome(); //创建地图 void createmap(); //光标位置 void SetPos(int x, int y);//游戏的状态 enum GAME_STATUS {OK 1,//正常运行ESC, //按了ESC键退出正常退出KILL_BY_WALL,//撞墙KILL_BY_SELF //撞到自身 };//蛇行走的方向 enum DIRECTION {UP,DOWN,LEFT,RIGHT };//蛇身结点的定义 typedef struct SnakeNode {int x;int y;struct SnakeNode* next; }SnakeNode, * pSnakeNode;// 贪吃蛇 typedef struct Snake {pSnakeNode pSnake;//维护整条蛇的指针是指向蛇头pSnakeNode pFood;//指向食物的指针int Score;//当前累积的分数int FoodWeight;//一个食物的分数int SleepTime;//蛇休眠的时间休眠的时间越短蛇的速度越快休眠的时间越长蛇的速度越慢enum GAME_STATUS status;//游戏当前的状态enum DIRECTION dir;//蛇当前走的方向 }Snake, * pSnake;//初始化贪吃蛇 void InitSnake(pSnake ps); //创建食物 void Createfood(pSnake ps); //打印帮助信息 void PrintHelpInfo(); //游戏初始化 void GameStart(pSnake ps); //蛇移动 void Snakemove(pSnake ps); //打印蛇 void PrintShake(pSnake ps); //判断下一个坐标是否是食物 int Nextblock(pSnake ps, pSnakeNode pNext); //是食物 void IsFood(pSnake ps,pSnakeNode pNext); // 不是食物 void NotFood(pSnake ps, pSnakeNode pNext); //是否撞自己 void KillBySelf(pSnake ps); //是否撞墙 void KillByWall(pSnake ps); //游戏进程 void GameRun(pSnake ps); //游戏结束的资源释放 void GameEnd(pSnake ps); //snake.c #includeshake.h void setwindows() {system(title 贪吃蛇);system(mode con cols100 lines30); } void hidcursor() {//获得设备句柄HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);//定义控制台相关光标的结构体CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false;//光标可见性关闭SetConsoleCursorInfo(handle, CursorInfo);//设置控制台光标状态 }void SetPos(int x, int y) {//获得设备句柄HANDLE hanlde GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos { x, y };//设置控制台光标状态SetConsoleCursorPosition(hanlde, pos); }void welcome() {//欢迎信息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() {//上SetPos(0, 0);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//下SetPos(0, 26);for (int i 0; i 56; i 2){wprintf(L%lc, WALL);}//左for (int i 1; i 25; i){SetPos(0, i);wprintf(L%lc, WALL);}//右for (int 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 3; i){cur (pSnakeNode)malloc(sizeof(SnakeNode));if (cur NULL){perror(InitSnake():malloc());return;}cur-x POS_X 2 * i;cur-y POS_Y;cur-next NULL;//头插法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%lc, BODY);cur cur-next;}//贪吃蛇的其他信息初始化ps-dir RIGHT;ps-FoodWeight 10;ps-pFood NULL;ps-Score 0;ps-SleepTime 200;ps-status OK; } //创建食物 void Createfood(pSnake ps) {int x 0;int y 0;again:do{x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);//坐标和蛇的身体的每个节点的做坐标比较pSnakeNode cur ps-pSnake;while (cur){if (x cur-x y cur-y){goto again;}cur cur-next;}//创建食物pSnakeNode pFood (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood NULL){perror(CreateFood()::malloc());return;}pFood-x x;pFood-y y;ps-pFood pFood;SetPos(x, y);wprintf(L%lc, FOOD); }//打印帮助信息 void PrintHelpInfo() {SetPos(59, 15);printf(1.不要撞到墙);SetPos(59, 16);printf(2.不要撞到自己);SetPos(59, 17);printf(3.用 ↑ . ↓ . ← . → 来控制蛇的移动);SetPos(59, 18);printf(4.F3加速F4减速,加速能得到更高的分数);SetPos(59, 19);printf(5.ESC退出,space暂停);SetPos(59, 20);printf(Dream_Snowar所作); }//游戏初始化 void GameStart(pSnake ps) {setwindows();welcome();hidcursor();createmap();InitSnake(ps);Createfood(ps);PrintHelpInfo(); }//判断下一个坐标是否是食物 int Nextblock(pSnake ps, pSnakeNode pNext) {if (ps-pFood-x pNext-x ps-pFood-y pNext-y){return 1;}else{return 0;} }//space暂停 void pause() {while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}} } //打印蛇 void PrintShake(pSnake ps) {pSnakeNode cur ps-pSnake;while (cur){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;} }//是食物 void IsFood(pSnake ps, pSnakeNode pNext) {pNext-next ps-pSnake;ps-pSnake pNext;PrintShake(ps);ps-Score ps-FoodWeight;free(ps-pFood);Createfood(ps); } //不是食物 void NotFood(pSnake ps, pSnakeNode pNext) {pNext-next ps-pSnake;ps-pSnake pNext;pSnakeNode cur ps-pSnake;while (cur-next-next){SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}SetPos(cur-next-x, cur-next-y);printf( );free(cur-next);cur-next NULL; } //是否撞自己 void KillBySelf(pSnake ps) {pSnakeNode cur ps-pSnake-next;//从第二个节点开始while (cur){if (cur-x ps-pSnake-x cur-y ps-pSnake-y){ps-status KILL_BY_SELF;return;}cur cur-next;} } //是否撞墙 void 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;} }void Snakemove(pSnake ps) {pSnakeNode pNext (pSnakeNode)malloc(sizeof(SnakeNode));if (pNext NULL){perror(CreateFood()::malloc());return;}pNext-next NULL;switch (ps-dir){case UP:pNext-x ps-pSnake-x;pNext-y ps-pSnake-y - 1;break;case DOWN:pNext-x ps-pSnake-x;pNext-y ps-pSnake-y 1;break;case LEFT:pNext-x ps-pSnake-x - 2;pNext-y ps-pSnake-y;break;case RIGHT:pNext-x ps-pSnake-x 2;pNext-y ps-pSnake-y;break;}//判断下一个坐标是都是食物if (Nextblock(ps, pNext)){IsFood(ps, pNext);}else{NotFood(ps, pNext);} } //游戏运行 void GameRun(pSnake ps) { do{//当前的分数SetPos(59, 10);printf(总分:%d\n, ps-Score);SetPos(59, 11);printf(分数倍率:%02d\n, ps-FoodWeight);//检测按键,↑ . ↓ . ← . → . ESC . F3 . F4 . spaceif (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_ESCAPE)){ps-status ESC;break;}else if (KEY_PRESS(VK_SPACE)){//游戏暂停pause();}else if (KEY_PRESS(VK_F3)){if (ps-SleepTime 80){ps-SleepTime - 30;ps-FoodWeight 2;}}else if (KEY_PRESS(VK_F4)){if (ps-FoodWeight 2){ps-SleepTime 30;ps-FoodWeight - 2;}}//休眠Sleep(ps-SleepTime);//走一步Snakemove(ps);KillBySelf(ps);KillByWall(ps);} while (ps-status OK);} void GameEnd(pSnake ps) {SetPos(15, 12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_WALL:printf(撞墙了游戏结束\n);break;case KILL_BY_SELF:printf(咬到自己了游戏结束\n);break;}//释放贪吃蛇的链表资源pSnakeNode cur ps-pSnake;pSnakeNode del NULL;while (cur){del cur;cur cur-next;free(del);}free(ps-pFood);ps NULL; } //test.c #includeshake.h void test() {//创建贪吃蛇Snake snake { 0 };GameStart(snake);//游戏前的初始化GameRun(snake);GameEnd(snake); } int main() {setlocale(LC_ALL, );test();//贪吃蛇游戏的测试SetPos(0, 27);return 0; } C语言的学习结束了,把贪吃蛇作为最后的收官之作是我目前的想法,接下来我重点完成,C语言实践和数据结构的博客的撰写,希望大家多多支持.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/89881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电子商务网站设计与网络营销实验大连网络推广营销

游戏服务器过年这段时间忙完了,好久没看web了,重温一下。发现竟然没有文章记录这些修BUG的过程,记录一下。 目录 如何处理F5刷新? 如何处理F5刷新? 后端应该发现路由不存在,直接返回打包好的index.html就…

专业设计美容院装修公司兰州网络seo公司

一、什么是WebDriver WebDriver提供了另外一种方式与浏览器进行交互。那就是利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小&am…

广州网站建设排名一元夺宝网站开发

目录 目录 1 字典 1.1 字典的基本操作示例 1.2 字典推导式 2 集合 2.1 集合的常用操作示例 3 列表、元组、字典、集合的区别 1 字典 在Python中,字典(Dictionary)是一种无序的数据结构,用于存储键值对的集合。每个…

网站改版做301wordpress 侧边栏 修改字体大小

1.分片控制 在 IP 数据报报头中,标识、标志和片偏移3 个字段与控制分片和重组有关。 标识:是源主机赋予 IP 数据报的标识符。目的主机利用此域和目的地址判断收到的分片属于哪个数据报,以便数据报重组。分片时,该域必须不…

网络电商推广方案seo公司软件

现象 在使用前端工具vite(版本5),搭建vue3项目时,启动vite,浏览器显示页面:找不到localhost的网页, 起初怀疑是 未加参数 --host0.0.0.0,导致,后加上该参数后问题依旧 解决 将index.html页面…

深圳最好的网站建设公司哪家好wordpress换主题了

一、什么是HTML 超文本标记语言&#xff0c;不是一种编程语言&#xff0c;而是一种标记语言&#xff0c;描述网页的语言&#xff0c;HTML使用标签描述网页中图片、文本、音乐、视频、超链接等。 二、常用标签 1、标题标签 <h1>一级标题</h1> 1-6 2、段落标签<p&…

php网站开发实验总结长沙弧度seo

1、打开Android Studio 2、点击 New Project 选择 Empty Activity 3、点击 Next 4、点击 Finish 等待加载完成&#xff0c;取决于网络&#xff0c;第一次加载可能要很久。。。 5、下载完成 可以在右上角切换为 Project 模式 6、创建一个虚拟设备 https://www.bilibili…

wordpress 数据库ip深圳白帽优化

题目要求&#xff1a;给定一个字符串如“12*3”,没有括号&#xff0c;要求利用栈的知识来处理结果算出答案 我的思路&#xff1a;建立两个栈&#xff0c;一个存放数据&#xff0c;一个存放符号&#xff0c;再定义一个结构体做为操作的主体&#xff0c;然后制作几个函数&#x…

建设网站模块需要哪些网站备案个人和企业的区别

使用spring data JPA和mybatis都是用来访问数据库&#xff0c;但他们的分工不同&#xff1a; 1.spring data jpa默认使用hibernate作为ORM实现&#xff0c;是spring 提供的一套jpa接口&#xff0c;使用spring data jpa主要完成一些简单的增删改查功能。 2.对于复杂的查询功能会…

阿里云服务器配置网站博客网站开发利用数据库

element-ui的组件名就是类名 样式穿透&#xff08;用来修改没有类名的子组件样式&#xff09; 例如修改头部具名插槽的样式&#xff08;但是无法定位该元素&#xff09; 查看最后生成的html结构中对应的结构&#xff08;这里的头部有类名&#xff0c;可以直接对该类名进行样…

石家庄网站建设策划方案长沙网站推

全世界只有3.14 % 的人关注了爆炸吧知识传说我国&#xff0c;本科生遍地走&#xff0c;研究生多如狗。但一估算&#xff0c;从1977年高考恢复以来&#xff0c;国内现在的本科率竟然还不到5%。这样一想&#xff0c;30多年前的本科生数量肯定更少&#xff0c;也更珍贵。如果是北大…

做培训的都上哪些网站廉江新闻最新消息

文章目录 写在前面1. 类的6个默认成员函数2. 构造函数2.1 构造函数的引入2.1 构造函数的特性 3. 析构函数3.1 析构函数的引入3.2 析构函数的特性 4. 拷贝构造函数4.1 拷贝构造函数概念4.2 拷贝构造函数的特性4.3 拷贝构造函数典型调用场景 5. 赋值运算符重载5.1 运算符重载5.2 …

北京网站制作策划大都会app最新版本下载

http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/Default.aspx div圆角 tags 日期控件等等转载于:https://www.cnblogs.com/freedom831215/archive/2011/12/13/2286051.html

东莞购物网站音乐网站开发编程语言

在数字化时代&#xff0c;数据传输的同步技术对于确保信息的一致性和通信质量至关重要。本文将探讨数据传输同步技术的种类、如何实现高效安全的数据传输&#xff0c;以及企业在数据迁移中常用的几种方式。最后&#xff0c;我们将重点介绍镭速大数据迁移工具的优势。 数据传输同…

威海做网站的哪家好关于门户网站建设方案

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

没有做网站经验可以学seo吗wordpress直排主题

目 录 1 绪论 1.1 选题背景和意义 1.2国内外研究现状 1.3论文结构与章节安排 2 课堂考勤系统系统分析 2.1 可行性分析 2.1.1技术可行性分析 2.1.2 操作可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.3 系统用例分析 2.4 系统流程分析 2.…

宝丰县建设局网站wordpress仿百度首页

Python这个编程语言的大名当然听说过了呀&#xff0c;这几年特别火&#xff0c;火的一塌涂地。大家可以回忆一下&#xff1a;朋友圈推荐的广告里经常可以看见python的网课广告。 本学期&#xff0c;学校开设了python课程&#xff0c;这几天学习了一下入了一下门&#xff0c;感…

南通的互联网公司网站专业团队打造专业品质

一、memcpy —— 内存拷贝 void * memcpy ( void * destination, const void * source, size_t num ); memcpy函数用于将源内存区域的内容复制到目标内存区域。功能是将从source指向的内存起始位置连续num个字节的数据&#xff0c;原样复制到destination指向的内存区域。 例…

江苏苏州建设行政主管部门网站网站域名注册人查询

1. deque deque 容器用数组&#xff08;数组名假设为 map&#xff09;存储着各个连续空间的首地址。也就是说&#xff0c;map 数组中存储的都是指针如果 map 数组满了怎么办&#xff1f;很简单&#xff0c;再申请一块更大的连续空间供 map 数组使用&#xff0c;将原有数据&…

织梦做的网站怎么发布茶叶网站制作模板

目录 一、C中STL&#xff08;Standard Template Library&#xff09; 二、 Gun源代码开发精神 三、 实现版本 四、GNU C库的头文件分布 bits目录 ext目录 backward目录 iostream目录 stdexcept目录 string目录 上一篇文章&#xff1a; C标准模板库&#xff08;STL&am…