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

贪吃蛇(c实现)

目录

游戏说明:

 第一个是又是封面,第二个为提示信息,第三个是游戏运行界面

游戏效果展示:

 游戏代码展示:

snack.c

 test.c

 snack.h

控制台程序的准备:

控制台程序名字修改:

 参考:mode命令(mode | Microsoft Learn)

游戏框架构建:

控制台屏幕上的坐标COORD:

隐藏光标:

 光标跳转

打印颜色设置:

初始化界面:

需要注意的地方就是:

 例如第一次的坐标就为 (i,j) 那么下一次坐标就为(i+2,j);

 宽字符打印准备:

初始化蛇与蛇的打印:

随机创建食物:

蛇的单向移动:

大致小部分已经实现完成,那么就利用游戏逻辑来实现剩余的代码;

添加方向的改变与判断蛇的各个状态判断:

 对该函数里面各个小函数进行代码展示:

最后,还有对应的就是运行是代码的逻辑展示

速度的控制(单位毫秒):

 

 最后的游戏收尾就是提示信息的打印:

最后一步便是锦上添花了,就是打印提示信息:

到这里就已经完成了,一共有三个页面:

 第一个是又是封面,第二个为提示信息,第三个是游戏运行界面


 

游戏说明:

  1. 按方向键上下左右,可以实现蛇移动方向的改变
  2. 按F3加速,F4减速
  3. 按ESC正常退出游戏,按空格暂停游戏
  4. 加速可以获得更多的分数
  5. 获得100即可获得胜利

 (待优化部分:背景音乐,记录历史最高得分)

 第一个是又是封面,第二个为提示信息,第三个是游戏运行界面

游戏效果展示:

贪吃蛇游戏当中蛇的移动速度可以进行调整,动图当中把速度调得较慢(速度太快导致动图上蛇身显示不全),下面给出的代码当中将蛇的速度调整到了合适的位置,大家可以试试。

贪吃蛇

 

 游戏代码展示:

snack.c

