C语言贪吃蛇实现,以及一些有趣的想法(可加速减速)
文章目录
- 每日一言
- 代码:
- Snake.h
- Snake.c
- test.c
- 可以增加游戏趣味性的想法
- ���语
每日一言
结局每隔一段时间就会到来,我经历它,就像飞机穿过云层。
()跟着课程敲了一下午,终于写好了~
用到了一些没用过的函数,总结介绍一下
()⭐首先是设置光标位置,它可以让我们指哪打哪,非常好用awa,以下是一个封装好的函数
//设置光标位置 void SetPos(int y, int x) { //获得设备句柄 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //根据句柄设置光标的位置 COORD pos = { x,y };//先行后列更符合习惯 SetConsoleCursorPosition(handle, pos); }
⭐接着是隐藏光标,光标总是一闪一闪的实在是有点烦(bushi
以下是让光标消失的魔法
//以下为隐藏光标代码 //控制台光标信息 CONSOLE_CURSOR_INFO cursor_info = { 0 }; //获得设备句柄 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleCursorInfo(handle, &cursor_info); //隐藏光标 cursor_info.bVisible = false; //将更改应用到对应的控制台 SetConsoleCursorInfo(handle, &cursor_info);
⭐接下来是修改命令框大小与设置命令框标题
//设置命令框大小 system("mode con cols=100 lines=50"); //设置命令框标题 system("title 贪吃蛇");
⭐然后是设置本地环境,让你可以打印出宽字符,需要包含#include
//设置本地环境,设置后支持宽字符的使用 setlocale(LC_ALL, "");
⭐还有最重要的如何检测一个键是否被按过,以下是一个被定义的宏,通过它来检查按键
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)) & 1 ? 1 : 0)
VK代表虚拟键值
以上只是这些函数的简单介绍,如果想详细了解的可以点击🌳虚拟键码
⭐接下来是要写完整个贪吃蛇用到的知识
- C语言(重要)
- 数据结构中的单链表(重要)
- WIN32 API (会用一点点就行)
代码:
Snake.h
#pragma once #include #include #include #include #include #include #include //检测一个键是否被按过 #define KEY_PRESS(VK) ((GetAsyncKeyState(VK)) & 1 ? 1 : 0) //方向 enum DIRECTION { UP = 1, DOWN, LEFT, RIGHT }; //游戏状态 enum GAME_STATUS { OK = 1, KILL_BY_WALL, KILL_BY_SELF, GAMEOVER }; //蛇身 typedef struct SnakeNode { int x; int y; struct SnakeNode* next; }SnakeNode, * pSnakeNode; //整条蛇 typedef struct Snake{ int Score;//分数 int FoodWight;//一个食物的分数 int SleepTime;//每走一步需要的时间 pSnakeNode pSnake;//维护整条蛇的指针 pSnakeNode pFood;//维护食物的指针 enum DIRECTION Dir;//方向 enum GAME_STATUS Status;//游戏状态 }Snake, * pSnake; //设置光标位置 void SetPos(int x, int y); //游戏开始前的准备工作 void GameStart(pSnake snake); //游戏运行时的维护工作 void GameRun(pSnake snake); //游戏结束时的维护工作 void GameEnd();
Snake.c
#include "Snake.h" //设置光标位置 void SetPos(int y, int x) { //获得设备句柄 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //根据句柄设置光标的位置 COORD pos = { x,y };//先行后列更符合习惯 SetConsoleCursorPosition(handle, pos); } //打印地图 void PrintMap() { int i = 0; //上 SetPos(0, 0); for (i = 0; i FoodWight = 10; snake->Dir = RIGHT; snake->Score = 0; snake->SleepTime = 200; snake->Status = OK; //创建蛇身(单链表) pSnakeNode cur = NULL; int i = 0; for (i = 0; i x = 5; cur->y = 24 + i * 2; //头插法 cur->next = NULL; if (snake->pSnake == NULL) { snake->pSnake = cur; } else { cur->next = snake->pSnake; snake->pSnake = cur; } } //打印蛇的身体 cur = snake->pSnake; while (cur) { SetPos(cur->x, cur->y); wprintf(L"●"); cur = cur->next; } } //创建食物 void CreateFood(pSnake snake) { int x = 0; int y = 1; roll: //生成食物坐标 //列应为2的倍数 while (y % 2 != 0) { x = rand() % 25 + 1; y = rand() % 53 + 2; } //食物不能生成在蛇身上 pSnakeNode cur = snake->pSnake; while (cur) { //如果与蛇身重复,则重新生成食物坐标 if (cur->x == x && cur->y == y) { goto roll; } cur = cur->next; } //创建食物 pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode)); if (!pFood) { perror("CreateFood() pFood malloc fail"); return; } else { //设置食物坐标 pFood->x = x; pFood->y = y; //printf("x = %d y = %d", x, y); //打印食物 SetPos(pFood->x, pFood->y); wprintf(L"☆"); //将食物信息给到游戏 snake->pFood = pFood; } //SetPos(27, 0); } //游戏开始前的准备工作 void GameStart(pSnake snake) { //以下为隐藏光标代码 //控制台光标信息 CONSOLE_CURSOR_INFO cursor_info = { 0 }; //获得设备句柄 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleCursorInfo(handle, &cursor_info); //隐藏光标 cursor_info.bVisible = false; //将更改应用到对应的控制台 SetConsoleCursorInfo(handle, &cursor_info); //设置命令框大小 system("mode con cols=100 lines=30"); //设置命令框题目 system("title 贪吃蛇"); //游戏介绍 WelcomeToGame(); //打印地图 PrintMap(snake); //初始化蛇 InitSnake(snake); //创建食物 CreateFood(snake); } //打印游戏说明 void PrintHelpInfo() { SetPos(15, 64); printf("不能碰墙,不能咬到自己"); SetPos(16, 64); printf("用↑.↓.←.→ 分别控制蛇的移动"); SetPos(17, 64); printf("F3为加速,F4为减速"); SetPos(18, 64); printf("ESC :退出游戏.space:暂停游戏."); } //判断下一个位置是不是食物 bool IsFood(pSnake snake, pSnakeNode pNextNode) { if (snake->pFood->x == pNextNode->x && snake->pFood->y == pNextNode->y) { return true; } return false; } //吃食物 void EatFood(pSnake snake,pSnakeNode pNextNode) { //头插 pNextNode->next = snake->pSnake; snake->pSnake = pNextNode; //打印蛇 pSnakeNode cur = snake->pSnake; while (cur) { SetPos(cur->x, cur->y); wprintf(L"●"); cur = cur->next; } //加分数 snake->Score += snake->FoodWight; //释放掉食物节点占用的内存 free(snake->pFood); snake->pFood = NULL; //创建一个新的食物 CreateFood(snake); } //下个位置不是食物 void NotEatFood(pSnake snake, pSnakeNode pNextNode) { //头插 pNextNode->next = snake->pSnake; snake->pSnake = pNextNode; //找到尾节点的前一个节点,顺便打印蛇身 pSnakeNode cur = snake->pSnake; while (cur->next->next != NULL) { SetPos(cur->x, cur->y); wprintf(L"●"); cur = cur->next; } //在蛇尾打印空格 SetPos(cur->next->x, cur->next->y); printf(" "); //释放尾节点 free(cur->next); cur->next = NULL; } void SnakeMove(pSnake snake) { //创建下一个节点 pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode)); if (!pNextNode) { perror("SnakeMove() pNextNode malloc fail"); return; } //确定下一个节点的位置 switch (snake->Dir) { case UP: { pNextNode->x = snake->pSnake->x - 1; pNextNode->y = snake->pSnake->y; break; } case DOWN: { pNextNode->x = snake->pSnake->x + 1; pNextNode->y = snake->pSnake->y; break; } case LEFT: { pNextNode->x = snake->pSnake->x; pNextNode->y = snake->pSnake->y - 2; break; } case RIGHT: { pNextNode->x = snake->pSnake->x; pNextNode->y = snake->pSnake->y + 2; break; } } //判断下一个节点是不是食物 if (IsFood(snake,pNextNode)) { //吃食物 EatFood(snake, pNextNode); } else { //不是食物就正常走 NotEatFood(snake, pNextNode); } //判断是否撞墙 if (snake->pSnake->x == 26 || snake->pSnake->x == 0 || snake->pSnake->y == 0 || snake->pSnake->y == 56) { snake->Status = KILL_BY_WALL; return; } //判断是否撞到自己 pSnakeNode cur = snake->pSnake->next; while (cur) { if (pNextNode->x == cur->x && pNextNode->y == cur->y) { snake->Status = KILL_BY_SELF; return; } cur = cur->next; } } void pause() { while (1) { Sleep(300); //按空格退出暂停 if (KEY_PRESS(VK_SPACE)) { break; } } } void GameRun(pSnake snake) { //打印游戏说明 PrintHelpInfo(); //蛇的移动 do { //打印得分与食物分值 SetPos(10, 64); printf("得分: %5d ", snake->Score); printf("每个食物分值:%2d分", snake->FoodWight); //判断玩家是否要改变蛇的方向 //按上不能往下 if (KEY_PRESS(VK_UP) && snake->Dir != DOWN) { snake->Dir = UP; } else if (KEY_PRESS(VK_DOWN) && snake->Dir != UP) { snake->Dir = DOWN; } else if (KEY_PRESS(VK_LEFT) && snake->Dir != RIGHT) { snake->Dir = LEFT; } else if (KEY_PRESS(VK_RIGHT) && snake->Dir != LEFT) { snake->Dir = RIGHT; } else if (KEY_PRESS(VK_SPACE)) { //暂停 pause(); } else if (KEY_PRESS(VK_F3)) { //加速 if (snake->SleepTime >= 50) { snake->SleepTime -= 30; snake->FoodWight += 2; } } else if (KEY_PRESS(VK_F4)) { //减速 if (snake->SleepTime snake-SleepTime += 30; snake->FoodWight -= 2; } } else if (KEY_PRESS(VK_ESCAPE)) { snake->Status = GAMEOVER; return; } //休眠一下 Sleep(snake->SleepTime); //蛇走一步 SnakeMove(snake); } while (snake->Status == OK); } //游戏结束时的维护工作 void GameEnd(pSnake snake) { //判断玩家是怎么输的 if (snake->Status == KILL_BY_SELF) { SetPos(10, 18); printf("很可惜,你咬到自己了"); } else if (snake->Status == KILL_BY_WALL) { SetPos(10, 18); printf("很可惜,你被墙撞死了"); } else if (snake->Status == GAMEOVER) { SetPos(10, 18); printf("你选择了退出游戏"); } //释放蛇身的节点 pSnakeNode cur = snake->pSnake; while (cur) { pSnakeNode del = cur; cur = cur->next; free(del); } }
test.c
#include "Snake.h" //int main() { // //设置命令框大小 // system("mode con cols=100 lines=50"); // //设置命令框标题 // system("title 贪吃蛇"); // // //COORD pos = { 40,10 }; // // //控制台光标信息 结构体 // CONSOLE_CURSOR_INFO cursor_info = { 0 }; // // //获得设备句柄 // HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // // GetConsoleCursorInfo(handle, &cursor_info); // // //设置光标大小 // //cursor_info.dwSize = 50; // // //隐藏光标 // cursor_info.bVisible = false; // // //设置控制台 // SetConsoleCursorInfo(handle, &cursor_info); // // //根据句柄设置光标的位置 // COORD pos = { 20,5 }; // SetConsoleCursorPosition(handle, pos); // // // printf("12345"); // // // getchar(); // return 0; //} //int main() { // //设置本地环境,设置后支持宽字符的使用 // setlocale(LC_ALL, ""); // int i = 0; // for (i = 0; i
可以增加游戏趣味性的想法
- 在场上随机投放道具,吃到了可以获得2次穿墙机会(传送门)
- 在场上随机投放道具,吃到了令玩家的按键功能相反(按上蛇往下走)
- 可以吃道具,扩大地图,或者随着蛇的增大地图随之变大
- 给贪吃蛇染上新颜色
- 可以增加贪吃蛇选皮肤界面
- 可以吃道具,吃到后蛇分成两半,一边用wasd键操控,一边用上下左右键操控(该道具整局只在一条蛇时概率出现)
- 增加音效
结语
请给自己些耐心,一口吃不成胖子。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!
都看到这里啦!真棒(*^▽^*)
可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家
编程小白写作,如有纰漏或错误,欢迎指正
The End