1688网站可以做全屏吗商丘网站建设网站推广
- 作者: 五速梦信息网
- 时间: 2026年03月17日 18:16
当前位置: 首页 > news >正文
1688网站可以做全屏吗,商丘网站建设网站推广,江苏提升关键词排名收费,镇江网页设计实战班本篇使用C语言实现贪吃蛇小游戏#xff0c;我们将其分为了三个大部分#xff0c;第一个部分游戏开始GameStart#xff0c;游戏运行GameRun#xff0c;以及游戏结束GameRun。对于整体游戏主要思想是基于链表实现#xff0c;但若仅仅只有C语言的知识还不够#xff0c;我们还… 本篇使用C语言实现贪吃蛇小游戏我们将其分为了三个大部分第一个部分游戏开始GameStart游戏运行GameRun以及游戏结束GameRun。对于整体游戏主要思想是基于链表实现但若仅仅只有C语言的知识还不够我们还需要学习控制台的一些相关操作结合实现贪吃蛇游戏所以我们先介绍了一些有关Win32 API的知识。 以下为整体实现的思路以及对应的代码在文章的末尾也给出了整体代码以及对应的测试有需要的读者可以根据目录直接跳到对应的位置。 另外这只是一个基础版本的读者还可在此基础上进行升级如 1.将地图的进行升级不在仅仅只是一个方框加大难度 2.写一个文件操作记录历史最高得分记录 3.将运行出来的效果加上各种动画等等。 1.Win32 API介绍 1.1 Win32 API Windows这个多作业系统除了协调应用程序的执行、内存分配、管理资源之外同时也作为一个很大的服务中心调用这个服务中心的各种服务每一种服务就是一个函数可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的由于这些函数服务的对象是应用程序Application)所以将其称之为Application Programming Interface简称API函数WIN32 API也就是Microsoft Windows32位平台的应用程序编程接口。 1.2 控制台程序 平时通过VS2022或者Windows命令提示符cmd运行起来的黑框程序就是控制台程序 我们可以通过使用cmd命令来控制控制台窗口的长宽如下控制台窗口的大小为30行、100列。 mode con cols100 lines30 如上图所示可以通过cmd命令来设置控制台窗口的长宽。 还可以使用命令设置控制台窗口的名字 如果要将以上的控制台窗口执行的命令调用在C语言中我们可以使用C语言函数中的system来执行如下 #include stdio.h #include Windows.hint main() {system(mode con cols100 lines30);system(title Snake);getchar();return 0; } 如果使用上述的C语言命令无法实现该情况请先将C语言中的默认终端应用程序 改为Windows控制台主机如下 对VS弹出的控制终端鼠标右键点击属性点击终端找到对应的位置修改即可。 1.3 控制台屏幕上的坐标COORD COORD是Windows API中定义的一个结构体表示一个字符在控制台屏幕上的坐标。 使用该结构体需要头文件 Windows.h。 typedef struct _COORD {SHORT X;SHORT Y; }COORD, *PCOORD;COORD pos{ 10, 15 }; //给坐标赋值 通过以上的坐标结构体我们可以实现控制一个字符在控制台屏幕的坐标便于我们在控制台不同的位置打印该字符。 1.4 GetStdHandle GetStdHandle 是一个Windows API函数。用于从一个特定的标准设备标准输入标准输出或者标准错误中取得一个句柄用来标识不同设备的数值使用这个句柄可以操作设备。 即若我们我们需要对某一个打开的控制台程序进行操作我们就必须通过GetStdHandle这个函数得到对应的控制台标识获取权限才可以对中国控制台程序进行操作。 HANDLE hOutput NULL;//获取标准输出的句柄用来标识不同设备的数值hOutput GetStdHandle(STD_OUTPUT_HANDLE); 1.5 GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标大小和可见性信息 BOOL WINAPI GetConsoleCursorInfo{HANDLE hConsoleOutput;PCONSOLE_CURSOR_INFO lpConsoleCursorInfo; };//PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 结构体的指针 //该结构体接收有关主机游标的信息//CONSOLE_CURSOR_INFO 结构体 typedef struct _CONSOLE_CURSOR_INFO {DWORD dwSize;BOOL bVisible; }CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; 对于 CONSOLE_CURSOR_INFO 结构体来说 对应其中的dwSize有光标填充的字符单元格百分比。此值介于1到100之间。光标的外观会变化范围从填充单元格到单元格底部消失通常取值0、25、50、75、100. bVisible游标的可见性若光标可见则此成员为TURE反之为FALSE。 对于SetConsoleCursorInfo函数来说就是将设置的CONSOLE_CURSOR_INFO类型变量进行设置设置指定控制台缓冲区的光标的大小和可见性。如下操作我们可以将控制台缓冲区的光标隐藏。 int main() {COORD pos { 40, 10 };CONSOLE_CURSOR_INFO cursor_info {0};HANDLE handle GetStdHandle(STD_OUTPUT_HANDLE);GetConsoleCursorInfo(handle, cursor_info);cursor_info.dwSize 100;cursor_info.bVisible false;//隐藏SetConsoleCursorInfo(handle, cursor_info);getchar(); //用于将程序暂停在此要不然会一下运行结束return 0; } 不仅仅可以将光标隐藏还可以将光标的大小设置为任意位置读者可以自行操作。 1.6 SetConsoleCursorPosition 该函数设置控制台屏幕缓冲区中光标的位置我们将想要设置的坐标信息放在COORD类型的pos中调用SetConsoleCursorPosition 函数将光标位置设置到指定位置。所以该函数可以使我们在指定位置打印出我们想要的结果。如下 int main() {COORD pos { 10, 5 };HANDLE hOutput NULL;hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);printf(haha\n);return 0; } 使用如上函数我们就可以在指定的位置打印出我们想要的数据。 为了方便我们可以封装一个设置光标位置的函数 void SetPos(short x, short y) {COORD pos { x,y };HANDLE hOutput NULL;//获取标准输出的句柄hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置光标位置SetConsoleCursorPosition(hOutput, pos); } 1.7 GetAsyncKeyState 该函数的作用为可以将键盘上的每一个健的虚拟键值传递给函数函数通过返回值来区分按键的状态。 该函数的返回值为short类型在上一次调用GetAsyncKeyState函数之后如果返回的16为的short类型数据中最高位为1说明按键的状态是按下若最高层是0说明按键的状态是抬起如果最低位置被置为1说明该按键被按过若为0则没有被按过。 所以我们可以定义一个宏来判断虚拟按键VK是否被按过 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) 0x1) ? 1 : 0 ) 该宏就可以将我们的按键信息传达给程序便于我们操作贪吃蛇。 2.贪吃蛇程序的设计 前面的一些基础知识介绍完之后我们就需要开始进行正式的贪吃蛇程序的设计了首先贪吃蛇游戏的板块一共分为三个部分其中分别为游戏开始前GameStart、游戏运行时GameRun、游戏结束之后GameEnd三个大模块在这三个大模块中也包含许多小模块我将以层次图给出如下 上图则为我们大概将要实现的步骤所以将按照当前思路进行讲解。
C语言库函数本地化 在进行代码编写前我们需要先对程序进行本地化因为在C语言中并不是适用于所有地区的字符所以如果我们需要使用C语言库中允许打印之外的符号那么我们需要先对当前的C语言环境进行本地化。 locale.h本地化locale.h提供的函数用于控制C标准库对于不同地区会产生不一样的行为的部分。在标准可以中依赖于地区部分一共有数字量的格式、货币量的格式、字符集、日期和时间的表示形式。 类项通过修改地区程序可以改变它的行为来适应世界的不同区域但是地区的改变可能将会影响库的许多部分其中一部分可能是我们并不希望修改的所以C语言中支持针对不同的类项进行修改如这些宏LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME、LC_ALL—针对所有类项修改。 对于以上的宏的使用我们需要使用setlocale函数对于setlocale该函数的使用如下
//执行C标准库环境 setlocale(LC_ALL, C);//将C标准库本地化 setlocale(LC_ALL, ); 2.1 贪吃蛇数据结构 蛇身首先对于贪吃蛇结点的设计因为贪吃蛇处于一个移动的形式所以我们在贪吃蛇结构体的设置中需要定义出贪吃蛇的坐标一级下一个结点的指针。 整个游戏然后就是对整个游戏维护的结构体对于整个游戏维护的结构体中首先需要对整个蛇进行维护所以设置一个结构体指针指向蛇头然后就是对食物的维护食物同样采用蛇身的结构体然后是总分和每个食物的分数还有每一次程序休眠的时间休眠时间决定贪吃蛇的前进的速度以及当前蛇头的方向和蛇的状态。 代码如下 //枚举当前的蛇的方向 enum DIRECTION { UP, DOWN, LEFT, RIGHT }; //当前蛇的状态OK正常允许ESC主动退出KILL_BY_WALL被墙杀死KILL_BY_SELF咬到自己死亡 enum STATUS { OK, ESC, KILL_BY_WALL, KILL_BY_SELF };#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)typedef struct SnakeNode {int x; //x轴坐标int y; //y轴坐标struct SnakeNode* next; }SnakeNode;typedef struct Snake {SnakeNode* SnakeHead; //蛇头用来维护整个蛇身SnakeNode* pFood; //食物维护食物的指针int score; //总分用来计算当前得分int foodWeight; //食物分数默认食物的分数int SleepTime; //每一步的休眠时间enum DIRECTION dir; //蛇头的方向默认向右enum STATUS status; //蛇的状态当前蛇的状态 }Snake; 2.2 GameStart 2.2.1 欢迎界面 在打印欢迎界面之前我们需要将控制台的窗口大小设置为固定大小并且设置窗口名称同时获取标准输出句柄然后将光标隐藏起来具体操作如下 void GameStart(Snake* ps) {//先设置当前窗口大小system(mode con cols100 lines30);//设置窗口名system(title Snake);//获取标准输出的句柄HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);//隐藏当前光标CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//打印地图CreateMap();//初始化蛇InitSnake(ps);//创建一个食物CreateFood(ps); } 该操作都是通过以上对Win32 API介绍的知识。 然后就是对欢迎界面的设置对于欢迎界面我们要将其设置为如下形式其中欢迎在中间位置按任意位置继续在界面下端。第二个界面为操作方式讲解也是位于中间位置。 设置以上形式的打印我们只需要调用以上设置位置的函数然后在打印即可当然还涉及以下暂停函数和清屏函数如下 void SetPos(short x, short y) {COORD pos { x,y };HANDLE hOutput NULL;//获取标准输出句柄hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上的光标的位置SetConsoleCursorPosition(hOutput, pos); }void WelcomeToGame() {SetPos(40, 15); //大概设置在中间位置具体可看自己的偏好printf(欢迎来到贪吃蛇小游戏);SetPos(40, 25); //在下端设置“请按任意位置继续…”system(pause);system(cls); //清屏SetPos(25, 12); printf(⽤ ↑ . ↓ . ← . → 分别控制蛇的移动 F3为加速F4为减速\n);SetPos(25, 13);printf(加速将得到更高的分数.\n);SetPos(40,25);system(pause);system(cls); } 2.2.2 打印地图 对于地图的设计我们大概设计出下列的地图大致呈现一个正方形但是在控制台缓冲区的形式如下对于一个光标的位置高度大概是宽度的两倍所以我们设计出来的宽必须是列的两倍我们使用打印墙的字符为宽字符本地字符刚好占两个字符位所以我们生成的宽度必须位偶数。 我们将分别打印墙的上半部分、下半部分、左边和右边如下 void CreateMap() {int i 0;SetPos(0, 0);//打印上面for (i 0; i 58; i2) {wprintf(L%lc, WALL);}//打印下面SetPos(0, 26);for (i 0; i 58; i 2) {wprintf(L%lc, WALL);}//打印左边for (i 1; i 26; i) {SetPos(0, i);wprintf(L%lc, WALL);}//打印右边for (i 1; i 26; i) {SetPos(56, i);wprintf(L%lc, WALL);} } 2.2.3 初始化蛇 现在我们需要将蛇初始化对于蛇的初始化我们默认将蛇的身体设置为5个结点每一个结点我们采用链表头插的方式进行插入从第二十四列第5行开始向右头插。在设置完蛇身之后我们将蛇给打印出来然后将蛇的其他信息初始化食物指针置为NULL默认方向设置为RIGHT分数为0每个食物的分数为10分默认状态为OK休眠时间为200ms如下 注对于蛇身结点的设置对于x坐标必须为偶数因为对于以上的墙假若我们撞左墙或者右墙时刚好横坐标为偶数便于我们识别撞墙。 void InitSnake(Snake* ps) {SnakeNode* cur NULL;for (int i 0; i 5; i) {cur (SnakeNode*)malloc(sizeof(SnakeNode));if (cur NULL) {perror(InitSnake malloc:);exit(1);}cur-x POS_X 2 * i;cur-y POS_y;cur-next NULL;if (ps-SnakeHead NULL) {ps-SnakeHead cur;}else {cur-next ps-SnakeHead;ps-SnakeHead cur;}}//打印蛇身cur ps-SnakeHead;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;} 2.2.4 创建食物 食物创建的结点按照蛇身结点创建其中仍然必须遵守横坐标为偶数因为蛇的横坐标为偶数 吃到食物的时候能更好接上。所以对于食物的生成我们使用rand函数进行生成但是对于食物的生成有两点需要注意的 1.食物的随机生成不能生成在墙外 2.食物的随机生成不能生成在蛇的身上。 最后我们需要将食物打印在屏幕上实现的代码如下 void CreateFood(Snake* ps) {SnakeNode* cur ps-SnakeHead;int x 0;int y 0;do {x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);while (cur) {if (cur-x x cur-y y) {do {x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);}cur cur-next;}//创建食物SnakeNode* Food (SnakeNode)malloc(sizeof(SnakeNode));if (Food NULL) {perror(CreateFood malloc:);exit(1);}Food-x x;Food-y y;Food-next NULL;ps-pFood Food;SetPos(x, y);wprintf(L%lc, FOOD); } 实现完以上步骤之后我们打印出来的界面就为 2.3 GameRun 对于GameRun函数的基本框架如下 void GameRun(Snake ps) {ps-status OK;//打印右侧帮助信息PrintHelpInfo();do {GainKeyInfo(ps);if (ps-status ESC) {break;}SnakeMove(ps);Sleep(ps-SleepTime);} while (ps-status OK); } 2.3.1 打印帮助信息 打印出来的帮助信息其实就为一些游戏规则和游戏操作还是按照以上类似的操作进行写代码 void PrintHelpInfo() {SetPos(64, 15);printf(不能穿墙不能咬到自己\n);SetPos(64, 16);printf(用↑.↓.←.→分别控制蛇的移动.);SetPos(64, 17);printf(F3为加速F4为减速);SetPos(64, 18);printf(ESC: 退出游戏、space暂停游戏.);SetPos(64, 20);printf(版权桀桀桀桀桀桀); }2.3.2 获取键盘信息 从键盘获取信息是非常重要的一部分其中涉及到我们之前定义的宏在接收到键盘中上、下、左、右的信息时我们还需要判断当前位置的情况也就是说蛇向下移动时不能向上进行掉头向左移动时不能向右进行掉头……。 另外因为是频繁接收到信息得分和每一个食物所占分数是变化的。所以我们还需要在这一部分把当前得分给打印出来以及当前每一个食物所占的分数速度越快获取的分数越多速度越慢获取的分数越少。 当按下空格健的时候我们需要将游戏暂停所以我们需要设计一个死循环当再一次按下空格键的时候跳出循环每一次循环随眠100ms或者200ms。 获取到F3和F4时我们需要将对应的休眠时间和每个食物的分数进行调整每一次加速休眠时间减少30ms食物分数增加2每一次减速休眠时间增加30ms食物分数减少2休眠时间最少为80ms食物分数最少为2分。 具体代码如下 //空格键暂停 void pause() {while (1) {Sleep(100);if (KEY_PRESS(VK_SPACE)) {break;}} }void GainKeyInfo(Snake* ps) {SetPos(64, 10); printf(得分%5d, ps-score);SetPos(64, 11);printf(每个食物得分%2d, 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_RIGHT) ps-dir ! LEFT) {ps-dir RIGHT;}else if (KEY_PRESS(VK_LEFT) ps-dir ! RIGHT) {ps-dir LEFT;}else if (KEY_PRESS(VK_SPACE)) {pause();}else if (KEY_PRESS(VK_ESCAPE)) {ps-status ESC;}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;}} } 2.3.3 蛇的移动 蛇的移动部分属于整个贪吃蛇中最为关键也是最为复杂的一个部分。 首先我们需要考虑在当前情况下如果进行转向刚好吃到食物的情况以及转向之后不是食物的情况以及在贪吃蛇每走一步都需要判断是否撞墙或者是否咬到自己。 转向遇到食物创建一个结点在蛇要走的下一个位置若这个结点刚好与食物重叠那么将创建的结点头插到蛇中然后将食物的空间删除。然后将整条蛇打印一遍。最后在创建出一个食物。 转向没有遇到食物创建一个结点在蛇要走的下一个位置下一个位置不是食物将这个结点插入到蛇中然后将蛇打印出来但是最后一个结点不能打印最后一个结点的位置打印两个空格然后将最后一个结点释放掉。 撞墙检测每走完一步都需要将蛇的头结点与墙的位置进行判断如果出现在墙的位置那么就撞墙了将蛇的状态改为KILL_BY_WALL。 咬到自己检测每走完一步都需要将蛇的头结点与身上的各个结点进行对比若出现横纵坐标都相等的情况那么说明已经咬到自己了将蛇的状态改为KILL_BY_SELF。 实现的代码如下 //下一个结点是食物 int NextIsFood(SnakeNode* nextNode, Snake* ps) {if (nextNode-x ps-pFood-x nextNode-y ps-pFood-y) {return 1;}else {return 0;} }//下一个结点是食物吃掉食物 void EatFood(SnakeNode* nextNode, Snake* ps) {nextNode-next ps-SnakeHead;ps-SnakeHead nextNode;SnakeNode* cur ps-SnakeHead;while (cur) {SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}ps-score ps-foodWeight;free(ps-pFood);//创建新食物CreateFood(ps); }//下一个结点不是食物不吃食物 void NotEatFood(SnakeNode* nextNode, Snake* ps) {nextNode-next ps-SnakeHead;ps-SnakeHead nextNode;SnakeNode* cur ps-SnakeHead;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 KillByWall(Snake* ps) {if (ps-SnakeHead-x 0 ||ps-SnakeHead-x 56 ||ps-SnakeHead-y 0 ||ps-SnakeHead-y 26) {ps-status KILL_BY_WALL;} }//检测是否咬到自己 void KillBySelf(Snake* ps) {SnakeNode* cur ps-SnakeHead-next;while (cur) {if (ps-SnakeHead-x cur-x ps-SnakeHead-y cur-y) {ps-status KILL_BY_SELF;return;}cur cur-next;} }void SnakeMove(Snake* ps) {//创建下一个结点SnakeNode* nextNode (SnakeNode)malloc(sizeof(SnakeNode));if (nextNode NULL) {perror(SnakeMove malloc:);exit(1);}//确定下一个节点的位置switch (ps-dir){case UP:{nextNode-x ps-SnakeHead-x;nextNode-y ps-SnakeHead-y - 1;}break;case DOWN: {nextNode-x ps-SnakeHead-x;nextNode-y ps-SnakeHead-y 1;}break;case RIGHT: {nextNode-x ps-SnakeHead-x 2;nextNode-y ps-SnakeHead-y;}break;case LEFT: {nextNode-x ps-SnakeHead-x - 2;nextNode-y ps-SnakeHead-y;}break;}if (NextIsFood(nextNode, ps)) {EatFood(nextNode, ps);}else {NotEatFood(nextNode,ps);}KillByWall(ps);KillBySelf(ps); }void GameRun(Snake ps) {ps-status OK;//打印右侧帮助信息PrintHelpInfo();do {GainKeyInfo(ps);if (ps-status ESC) {break;}SnakeMove(ps);Sleep(ps-SleepTime);} while (ps-status OK); } 实现完以上的步骤之后贪吃蛇代码就已经可以运行起来了但是我们还是需要对后续进行处理。 2.4 GameEnd 接下来就是对游戏的善后工作了我们需要检测游戏是因为什么而结束的然后在屏幕中间打印出结束的原因最后我们将蛇的各个结点进行释放。 void GameEnd(Snake* ps) {SnakeNode* cur ps-SnakeHead;SetPos(15, 12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_SELF:printf(很遗憾你咬到了你自己\n);break;case KILL_BY_WALL:printf(很遗憾你撞到墙了\n);break;}while (cur) {SnakeNode* next cur-next;free(cur);cur next;}free(ps-pFood);ps-pFood NULL;ps-SnakeHead NULL;ps NULL; } 3.总代码 3.1 snake.h #pragma once #include stdio.h #include stdlib.h #include Windows.h #include stdbool.h #include locale.h//枚举当前的蛇的方向 enum DIRECTION { UP, DOWN, LEFT, RIGHT }; //当前蛇的状态OK正常允许ESC主动退出KILL_BY_WALL被墙杀死KILL_BY_SELF咬到自己死亡 enum STATUS { OK, ESC, KILL_BY_WALL, KILL_BY_SELF };#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)typedef struct SnakeNode {int x; //x轴坐标int y; //y轴坐标struct SnakeNode* next; }SnakeNode;typedef struct Snake {SnakeNode* SnakeHead; //蛇头用来维护整个蛇身SnakeNode* pFood; //食物维护食物的指针int score; //总分用来计算当前得分int foodWeight; //食物分数默认食物的分数int SleepTime; //每一步的休眠时间enum DIRECTION dir; //蛇头的方向默认向右enum STATUS status; //蛇的状态当前蛇的状态 }Snake;//设置光标位置 void SetPos(short x, short y);//游戏开始 void GameStart(Snake* ps);//欢迎界面 void WelcomeToGame();//打印地图 void CreateMap();//初始化蛇 void InitSnake(Snake* ps);//创建食物 void CreateFood(Snake* ps);//运行游戏 void GameRun(Snake* ps);//打印右侧帮助信息 void PrintHelpInfo();//获取键盘信息 void GainKeyInfo(Snake* ps);//暂停游戏 void pause();//蛇移动 void SnakeMove(Snake* ps);//如果下一个位置就是食物 int NextIsFood(SnakeNode* nextNode, Snake* ps);//吃掉食物 void EatFood(SnakeNode* nextNode, Snake* ps);//不是食物 void NotEatFood(SnakeNode* nextNode,Snake* ps);//被墙杀死 void KillByWall(Snake* ps);//被自己杀死 void KillBySelf(Snake* ps);//游戏结束。处理 void GameEnd(Snake* ps); 3.2 snake.c #define _CRT_SECURE_NO_WARNINGS 1 #include snake.hvoid SetPos(short x, short y) {COORD pos { x,y };HANDLE hOutput NULL;//获取标准输出句柄hOutput GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上的光标的位置SetConsoleCursorPosition(hOutput, pos); }void WelcomeToGame() {SetPos(40, 15); //大概设置在中间位置具体可看自己的偏好printf(欢迎来到贪吃蛇小游戏);SetPos(40, 25); //在下端设置“请按任意位置继续…”system(pause);system(cls); //清屏SetPos(25, 12); printf(⽤ ↑ . ↓ . ← . → 分别控制蛇的移动 F3为加速F4为减速\n);SetPos(25, 13);printf(加速将得到更高的分数.\n);SetPos(40,25);system(pause);system(cls); }void CreateMap() {int i 0;SetPos(0, 0);//打印上面for (i 0; i 58; i2) {wprintf(L%lc, WALL);}//打印下面SetPos(0, 26);for (i 0; i 58; i 2) {wprintf(L%lc, WALL);}//打印左边for (i 1; i 26; i) {SetPos(0, i);wprintf(L%lc, WALL);}//打印右边for (i 1; i 26; i) {SetPos(56, i);wprintf(L%lc, WALL);} }void InitSnake(Snake* ps) {SnakeNode* cur NULL;for (int i 0; i 5; i) {cur (SnakeNode*)malloc(sizeof(SnakeNode));if (cur NULL) {perror(InitSnake malloc:);exit(1);}cur-x POS_X 2 * i;cur-y POS_y;cur-next NULL;if (ps-SnakeHead NULL) {ps-SnakeHead cur;}else {cur-next ps-SnakeHead;ps-SnakeHead cur;}}//打印蛇身cur ps-SnakeHead;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(Snake* ps) {SnakeNode* cur ps-SnakeHead;int x 0;int y 0;do {x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);while (cur) {if (cur-x x cur-y y) {do {x rand() % 53 2;y rand() % 24 1;} while (x % 2 ! 0);}cur cur-next;}//创建食物SnakeNode* Food (SnakeNode)malloc(sizeof(SnakeNode));if (Food NULL) {perror(CreateFood malloc:);exit(1);}Food-x x;Food-y y;Food-next NULL;ps-pFood Food;SetPos(x, y);wprintf(L%lc, FOOD); }void GameStart(Snake ps) {//先设置当前窗口大小system(mode con cols100 lines30);//设置窗口名system(title Snake);//获取标准输出的句柄HANDLE hOutput GetStdHandle(STD_OUTPUT_HANDLE);//隐藏当前光标CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(hOutput, CursorInfo);//获取控制台光标信息CursorInfo.bVisible false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, CursorInfo);//设置控制台光标状态//打印欢迎界面WelcomeToGame();//打印地图CreateMap();//初始化蛇InitSnake(ps);//创建一个食物CreateFood(ps); }void PrintHelpInfo() {SetPos(64, 15);printf(不能穿墙不能咬到自己\n);SetPos(64, 16);printf(用↑.↓.←.→分别控制蛇的移动.);SetPos(64, 17);printf(F3为加速F4为减速);SetPos(64, 18);printf(ESC: 退出游戏、space暂停游戏.);SetPos(64, 20);printf(版权桀桀桀桀桀桀); }void GainKeyInfo(Snake* ps) {SetPos(64, 10);printf(得分%5d, ps-score);SetPos(64, 11);printf(每个食物得分%2d, 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_RIGHT) ps-dir ! LEFT) {ps-dir RIGHT;}else if (KEY_PRESS(VK_LEFT) ps-dir ! RIGHT) {ps-dir LEFT;}else if (KEY_PRESS(VK_SPACE)) {pause();}else if (KEY_PRESS(VK_ESCAPE)) {ps-status ESC;}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;}} }void pause() {while (1) {Sleep(100);if (KEY_PRESS(VK_SPACE)) {break;}} }int NextIsFood(SnakeNode* nextNode, Snake* ps) {if (nextNode-x ps-pFood-x nextNode-y ps-pFood-y) {return 1;}else {return 0;} }void EatFood(SnakeNode* nextNode, Snake* ps) {nextNode-next ps-SnakeHead;ps-SnakeHead nextNode;SnakeNode* cur ps-SnakeHead;while (cur) {SetPos(cur-x, cur-y);wprintf(L%lc, BODY);cur cur-next;}ps-score ps-foodWeight;free(ps-pFood);//创建新食物CreateFood(ps); }void NotEatFood(SnakeNode* nextNode, Snake* ps) {nextNode-next ps-SnakeHead;ps-SnakeHead nextNode;SnakeNode* cur ps-SnakeHead;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 KillByWall(Snake* ps) {if (ps-SnakeHead-x 0 ||ps-SnakeHead-x 56 ||ps-SnakeHead-y 0 ||ps-SnakeHead-y 26) {ps-status KILL_BY_WALL;} }void KillBySelf(Snake* ps) {SnakeNode* cur ps-SnakeHead-next;while (cur) {if (ps-SnakeHead-x cur-x ps-SnakeHead-y cur-y) {ps-status KILL_BY_SELF;return;}cur cur-next;} }void SnakeMove(Snake* ps) {//创建下一个结点SnakeNode* nextNode (SnakeNode)malloc(sizeof(SnakeNode));if (nextNode NULL) {perror(SnakeMove malloc:);exit(1);}//确定下一个节点的位置switch (ps-dir){case UP:{nextNode-x ps-SnakeHead-x;nextNode-y ps-SnakeHead-y - 1;}break;case DOWN: {nextNode-x ps-SnakeHead-x;nextNode-y ps-SnakeHead-y 1;}break;case RIGHT: {nextNode-x ps-SnakeHead-x 2;nextNode-y ps-SnakeHead-y;}break;case LEFT: {nextNode-x ps-SnakeHead-x - 2;nextNode-y ps-SnakeHead-y;}break;}if (NextIsFood(nextNode, ps)) {EatFood(nextNode, ps);}else {NotEatFood(nextNode,ps);}KillByWall(ps);KillBySelf(ps); }void GameRun(Snake ps) {ps-status OK;//打印右侧帮助信息PrintHelpInfo();do {GainKeyInfo(ps);if (ps-status ESC) {break;}SnakeMove(ps);Sleep(ps-SleepTime);} while (ps-status OK); }void GameEnd(Snake* ps) {SnakeNode* cur ps-SnakeHead;SetPos(15, 12);switch (ps-status){case ESC:printf(主动退出游戏正常退出\n);break;case KILL_BY_SELF:printf(很遗憾你咬到了你自己\n);break;case KILL_BY_WALL:printf(很遗憾你撞到墙了\n);break;}while (cur) {SnakeNode* next cur-next;free(cur);cur next;}free(ps-pFood);ps-pFood NULL;ps-SnakeHead NULL;ps NULL; } 3.3 test.c #define _CRT_SECURE_NO_WARNINGS 1 #include snake.hvoid Test01() {int ch 0;do {Snake snake { 0 };GameStart(snake);GameRun(snake);GameEnd(snake);SetPos(20, 15);printf(再来一局吗(Y/N));ch getchar();getchar();} while (ch Y || ch y); }int main() {//修改适配本地中文环境setlocale(LC_ALL, );Test01();SetPos(0, 27);return 0; } 至此整个游戏的编写就结束了读者还可以对这个代码进行升级比如 1.将地图的进行升级不在仅仅只是一个方框加大难度 2.写一个文件操作记录历史最高得分记录 3.将运行出来的效果加上各种动画。等等。 4.运行结果
- 上一篇: 1688网站店招怎么做南山区网站建设
- 下一篇: 1688网站特点wordpress 图片站模板
相关文章
-
1688网站店招怎么做南山区网站建设
1688网站店招怎么做南山区网站建设
- 技术栈
- 2026年03月17日
-
1688网站店招怎么做旅游网站开发难吗
1688网站店招怎么做旅游网站开发难吗
- 技术栈
- 2026年03月17日
-
1688购物平台模版网站利于优化
1688购物平台模版网站利于优化
- 技术栈
- 2026年03月17日
-
1688网站特点wordpress 图片站模板
1688网站特点wordpress 图片站模板
- 技术栈
- 2026年03月17日
-
1688网站特点上海网站建设代码
1688网站特点上海网站建设代码
- 技术栈
- 2026年03月17日
-
1920的网站做字体大小网站怎么做站内搜索
1920的网站做字体大小网站怎么做站内搜索
- 技术栈
- 2026年03月17日