#define  _CRT_SECURE_NO_WARNINGS#include"snack.h"
void color(int c)
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //颜色设置//注:SetConsoleTextAttribute是一个API(应用程序编程接口)
}
void cursor_hide()
{HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标 SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态 
}void SetPos(int x,int y)
{//获得标准输出设备的句柄HANDLE hOutput = NULL;hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//定位光标的位置,到posCOORD pos = { x,y };SetConsoleCursorPosition(hOutput, pos);
}void Welcome_game()
{color(9);SetPos(35, 12);wprintf(L"欢迎来到贪吃蛇小游戏\n");SetPos(36, 18);system("pause");system("cls");SetPos(25, 14);wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");SetPos(25, 15);wprintf(L"按F3加速,F4减速");SetPos(25, 16);wprintf(L"按ESC正常退出游戏,按空格暂停游戏");SetPos(25, 17);wprintf(L"加速可以获得更多的分数");SetPos(25, 18);wprintf(L"由能力有限公司提供技术支持");SetPos(0, 25);system("pause");system("cls");color(7);
}void CreatMap()
{color(12);//上for (int i = 0; i < 29; i++){wprintf(L"%lc", L'□');}//下SetPos(0, 26);for (int i = 0; i < 29; i++){wprintf(L"%lc", L'□');} //左for (int i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%lc", L'□');}//右for (int i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%lc", L'□');}color(7);
}void CreateSnack(pSnack ps)
{color(10);//默认开始初始化为5个结点pSnackNode cur = NULL;for (int i = 0; i < 5; i++){cur =(pSnackNode)malloc(sizeof(SnackNode));cur->next = NULL;cur->x = POS_X + i * 2;cur->y = POS_Y;if (ps->_psnack == NULL)//第一次头插{ps->_psnack = cur;}else{cur->next = ps->_psnack;ps->_psnack = cur;}}while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}cur= ps->_psnack;//设置蛇的相关信息ps->_dir = RIGHT;ps->_food_weight = 10;ps->_sleep_time = 200;ps->_status = OK;color(7);
}void CreateFood(pSnack ps)
{int x = 0;//2-54int y = 0;//1-25again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x%2!=0);//检测改坐标是否与蛇身重合 pSnackNode cur = ps->_psnack;while (cur){if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}pSnackNode SnackFood = (pSnackNode)malloc(sizeof(SnackNode));if (SnackFood == NULL){perror("CreateFood malloc fail");return;}color(13);SnackFood->x = x;SnackFood->y = y;SnackFood->next = NULL;SetPos(x, y);wprintf(L"%lc", Food);ps->_pfood = SnackFood;color(7);
}void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE)){break;}}
}void GameStart(pSnack ps)
{system("mode con cols=100 lines=30");system("title 贪吃蛇");//1光标隐藏cursor_hide();//2.打印环境界面//第一个界面,欢迎// 第二个界面,介绍怎么操作游戏Welcome_game();//+3.功能介绍CreatMap();//创建蛇CreateSnack(ps);//创建食物CreateFood(ps);//SetPos(0, 29);//system("pause");
}void PrintHelpInfo()
{color(15);SetPos(64, 10);wprintf(L"不能穿墙,不能咬到自己");SetPos(64, 12);wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");SetPos(64, 14);wprintf(L"按F3加速,F4减速");SetPos(64, 16);wprintf(L"按ESC正常退出游戏,按空格暂停游戏");SetPos(64, 18);wprintf(L"能力有限公司提供支持");SetPos(0, 29);//	system("pause");color(7);
}bool Next_Is_Food(pSnackNode pn, pSnack ps)
{return (ps->_pfood->x == pn->x && ps->_pfood->y == pn->y);
}void Eat_Food(pSnackNode pn, pSnack ps)
{ps->_pfood->next = ps->_psnack;ps->_psnack = ps->_pfood;free(pn);pn = NULL;pSnackNode cur = ps->_psnack;color(10);while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}color(7);ps->_sum_score += ps->_food_weight;//在重新生成食物CreateFood(ps);}void No_Food(pSnackNode pn, pSnack ps)
{pn->next = ps->_psnack;ps->_psnack = pn;pSnackNode cur = ps->_psnack;//打印出来五个了color(10);while (cur->next->next != NULL){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}color(7);//将第六个位置打印为空格//释放第六个SetPos(cur->next->x, cur->next->y);printf("  ");free(cur->next);//再将倒数第二个的next为NULLcur->next = NULL;
}void Kill_By_Wall(pSnack ps)
{if(ps->_psnack->x == 0 || ps->_psnack->x == 56 ||ps->_psnack->y == 0 || ps->_psnack->y == 26){ps->_status = KILL_BY_WALL;}
}void Kill_By_Self(pSnack ps)
{pSnackNode cur = ps->_psnack -> next;while (cur){if (cur->x == ps->_psnack->x && cur->y == ps->_psnack->y){ps->_status = KILL_BY_SELF;break;}cur = cur->next;}
}void SnackMove(pSnack ps)
{pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));if (pNextNode == NULL){perror("SnackMove::malloc fail");return;}switch (ps->_dir){case UP:pNextNode->x = ps->_psnack->x;pNextNode->y = ps->_psnack->y - 1;break;case DOWN:pNextNode->x = ps->_psnack->x;pNextNode->y = ps->_psnack->y + 1;break;case LEFT:pNextNode->x = ps->_psnack->x - 2;pNextNode->y = ps->_psnack->y;break;case RIGHT:pNextNode->x = ps->_psnack->x + 2;pNextNode->y = ps->_psnack->y;break;}//下一个位置是食物if (Next_Is_Food(pNextNode, ps)){Eat_Food(pNextNode,ps);}else{No_Food(pNextNode, ps);}//检测是否被撞墙死Kill_By_Wall(ps);//检测是否被撞自己死Kill_By_Self(ps);
}void GameRun(pSnack ps)
{PrintHelpInfo();//SetPos(64, 10);do {SetPos(64, 6);wprintf(L"当前的总分数为:");printf("%d ", ps->_sum_score);SetPos(64, 8);wprintf(L"当前单个食物分数为:");printf("%d ", ps->_food_weight);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_OK;}else if (KEY_PRESS(VK_F3)){//加速if (ps->_sleep_time > 80){ps->_sleep_time -= 30;ps->_food_weight += 2;}}else if (KEY_PRESS(VK_F4)){//减速if (ps->_food_weight > 2){ps->_sleep_time += 30;ps->_food_weight -= 2;}}//实现蛇的移动SnackMove(ps);Sleep(ps->_sleep_time);} while (ps->_status==OK);//移动//实施打印情况
}void GameEnd(pSnack ps)
{SetPos(24, 12);switch (ps->_status){case END_OK:wprintf(L"您主动结束游戏\n");break;case KILL_BY_WALL:wprintf(L"您撞到墙上,游戏结束\n");break;case KILL_BY_SELF:wprintf(L"您撞到了自己,游戏结束\n");break;}//释放蛇身的链表pSnackNode cur = ps->_psnack;while (cur){pSnackNode del = cur;cur = cur->next;free(del);}
}

 test.c

