贪吃蛇小游戏的实现代码

一. 头文件

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>
#define Pos_x 24
#define Pos_y 5
#define WALL L'□'#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)//判断按键是按过还是没按过
//蛇的方向
enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
};//蛇的状态
//正常,撞墙,撞到自己,正常退出
enum STATUS
{OK,//正常,继续游戏KILL_BY_WALL,//撞墙KILL_BY_SELF,//撞到自己END_NORMAL//正常退出
};//蛇身的节点类型
typedef struct SnakeNode
{//坐标int x;int y;//指向下一个节点的指针struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//贪吃蛇
typedef struct Snake
{pSnakeNode _pSnake;//指向蛇头的指针pSnakeNode _pFood;//指向食物节点的指针enum DIRECTION _dir;//蛇的方向enum STATUS _status;//游戏的状态int _food_weight;//一个食物的分数int _score;//总成绩int _sleep_time;//休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;//函数的声明//定位光标位置void SetPos(short x, short y);//游戏的初始化
void GameStart(pSnake snake);//欢迎界面的打印
void Welcome();//创建地图
void CreateMap();//初始化蛇身
void InitSnake(pSnake ps);//创建食物
void CreateFood(pSnake ps);//打印帮助信息
void PrintHelpInfo();//查看节点是否是食物
int JubgeNextIsFood(pSnakeNode pn, pSnake ps);//游戏运行时的逻辑
void GameRun(pSnake ps);//游戏结束的处理
void GameEnd(pSnake ps);//检测蛇是否撞到墙
void KillWall(pSnake ps);//检测蛇是否撞到自己
void KillSelf(pSnake ps);

二. 实现蛇功能

#include"snake.h"
void SetPos(short x, short y)
{//获得标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定位光标的位置COORD pos = { x,y };SetConsoleCursorPosition(houtput, pos);//设置指定控制台屏幕缓冲区中光标的位置//参数:1. 控制台屏幕缓冲区的句柄//2. 指定新光标的位置的 COORD结构
}
int JubgeNextIsFood(pSnakeNode pn, pSnake ps)//判断下个节点是否是食物
{if (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y)return 1;elsereturn 0;
}
void EatFood(pSnakeNode pn, pSnake ps)
{//头插法ps->_pFood->next = ps->_pSnake;//将食物的下一个变为头ps->_pSnake = ps->_pFood;//将食物定义为头free(pn);//不需要pn记录头的位置了,就销毁pn = NULL;//打印蛇身pSnakeNode cur = ps->_pSnake;SetPos(cur->x, cur->y);wprintf(L"%lc", L'◆');cur = cur->next;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", L'●');cur = cur->next;}ps->_score += ps->_food_weight;//重新创建食物CreateFood(ps);//因为从thc.h里已经声明了,所以不用再上面声明
}
void NoFood(pSnakeNode pn, pSnake ps)
{pn->next = ps->_pSnake;//下一步的位置之后链接上头结点ps->_pSnake = pn;//将头变为下一步的位置pSnakeNode cur = pn->next, qrev = pn;while (cur->next){cur = cur->next;qrev = qrev->next;}SetPos(cur->x, cur->y);printf("  ");free(cur);cur = NULL;qrev->next = NULL;//打印蛇身cur = ps->_pSnake;SetPos(cur->x, cur->y);wprintf(L"%lc", L'◆');cur = cur->next;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", L'●');cur = cur->next;}
}
void Pause()//暂停函数
{while (1)//无限暂停直到再按一次空格键{ Sleep(200);if (KEY_PRESS(VK_SPACE)){break;}}
}
void KillWall(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 KillSelf(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;break;}cur = cur->next;}
}void Welcome()
{SetPos(40, 14);wprintf(L"欢迎来到贪吃蛇小游戏\n");SetPos(42, 20);system("pause");//暂停system("cls");//清空屏幕SetPos(25, 14);wprintf(L"用↑↓←→来操控蛇的移动方向,按F3加速,按F4减速\n");SetPos(25, 15);wprintf(L"加速能得到更高的分数\n");SetPos(42, 20);system("pause");system("cls");
}//蛇的移动
void SnakeMove(pSnake ps)
{SnakeNode* pNextNode = (SnakeNode*)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SnakeMove()::malloc()");return;}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 RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;}if (JubgeNextIsFood(pNextNode, ps))//检测下一个坐标是否是食物{EatFood(pNextNode, ps);//第一个参数记录头的位置,要在函数里销毁}else{NoFood(pNextNode, ps);}//撞墙死亡KillWall(ps); //撞到自己死亡KillSelf(ps);
}void CreateMap()//创造墙
{//上for (int i = 0; i < 29; i++)wprintf(L"%lc", WALL);//下SetPos(0, 26);for (int i = 0; i < 29; i++)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);}//getchar();
}void InitSnake(pSnake ps)//初始化蛇
{int i = 0;pSnakeNode cur = NULL;for (int i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake()::malloc()");return;}cur->next = NULL;cur->x = Pos_x + 2 * i;cur->y = Pos_y;//头插法插入链表if (ps->_pSnake == NULL)//空链表{ps->_pSnake = cur;}else //非空{cur->next = ps->_pSnake;ps->_pSnake = cur;}}cur = ps->_pSnake;SetPos(cur->x, cur->y);wprintf(L"%lc", L'◆');cur = cur->next;int tmp = 0;while (cur){tmp++;SetPos(cur->x, cur->y);wprintf(L"%lc", L'●');cur = cur->next;}//printf("%d", tmp);//设置贪吃蛇的属性ps->_dir = RIGHT;//默认向右ps->_score = 0;//总成绩初始为0ps->_food_weight = 10;//食物的奖励分数ps->_sleep_time = 200;//蛇多久动一次,单位是毫秒ps->_status = OK;//蛇的状态是正常的
}void CreateFood(pSnake ps)//随机生成食物
{int x = 0;int y = 0;//生成x是2的倍数//x: 2至54//y: 1至25
again:do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);//x和y的坐标不能和蛇的身体坐标冲突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;pfood->next = NULL;SetPos(x, y);//定位食物位置wprintf(L"%lc", L'★');ps->_pFood = pfood;}void PrintHelpInfo()
{SetPos(64, 10);wprintf(L"%ls", L"不能穿墙,不能咬到自己");SetPos(64, 11);wprintf(L"%ls", L"用↑↓←→来控制蛇");SetPos(64, 12);wprintf(L"%ls", L"按F5加速,F6减速");SetPos(64, 13);wprintf(L"%ls", L"按ESC退出游戏,空格暂停游戏");
}
void GameRun(pSnake ps)
{//打印帮助信息PrintHelpInfo();do{//打印总分数和食物的分值SetPos(64, 10);printf("总分数:%d\n", ps->_score);//总分数SetPos(64, 11);printf("当前食物的分值:%2d\n", ps->_food_weight);//食物的分值,%2d防止分数减少后面的0不去除//蛇只能向当前方向的左右转向,不能朝后转向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_NORMAL;//游戏状态设置为退出}else if (KEY_PRESS(VK_F5))//加速{if (ps->_sleep_time > 80){ps->_sleep_time -= 30;ps->_food_weight += 2;//速度增加食物分数增加}}else if (KEY_PRESS(VK_F6))//减速{if (ps->_sleep_time < 320){ps->_sleep_time += 30;ps->_food_weight -= 2;}}SnakeMove(ps);//蛇的移动Sleep(ps->_sleep_time);} while (ps->_status == OK);}
void GameEnd(pSnake ps)
{SetPos(60, 5);switch (ps->_status){case END_NORMAL:printf("主动退出游戏\n");break;case KILL_BY_WALL:printf("撞到墙啦o(╥﹏╥)o\n");break;case KILL_BY_SELF:printf("撞到自己啦┭┮﹏┭┮\n");break;}//释放蛇身的链表pSnakeNode cur = ps->_pSnake;while (cur){pSnakeNode tmp = cur;cur = cur->next;free(tmp);tmp = NULL;}}void GameStart(pSnake ps)
{//0. 设置窗口大小,隐藏光标system("mode con cols=100 lines=30");system("title 贪吃蛇");HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//隐藏光标操作 CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标状态CursorInfo.bVisible = false;//隐藏控制台光标SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态//1. 打印环境界面Welcome();//2. 绘制地图 CreateMap();//3. 创建蛇InitSnake(ps);//4. 创建食物CreateFood(ps);
}

三. 测试游戏文件

#include"snake.h"//完成游戏测试逻辑
void test()
{int f = 1;srand((unsigned int)time(NULL));do{system("cls");//创建贪吃蛇Snake  snake = { 0 };//初始化游戏GameStart(&snake);//玩游戏GameRun(&snake);//结束游戏GameEnd(&snake);system("cls");SetPos(35, 14);printf("是否再来一局(Y/N):");while(1){if (KEY_PRESS(78)){f = 0;break;}if (KEY_PRESS(89)){break;}}} while (f);SetPos(0, 27);//结束游戏的文字打印到下方
}int main()
{setlocale(LC_ALL, "");test();return 0;
}

我好水............

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

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

相关文章

新手必学:TikTok视频标签的使用方法

想让你的TikTok视频火起来&#xff0c;就得用对标签。标签能帮你的作品被更多人看到&#xff0c;也更有利于推广&#xff0c;可以为品牌增加曝光度、吸引更多观众、提高转化率和借势热门话题。那么应该如何选择标签并使用标签呢&#xff0c;看完这篇分享你或许会有所启发&#…

C# 快速排序算法的详细讲解

目录 一、前言 二、例子 三、快速排序算法图片讲解 四、快速排序算法代码 五、纯净代码 一、前言 用比较好懂的方式讲一下快速排序算法。 二、例子 如果我有一堆钱&#xff0c;想数清楚&#xff0c;最快的方案是什么&#xff1f; 图1 一堆钱 答&#xff1a;先分类&…

【C语言】bool 关键字

在C语言中&#xff0c;bool类型用于表示布尔值&#xff0c;即真或假。C语言本身在标准库中并未提供布尔类型&#xff0c;直到C99标准引入了stdbool.h头文件。该头文件定义了bool类型&#xff0c;以及两个常量&#xff1a;true和false。在此之前&#xff0c;通常使用整数来表示布…

保证 Kafka 数据可靠性最佳实践总结

文章目录 前言可靠性保证复制broker配置复制系数不彻底的首领选举最少同步副本保持副本同步持久化到磁盘 在可靠的系统中使用生产者发送确认配置生产者的重试参数 在可靠的系统中使用消费者消费者的可靠性配置手动提交偏移量 前言 可靠性是系统而不是某个独立组件的一个属性&a…

PHP花涧订购系统-计算机毕业设计源码00332

摘 要 近年来&#xff0c;电子商务的快速发展引起了行业和学术界的高度关注。花涧订购系统旨在为用户提供一个简单、高效、便捷的花卉购物体验&#xff0c;它不仅要求用户清晰地查看所需信息&#xff0c;而且还要求界面设计精美&#xff0c;使得功能与页面完美融合&#xff0c;…

告别烦人的捆绑软件!一键获取真正纯净系统!

很多用户反映自己下载到的纯净版系统&#xff0c;总是携带着各种各样的捆绑软件&#xff0c;特别影响自己的操作体验感&#xff0c;想知道哪里才有真正纯净的操作系统&#xff1f;以下系统之家小编给大家分享做到真正纯净的电脑操作系统。这些系统经过优化&#xff0c;去除乱七…

CSS 背景效果

目录 一、CSS背景属性 二、准备工作 三、background-color 四、background-image 五、background-repeat 六、background-position 七、background-size 八、background-attachment 九、background-clip 十、background-origin 十一、background 一、CSS背景属性 在…

零障碍入门:SSH免密登录与Hadoop生态系统的完美搭档【实训Day02】

一、 SSH免密登录配置 1 生成公钥和秘钥(在hadoop101上) # su star # cd /home/star/.ssh # ssh-keygen -t rsa 2 公钥和私钥 公钥id_rsa.pub 私钥id_rsa 3 将公钥拷贝到目标机器上(在hadoop101上) # ssh-copy-id hadoop101 # ssh-copy-id hadoop102 # ssh-co…

保存huggingface缓存中AI模型(从本地加载AI模型数据)

在github下拉项目后,首次运行时会下拉一堆模型数据&#xff0c;默认是保存在缓存的&#xff0c;如果你的系统盘空间快满的时候就会被系统清理掉&#xff0c;每次运行又重新下拉一次&#xff0c;特别麻烦。 默认下载的缓存路径如下&#xff1a;C:\Users\用户名\.cache\huggingf…

数据库管理系统中的磁盘、文件、页和记录管理

1. 引言 数据库管理系统&#xff08;DBMS&#xff09;是一个复杂的软件系统&#xff0c;用于管理和操作数据库中的数据。DBMS需要有效地在磁盘和内存之间组织和管理数据&#xff0c;以确保高效的数据存储和检索。本文将详细介绍DBMS中关于磁盘、文件、页和记录的管理&#xff…

GD32实战项目-app inventor-BLE低功耗DX-BT24蓝牙上位机制作-文末有关于生成的软件闪退或者卡死问题的解决

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 后续项目主要在下面该专栏中发布&#xff1a; 手把手教你嵌入式国产化_不及你的温柔的博客-CSDN博客 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转&#xff1a; 手把手教你嵌入式国产化-实战项目-无刷电机驱动&am…

zabbix 配置企业微信告警

1、申请一个企业微信&#xff0c; 官网链接 2、群内申请一个机器人 下载电脑版企业微信&#xff0c;登录后&#xff0c;在要接收群消息的群里&#xff0c;点击右上角三个点&#xff0c;添加机器人后&#xff0c;保存机器人的webhook地址 上传应用logo&#xff0c;填写应用名称…

Java 重载和重写

Java 重载和重写 重写重载定义指子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法&#xff0c;并且子类方法的实现覆盖了父类方法的实现。 参数列表和方法名必须相同&#xff0c;即外壳不变&#xff0c;核心重写指在一个类里面&#xff0c;方法名字相同&#x…

论文学习——基于区域多向信息融合的动态多目标优化引导预测策略

论文题目&#xff1a;Guided prediction strategy based on regional multi-directional information fusion for dynamic multi-objective optimization 基于区域多向信息融合的动态多目标优化引导预测策略&#xff08;Jinyu Feng a, Debao Chen b,c,d,∗, Feng Zou b,c, Fan…

微机原理 程序设计题

数字0~9、A~Z、a~z DATA SEGMENTINFOR1 DB 0AH, 0DH, "Please Press Any Key to input a letter :$"INFOR2 DB 0AH, 0DH, "You Input a Lowercase Letter! $"INFOR3 DB 0AH, 0DH, "You Input a Uppercase Letter! $"INFOR4 DB 0AH, 0DH, "…

100个名人的家,娄艺潇的家:大美国色,浪漫栖居

冠珠瓷砖「100个名人的家」&#xff0c;大美筑家&#xff0c;中国冠珠2024大美筑家之旅&#xff0c;冠珠瓷砖「100个名人的家」&#xff0c;探索中国人的烟火浪漫与美学追求。从中国家文化、人文居所、人生底蕴层面&#xff0c;发掘大美人居的故事&#xff0c;以中国瓷砖、空间…

git 撤销上一次提交

当在你的开发分支开发中&#xff0c;如果当前页面的修改还不确定但是提交了&#xff0c;且上一个提交的修改要合并到主干分支&#xff0c;此时需要撤销当前提交。 先撤销当前的提交&#xff0c;撤销回暂存区&#xff0c;然后保存备份一下.... git reset --soft HEAD^ 这样刚…

ll命令在ubuntu下不能使用的解决方案

ll命令在ubuntu下不能使用的解决方案 问题&#xff1a; ll命令在ubuntu下不能使用&#xff0c; 在Ubuntu终端里执行ll,提示:command not found 解决方案&#xff1a; 打开当前用户目录下的.bashrc文件 找到下面的内容&#xff0c;将前面的“#”去掉 #alias llls -alF 然…

《vue3》reactivity API(vue3的$set呢?)

在Vue2中&#xff0c;修改某一些数据&#xff0c;视图是不能及时重新渲染的。 比如数组 <div> {{ myHobbies }} </div>data: () > ({myHobbies: [篮球, 羽毛球, 桌球] }); mounted () {this.myHobbies[1] sing; // 视图层并没有改变 }因此&#xff0c;Vue2就提…

代码随想录算法训练营第四十三天| 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、 123.买卖股票的最佳时机III

121. 买卖股票的最佳时机 题目链接&#xff1a;121. 买卖股票的最佳时机 文档讲解&#xff1a;代码随想录 状态&#xff1a;做出来了 贪心思路&#xff1a; 因为股票就买卖一次&#xff0c;那么贪心的想法很自然就是取最左最小值&#xff0c;取最右最大值&#xff0c;那么得到的…