#define  _CRT_SECURE_NO_WARNINGS#include"snack.h"void test()
{char ch;do {//创建贪吃蛇Snack snack = { 0 };GameStart(&snack);//运行游戏GameRun(&snack);//结束游戏 - 善后工作GameEnd(&snack);SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar();while (getchar() != '\n');} while (ch == 'Y' || ch == 'y');SetPos(0, 28);}
int main()
{srand((unsigned int)time(NULL));setlocale(LC_ALL, "");test();return 0;
}

 snack.h

#define  _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<windows.h>
#include<stdbool.h>
#include<stdlib.h>
#include <locale.h>
#include<time.h>
#include<errno.h>
#include<assert.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_OK,
};typedef struct SnackNode
{int x;int y;//指向下一个结点struct SnackNode* next;
}SnackNode, * pSnackNode;typedef struct Snack
{//蛇的头pSnackNode _psnack;pSnackNode _pfood;enum DIRECTION _dir;enum GAME_STATUS _status;int _food_weight;//一个食物的分数int _sum_score;//总成绩int _sleep_time;//蛇的速度,越小越快
}Snack,*pSnack;//定位光标
void SetPos(int x, int y);//游戏开始
void GameStart(pSnack ps);//欢迎界面
void Welcome_game();//绘制地图
void CreatMap();//打印提示操作信息
void PrintHelpInfo();//创建蛇
void CreateSnack(pSnack ps);//创建食物
void CreateFood(pSnack ps);//游戏暂停
void Pause();//游戏正常运行
void GameRun(pSnack ps);//贪吃蛇的移动
void SnackMove(pSnack ps);//检查下一个坐标位置是否为食物
bool Next_Is_Food(pSnackNode pn,pSnack ps);//吃食物
void Eat_Food(pSnackNode pn, pSnack ps);//下一个位置不是食物,进行移动
void No_Food(pSnackNode pn, pSnack ps);//检测是否被撞墙死
void Kill_By_Wall(pSnack ps);//检测是否被撞自己死
void Kill_By_Self(pSnack ps);//正常的游戏结束
void GameEnd(pSnack ps);

 



控制台程序的准备:

需要运用到API

本游戏运行的时候需要用到控制台主机,而不是终端,对应的修改步骤如下:

控制台程序名字修改:

把名字改为贪吃蛇,会更好,那么修改方式如下:

 参考:mode命令(mode | Microsoft Learn)

system("title 贪吃蛇");

 

 

游戏框架构建:

首先定义游戏界面的大小,定义游戏区行数和列数。

平常我们运⾏起来的黑框程序其实就是控制台程序 我们可以使用cmd命令来设置控制台窗⼝的⻓宽:设置控制台窗⼝的大小,100行,30列

system("mode con cols=100 lines=30");

此外,我们还需要结构体用于表示蛇与食物的结点信息。

typedef struct SnackNode
{int x;int y;//指向下一个结点struct SnackNode* next;
}SnackNode, * pSnackNode;

此外还有存放游戏蛇的信息与各个游戏相关信息,也需要用结构体封装起来存放:

typedef struct Snack
{//蛇的头pSnackNode _psnack;pSnackNode _pfood;enum DIRECTION _dir;enum GAME_STATUS _status;int _food_weight;//一个食物的分数int _sum_score;//总成绩int _sleep_time;//蛇的速度,越小越快
}Snack,*pSnack;

同样也需要存放蛇的状态,比如正常,撞墙死亡,撞自己死亡。

//蛇的状态
enum GAME_STATUS
{OK,//正常KILL_BY_WALL,KILL_BY_SELF,END_OK,
};

同样蛇的运行方向也需要用一个枚举来存放:

为了增加可读性,我们使用一个数字来定义方向,如向上为1;

//蛇的方向
enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT,
};


控制台屏幕上的坐标COORD:

COORD是WindowsAPI中定义的⼀个结构体,表⽰⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系 (0,0)的原点位于缓冲区的顶部左侧单元格。

隐藏光标:

隐藏光标比较简单,是运用到WIN 32 API,先通过etConsoleCursorInfo(hOutput, &CursorInfo);获取控制台光标信息,再隐藏控制台光标,设置控制台光标状态;

void cursor_hide()
{HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标 SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态 
}

 光标跳转

光标跳转,也就是让光标跳转到获得标准输出设备的句柄,与隐藏光标的操作步骤类似,然后定位光标的位置,跳转到指定位置:

void SetPos(int x,int y)
{//获得标准输出设备的句柄HANDLE hOutput = NULL;hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//定位光标的位置,到posCOORD pos = { x,y };SetConsoleCursorPosition(hOutput, pos);
}

打印颜色设置:

 颜色设置函数的作用是,将此后输出的内容颜色都更为所指定的颜色,接收的参数c是颜色代码,十进制颜色代码表如下:

void color(int c)
{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //颜色设置//注:SetConsoleTextAttribute是一个API(应用程序编程接口)
}

初始化界面:

第一步就为打印地图:

需要注意的地方就是:
  1. 在cmd窗口中一个小方块占两个单位的横坐标,一个单位的纵坐标。我们的墙使用宽字符进行对应的填充,
  2. 光标跳转函数SetPos接收的是光标将要跳至位置的横纵坐标。
 例如第一次的坐标就为 (i,j) 那么下一次坐标就为(i+2,j);

 宽字符打印准备:

1:需要引头文件:

#include <locale.h>

2:修改当前地区

	setlocale(LC_ALL, "");

 3:对应的字符

#define Wall L'□'
#define Body L'●'
#define Food L'★'

我设置的墙的颜色为红色,可以根据自己喜欢,自己根据上面的图给出的颜色进行调整。 

void CreatMap()
{color(12);//上for (int i = 0; i < 29; i++){wprintf(L"%lc", L'□');}//下SetPos(0, 26);for (int i = 0; i < 29; i++){wprintf(L"%lc", L'□');} //左for (int i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%lc", L'□');}//右for (int i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%lc", L'□');}color(7);
}

初始化蛇与蛇的打印:

我默认开始蛇身加上蛇头一共五个结点大小:

最一开始蛇的坐标:

#define POS_X 24
#define POS_Y 5

我们的蛇是运用结构体,并运用的单链表来创造,那么我们打印只需要遍历就可以,还是比较简单的

初始化的代码如下:(蛇的颜色我设置的是绿色)

void CreateSnack(pSnack ps)
{color(10);//默认开始初始化为5个结点pSnackNode cur = NULL;for (int i = 0; i < 5; i++){cur =(pSnackNode)malloc(sizeof(SnackNode));cur->next = NULL;cur->x = POS_X + i * 2;cur->y = POS_Y;if (ps->_psnack == NULL)//第一次头插{ps->_psnack = cur;}else{cur->next = ps->_psnack;ps->_psnack = cur;}}while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}cur= ps->_psnack;//设置蛇的相关信息ps->_dir = RIGHT;ps->_food_weight = 10;ps->_sleep_time = 200;ps->_status = OK;color(7);
}

随机创建食物:

随机在游戏区生成食物,需要对生成后的坐标进行判断,只有该位置为空才能在此生成食物,否则需要重新生成坐标。食物坐标确定后,需要对游戏区该位置的状态进行标记。

食物我设置的是紫色。可以根据自己爱好,设置自己喜欢的颜色。

void CreateFood(pSnack ps)
{int x = 0;//2-54int y = 0;//1-25again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x%2!=0);//检测改坐标是否与蛇身重合 pSnackNode cur = ps->_psnack;while (cur){if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}pSnackNode SnackFood = (pSnackNode)malloc(sizeof(SnackNode));if (SnackFood == NULL){perror("CreateFood malloc fail");return;}color(13);SnackFood->x = x;SnackFood->y = y;SnackFood->next = NULL;SetPos(x, y);wprintf(L"%lc", Food);ps->_pfood = SnackFood;color(7);
}

蛇的单向移动:

移动蛇函数的作用就是先覆盖当前所显示的蛇,然后再打印移动后的蛇。

对应蛇尾的位置打印变为空格并删除一次蛇尾,然后再次创建一个新的蛇头,更换蛇头

void SnackMove(pSnack ps)
{pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));if (pNextNode == NULL){perror("SnackMove::malloc fail");return;}pNextNode->x = ps->_psnack->x + 2;pNextNode->y = ps->_psnack->y;pn->next = ps->_psnack;ps->_psnack = pn;pSnackNode cur = ps->_psnack;//打印出来五个了while (cur->next->next != NULL){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf("  ");
}


大致小部分已经实现完成,那么就利用游戏逻辑来实现剩余的代码;

在玩贪吃蛇的时候,我们知道

在蛇的移动过程,我们可以通过按键修改蛇的移动方向,来进行转弯,而且在移动的过程中,我们还可以随时改变速度,来改变游戏的难度,来增加游戏的可玩性,在行动的过程中,不免会撞墙,撞自己,吃到了食物,没有吃到食物,等等各种不同的情况,那么 对于实现的逻辑就是如上:

那么我先修改蛇的移动使其可以更换方向

在修改蛇的方向前,我们知道我们是通过按键来改变,那么我们就需要通过某种方法得知我们按了什么键来进行修改方向,同样也是API的知识

//检查某个按键是否被按了
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

添加方向的改变与判断蛇的各个状态判断:

bool Next_Is_Food(pSnackNode pn, pSnack ps)
{return (ps->_pfood->x == pn->x && ps->_pfood->y == pn->y);
}
void SnackMove(pSnack ps)
{pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));if (pNextNode == NULL){perror("SnackMove::malloc fail");return;}switch (ps->_dir){case UP:pNextNode->x = ps->_psnack->x;pNextNode->y = ps->_psnack->y - 1;break;case DOWN:pNextNode->x = ps->_psnack->x;pNextNode->y = ps->_psnack->y + 1;break;case LEFT:pNextNode->x = ps->_psnack->x - 2;pNextNode->y = ps->_psnack->y;break;case RIGHT:pNextNode->x = ps->_psnack->x + 2;pNextNode->y = ps->_psnack->y;break;}//下一个位置是食物if (Next_Is_Food(pNextNode, ps)){Eat_Food(pNextNode,ps);}else{No_Food(pNextNode, ps);}//检测是否被撞墙死Kill_By_Wall(ps);//检测是否被撞自己死Kill_By_Self(ps);
}

 对该函数里面各个小函数进行代码展示:

这里面的小函数都是比较好实现的,这里就不在解释:

Eat_Food(pNextNode,ps);

 需要注意的是吃完这个食物后,要记得重新随机创建食物

void Eat_Food(pSnackNode pn, pSnack ps)
{ps->_pfood->next = ps->_psnack;ps->_psnack = ps->_pfood;free(pn);pn = NULL;pSnackNode cur = ps->_psnack;color(10);while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}color(7);ps->_sum_score += ps->_food_weight;//在重新生成食物CreateFood(ps);
}

void No_Food(pSnackNode pn, pSnack ps)

 要记得把尾打印改为空格

void No_Food(pSnackNode pn, pSnack ps)
{pn->next = ps->_psnack;ps->_psnack = pn;pSnackNode cur = ps->_psnack;//打印出来五个了color(10);while (cur->next->next != NULL){SetPos(cur->x, cur->y);wprintf(L"%lc", Body);cur = cur->next;}color(7);//将第六个位置打印为空格//释放第六个SetPos(cur->next->x, cur->next->y);printf("  ");free(cur->next);//再将倒数第二个的next为NULLcur->next = NULL;
}

void Kill_By_Wall(pSnack ps)

void Kill_By_Wall(pSnack ps)
{if(ps->_psnack->x == 0 || ps->_psnack->x == 56 ||ps->_psnack->y == 0 || ps->_psnack->y == 26){ps->_status = KILL_BY_WALL;}
}

void Kill_By_Self(pSnack ps)

void Kill_By_Self(pSnack ps)
{pSnackNode cur = ps->_psnack -> next;while (cur){if (cur->x == ps->_psnack->x && cur->y == ps->_psnack->y){ps->_status = KILL_BY_SELF;break;}cur = cur->next;}
}

最后,还有对应的就是运行是代码的逻辑展示

void GameRun(pSnack ps)
{//SetPos(64, 10);do {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_OK;}else if (KEY_PRESS(VK_F3)){//加速if (ps->_sleep_time > 80){ps->_sleep_time -= 30;ps->_food_weight += 2;}}else if (KEY_PRESS(VK_F4)){//减速if (ps->_food_weight > 2){ps->_sleep_time += 30;ps->_food_weight -= 2;}}//实现蛇的移动SnackMove(ps);Sleep(ps->_sleep_time);} while (ps->_status==OK);//移动//实施打印情况
}

速度的控制(单位毫秒):

 

void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE)){break;}}
}

 最后的游戏收尾就是提示信息的打印:

void GameEnd(pSnack ps)
{SetPos(24, 12);switch (ps->_status){case END_OK:wprintf(L"您主动结束游戏\n");break;case KILL_BY_WALL:wprintf(L"您撞到墙上,游戏结束\n");break;case KILL_BY_SELF:wprintf(L"您撞到了自己,游戏结束\n");break;}//释放蛇身的链表pSnackNode cur = ps->_psnack;while (cur){pSnackNode del = cur;cur = cur->next;free(del);}
}


最后一步便是锦上添花了,就是打印提示信息:

 

void PrintHelpInfo()
{color(15);SetPos(64, 10);wprintf(L"不能穿墙,不能咬到自己");SetPos(64, 12);wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");SetPos(64, 14);wprintf(L"按F3加速,F4减速");SetPos(64, 16);wprintf(L"按ESC正常退出游戏,按空格暂停游戏");SetPos(64, 18);wprintf(L"能力有限公司提供支持");SetPos(0, 29);//	system("pause");color(7);
}

到这里就已经完成了,一共有三个页面:

 第一个是又是封面,第二个为提示信息,第三个是游戏运行界面

相关文章:

贪吃蛇(c实现)

目录 游戏说明&#xff1a; 第一个是又是封面&#xff0c;第二个为提示信息&#xff0c;第三个是游戏运行界面 游戏效果展示&#xff1a; 游戏代码展示&#xff1a; snack.c test.c snack.h 控制台程序的准备&#xff1a; 控制台程序名字修改&#xff1a; 参考&#xff1a…...

【论文阅读笔记】MapReduce: Simplified Data Processing on Large Clusters

文章目录 1 概念2 编程模型3 实现3.1 MapReduce执行流程3.2 master数据结构3.3 容错机制3.3.1 worker故障3.3.2 master故障3.3.3 出现故障时的语义 3.4 存储位置3.5 任务粒度3.6 备用任务 4 扩展技巧4.1 分区函数4.2 顺序保证4.3 Combiner函数4.4 输入和输出的类型4.5 副作用4.…...

LeetCode题练习与总结:二叉树的中序遍历--94

一、题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;roo…...

云计算十三课

centos安装 点击左上角文件 点击新建虚拟机 点击下一步 点击稍后安装操作系统&#xff0c;下一步 选择Linux&#xff08;l&#xff09;下一步 设置虚拟机名称 点击浏览选择安装位置 新建文件夹设置名称不能为中文&#xff0c;点击确定 点击下一步 设置磁盘大小点击下一步…...

[数据集][目标检测]电力场景安全帽检测数据集VOC+YOLO格式295张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;295 标注数量(xml文件个数)&#xff1a;295 标注数量(txt文件个数)&#xff1a;295 标注类别…...

AtCoder Beginner Contest 308 A题 New Scheme

A题&#xff1a;New Scheme 标签&#xff1a;模拟 题意&#xff1a;给定 8 8 8个数的序列&#xff0c;询问这些数是否满足以下条件&#xff1a; 在 100 100 100到 675 675 675之间且能被 25 25 25整除序列是单调非递减的 题解&#xff1a;按题意模拟判断就好了。 代码&#…...

C++编程与朱元墇的关系

学编程和英语没关系&#xff0c;我说这句话&#xff0c;没人会相信&#xff0c;也不会有人说我什么哗众取宠。 我说学编程和朱元墇有关系&#xff0c;一定有人说我放P&#xff0c;其实这个P也和朱元墇有关系&#xff0c; 和朱元墇有什么P关系啊。 真有这P事啊&#xff0c; 朱元…...

0060__设计模式

1. 简单工厂模式( Simple Factory Pattern ) — Graphic Design Patterns 工厂模式 | 菜鸟教程 【设计模式——学习笔记】23种设计模式——建造者模式Builder&#xff08;原理讲解应用场景介绍案例介绍Java代码实现&#xff09;-CSDN博客 设计模式—— 五&#xff1a;迪米特…...

【Linux 网络】网络编程套接字 -- 详解

⚪ 预备知识 1、理解源 IP 地址和目的 IP 地址 举例理解&#xff1a;&#xff08;唐僧西天取经&#xff09; 在 IP 数据包头部中 有两个 IP 地址&#xff0c; 分别叫做源 IP 地址 和目的 IP 地址。 如果我们的台式机或者笔记本没有 IP 地址就无法上网&#xff0c;而因为…...

编译OpenResty遇到找不到OpenSSL的解决办法

以OpenResty-1.19.9.1为例 编辑openresty-1.19.9.1/build/nginx-1.19.9/auto/lib/openssl/conf CORE_INCS"$CORE_INCS $OPENSSL/.openssl/include" CORE_DEPS"$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h" CORE_LIBS"$CORE_LIBS $OPENSSL/.…...

Amazon Bedrock 托管 Llama 3 8B70B

Amazon Bedrock 托管 Llama 3 8B&70B&#xff0c;先来体验&#xff1a;&#xff08;*实验环境账号有效期为1天&#xff0c;到期自动关停&#xff0c;请注意重要数据保护&#xff09; https://dev.amazoncloud.cn/experience/cloudlab?id65fd86c7ca2a0d291be26068&visi…...

海豚调度器早期版本如何新增worker分组

在DolphinScheduler 1.3.5版本中&#xff0c;Worker分组通常是在部署时通过配置文件进行定义的&#xff0c;而不是在用户界面上直接操作。以下是在DolphinScheduler中新增Worker分组的一般步骤&#xff1a; 修改配置文件&#xff1a; DolphinScheduler的Worker分组信息通常在/…...

Debian Linux 下给Nginx 1.26.0 编译增加Brotli算法支持

明月发现参考【给Nginx添加谷歌Brotli压缩算法支持】一文给出的方法&#xff0c;在Debian Linux 12.5下就一直编译失败&#xff0c;主要的错误是因为文件缺失&#xff0c;在专门又安装了apt-get install libbrotli-dev的依赖库后依然会因为文件缺失无法编译完成&#xff0c;就这…...

中国银行从业在线教育系统,如何搭建网课平台?

如今这个时代相信没多少人是没听过网课平台的&#xff0c;绝大多数人对网课平台的名气是如雷贯耳的。时代的发展&#xff0c;让人们学习的方式变得更加的方便与快捷。今天就来和大家说说网课平台搭建都有哪些方法?网课平台难搭建么? 网课平台搭建的方法&#xff0c;其实网课平…...

解决java.lang.IllegalArgumentException异常的正确方法

java.lang.IllegalArgumentException 是 Java 中的一个异常类&#xff0c;表示方法中传递的参数不合法。这个异常通常在方法被调用时抛出&#xff0c;表明方法的参数出现了问题。要正确解决这个异常&#xff0c;你可以按照以下步骤进行&#xff1a; 查看异常信息&#xff1a;首…...

齿轮滚刀刃口钝化技术简介

介绍 在滚刀的使用中发现&#xff0c;进口滚刀和国产滚刀在加工质量和寿命方面存在显著差异。经过多次比较得知&#xff0c;滚刀的使用寿命可以达到国产滚刀的两倍以上&#xff0c;而进口滚刀返回原厂磨削后的使用寿命约为新刀具的90% &#xff0c;但同样经过国内厂家磨削后&a…...

【ESP32接入ATK-MO1218 GPS模块】

【ESP32接入ATK-MO1218 GPS模块】 1. 引言2. ATK-MO1218 GPS模块概述3. 接入ATK-MO1218 GPS模块的步骤4. 示例代码5. 结论1. 引言 在现代的嵌入式系统和物联网项目中,精确的位置信息是至关重要的。ATK-MO1218 GPS模块作为一款高性能的GPS/北斗双模定位模块,为开发者提供了强…...

EDA设计学习笔记2:STM32F103C8T6最小系统板的仿绘

今日开始仿制练习一个STM32F103C8T6最小系统板&#xff0c;通过对这个最小系统板的仿制&#xff0c;达到对自己PCB设计的练习的目的&#xff0c;最终目标是自己设计出一块PCB&#xff0c;做一个OLED的桌面小摆件...... 也不知道画出来能不能用..... 目录 主控芯片的搜索与放置…...

实现树莓派DS18B20读取温度(OneWire)

简介 使用的是树莓派3B, Go编程实现OneWire方式读取DS18B20温度。 接线 DS18B20 包含经典三线&#xff0c; VCC和GND自不必说&#xff0c; 主要的是DQ线&#xff0c; 需要接4.7K的上拉电阻&#xff0c; 即4.7K欧姆的电阻接到DQ和VCC&#xff0c; 否则树莓派识别不到DS18B20&am…...

Android 蓝牙实战——蓝牙音乐播放/暂停状态(二十二)

对于蓝牙音乐的播放状态,我们首先主要处理的是 onPlayStatusChanged() 回调,这是协议栈通知 FW 层的一个回调接口。还有一个就是 getPlayBackState() 方法,这是媒体应用在初始化时未收到回调信息主动获取当前状态的方法。我们这里就来分析一下这两个状态的获取流程。 一、状…...

linux学习:视频输入+V4L2

目录 V4L2 视频采集流程 代码例子 核心命令字和结构体 VIDIOC_ENUM_FMT VIDIOC_G_FMT / VIDIOC_S_FMT / VIDIOC_TRY_FM VIDIOC_REQBUFS VIDIOC_QUERYBUF VIDIOC_QBUF /VIDIOC_DQBUF VIDIOC_STREAMON / VIDIOC_STREAMOFF V4L2 是 Linux 处理视频的最新标准代码模块&…...

[AutoSar]BSW_Diagnostic_004 ReadDataByIdentifier(0x22)的配置和实现

目录 关键词平台说明背景一、配置DcmDspDataInfos二、配置DcmDspDatas三、创建DcmDspDidInfos四、创建DcmDspDids五、总览六、创建一个ASWC七、mapping DCM port八、打开davinci developer&#xff0c;创建runnabl九、生成代码 关键词 嵌入式、C语言、autosar、OS、BSW、UDS、…...

C语言笔记13

字符数组与字符串常量区别 #include <stdio.h> int main() {char str1[] "hello bit.";char str2[] "hello bit.";char *str3 "hello bit.";char *str4 "hello bit.";if(str1 str2)printf("str1 and str2 are same\n…...

JavaScript进阶——04-创建对象和继承

创建对象的几种方式 通过Object <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>01_Object构造函数模式</title></head><body><!--方式一: Object构造函数模式* 套路: 先创建空Ob…...

队列(详解)

一.队列的概念 队列&#xff08;Queue&#xff09;是一种常见的数据结构&#xff0c;它按照先进先出的原则管理数据。这意味着最先进入队列的元素将被最先移出队列&#xff0c;类似于现实生活中排队的场景。 在队列中&#xff0c;数据项被添加到队列的一端&#xff0c;称为队尾…...

【原创】nnUnet V1在win11下的安装与配置

安装之前可以先了解一下论文的主要内容&#xff0c;便于之后网络训练与推理&#xff0c;调试程序。 论文地址&#xff1a;nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation | Nature Methods 也可以从其他博客快速浏览&#xff1a…...

C语言之指针初阶

目录 前言 一、内存与地址的关系 二、指针变量 三、野指针 四、const 五、传值调用与传址调用 总结 前言 本文主要介绍C语言指针的一些基础知识&#xff0c;为后面深入理解指针打下基础&#xff0c;因此本文内容主要包括内存与地址的关系&#xff0c;指针的基本语法&…...

异常检测的学习和实战

1.应用&#xff1a; 1.在工业上的应用 当检测设备是否处于异常工作状态时&#xff0c;可以由上图分析得到&#xff1a;那些零散的点对应的数据是异常数据。因为设备大多数时候都是处于正常工作状态的&#xff0c;所以数据点应该比较密集地集中在一个范围内&#xff0c;而那些明…...

RabbitMQ 面试题(一)

1. 简述为什么要使用 RabbitMQ ? 使用 RabbitMQ 的主要原因包括以下几点&#xff1a; 解耦&#xff1a;在复杂的系统中&#xff0c;不同的服务或组件之间往往需要通信和协作。RabbitMQ 作为消息队列&#xff0c;允许这些组件或服务通过发送和接收消息来交互&#xff0c;而无…...

org.postgresql.util.PSQLException: 错误: 关系 “dual“ 不存在

springboot 项目连接 postgreps&#xff0c;启动时报错 org.postgresql.util.PSQLException: 错误: 关系 "dual" 不存在。 查阅资料后发现这是由配置文件中的配置 datasource-dynamic-druid-validationQuery 导致的 spring:datasource:druid:stat-view-servlet:ena…...