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

C语言贪吃蛇(有详细注释)

这个贪吃蛇是在比特特训营里学到的,同时我还写了用EasyX图形库实现的图形化贪吃蛇,含有每个函数的实现以及游戏中各种细节的讲解,感兴趣的可以去看一看。
贪吃蛇小游戏

实现效果
在这里插入图片描述

以下就是源码,感兴趣的小伙伴可以cv自己玩一玩改造改造,每个函数都有相应功能细节的注释,有用的话欢迎大家点赞
snake.h

#pragma once
#include <locale.h>
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.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=1,END_NOMAL,//正常退出KILL_BY_WALL,KILL_BY_SELF
};
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
//相当于
//typedef struct SnakeNode* pSnakeNode;//结构体指针的重命名//描述蛇的结构体
typedef struct snake
{pSnakeNode _psnake;//指向贪吃蛇头结点的指针。pSnakeNode _fFood;//假设食物也是蛇节点的指针,吃掉时改变其状态即可。int _Score;//分数,到时候要打印int _Foodweight;int SleepTime;//每走一步休息的时间,时间越短,速度越快enum DIRECTION _Dir;//方向,用枚举常量给出enum GAME_STATUS _status;
}Snake,*psnake;//游戏开始
void GameStart(psnake);
//欢迎界面
WecomeGame();//打印游戏界面
//创建地图
void CreatMap();
void InitSnake(psnake ps);
void CreateFood(psnake ps);//游戏的正常运行
void GameRun(psnake ps);
//打印帮助信息
void SetPos(short x, short y);int KillBySelf(psnake ps);void GameOver(psnake ps);

===============================
snake.c

#define _CRT_SECURE_NO_WARNINGS
#include "snake.h"
//设置光标位置
void SetPos(short x, short y)
{COORD pos = { x,y };HANDLE hOutput = NULL;//获取标准输出的句柄hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}
WecomeGame()//打印游戏界面
{//定位光标,打印欢迎语句SetPos(40,15);printf("欢迎来到贪吃蛇游戏");SetPos(37, 27);//printf("按任意键继续");system("pause");//暂停程序,库函数的暂停命令//清空屏幕system("cls");SetPos(20, 15);printf("上下左右为↑↓←→,F3为加速,F4为减速  ");system("pause");//暂停程序,库函数的暂停命令system("cls");CreatMap();
}
void CreatMap()
{int i = 0;//通过创建的终端大小打印地图SetPos(0, 0);for (i = 0; i <= 56; i+=2){wprintf(L"%c",wall);}SetPos(0, 26);for (i = 0; i <= 56; i += 2){wprintf(L"%c", wall);}for (i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%c", wall);	}for (i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%c", wall);}
}void GameStart(psnake ps)
{//初始化控制台窗体及初始化信息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;//将状态设置为fasle,隐藏SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态//打印欢迎界面,提示WecomeGame();//打印游戏界面//初始化贪吃蛇InitSnake(ps);//创建食物CreateFood(ps);
}
void CreateFood(psnake ps)//创建食物
{//坐标范围内随机生成,且不可以生成在蛇身上。int x = 0;int y = 0;again:do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);//横坐标为2的倍数,因为宽字符的原因//坐标不可以和蛇的节点坐标冲突pSnakeNode cur = ps->_psnake;while (cur){//比较坐标if (cur->x == x && cur->y == y){goto again;//也可以利用循环解决}cur = cur->next;}pSnakeNode pfood = (pSnakeNode)malloc(sizeof(SnakeNode));if (pfood == NULL){perror("malloc fail");return;}pfood->x = x;pfood->y = y;ps->_fFood = pfood;//打印食物SetPos(x, y);wprintf(L"%lc", food);//getchar();随时阻塞,判断效果
}
void InitSnake(psnake ps)//初始化蛇
{int i = 0;for (i = 0; i < 5; i++){pSnakeNode snk = (pSnakeNode)malloc(sizeof(SnakeNode));if (snk == NULL)//问题检查{perror("malloc fail");return;}snk->x = POS_X + 2*i;//节点位置不同snk->y = POS_Y;snk->next = NULL;if (ps->_psnake == NULL){ps->_psnake = snk;}else//此时_psnake修饰的就是蛇节点的头结点{snk->next = ps->_psnake;ps->_psnake = snk;}}//打印蛇的身体pSnakeNode cur = ps->_psnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"% c", body);cur = cur->next;}//蛇的相关数据ps->_status = OK;ps->_Score = 0;ps->_Foodweight = 10;ps->_fFood = NULL;ps->SleepTime = 200;//休眠时间关乎蛇移动的速度ps->_Dir = RIGHT;
}
void PrintInform()
{SetPos(60, 15);printf("1:不能穿墙,不能咬到自己");SetPos(60, 17);printf("2:上下左右为↑↓←→,F3为加速,F4为减速");SetPos(60, 19);printf("3:F3加速,F4减速,Esc退出,空格暂停");//getchar();
}void Pause()//暂停游戏或者继续游戏
{while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}}
}//判断是否吃掉食物
int NextIsFood(psnake ps,pSnakeNode pnext)
{if (ps->_fFood->x == pnext->x && ps->_fFood->y == pnext->y){return 1;}else{return 0;}
}void EatFood(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;}//清理食物节点(食物节点是malloc出来的,所以要清理,不然会造成内存浪费),加分free(ps->_fFood);ps->_Score += ps->_Foodweight;//继续创建食物CreateFood(ps);
}void NotEatFood(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;
}//蛇是否撞墙
int 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;return 1;}return 0;
}//是否吃到自己
int KillBySelf(psnake ps)
{pSnakeNode cur = ps->_psnake->next;while (cur){if (ps->_psnake->x == cur->x && ps->_psnake->y == cur->y){ps->_status = KILL_BY_SELF;//改变状态return 1;}cur = cur->next;}return 0;
}//值得学习的地方,修改整个数组
void SnakeMove(psnake ps)
{pSnakeNode pnext = (pSnakeNode)malloc(sizeof(SnakeNode));if (pnext == NULL){perror("malloc fail");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 RIGHT:pnext->x = ps->_psnake->x+2;//减2,因为宽度为2.pnext->y = ps->_psnake->y;break;case LEFT:pnext->x = ps->_psnake->x-2;pnext->y = ps->_psnake->y;break;}//判断是否吃掉食物,如果吃掉食物,最后一个节点不清理,如果没有吃掉食物,就将其清理、//蛇头坐标和食物坐标if (NextIsFood(ps, pnext)){//吃掉食物EatFood(ps,pnext);}else{//没吃食物NotEatFood(ps,pnext);}//蛇是否撞墙KillByWall(ps);//是否吃到自己KillBySelf(ps);
}void GameRun(psnake ps)
{PrintInform();do{SetPos(64, 10);printf("得分:%0.5d", ps->_Score);SetPos(64, 12);printf("每个食物10分");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_ESCAPE)){ps->_status = END_NOMAL;//正常退出break;}else if (KEY_PRESS(VK_SPACE)){//暂停函数Pause();//封装一个函数,按下一次暂停,再按就继续}else if (KEY_PRESS(VK_F3))//加速{//ps->SleepTime = 100;//如果一直按着,那就一直二倍加速//ps->_Foodweight = 15;if (ps->SleepTime >= 80)//也可以逐渐加速{ps->SleepTime -= 30;ps->_Foodweight += 2;}}else if (KEY_PRESS(VK_F4))//减速{if (ps->SleepTime <= 300)//逐渐减速{ps->SleepTime += 30;ps->_Foodweight -= 2;}}Sleep(ps->SleepTime);//蛇的移动SnakeMove(ps);//继续封装成函数} while (ps->_status==OK);}//善后处理,打印分数,清理贪吃蛇
void GameOver(psnake ps)
{SetPos(20, 12);switch (ps->_status){case END_NOMAL:printf("您主动退出游戏");break;case KILL_BY_SELF:printf("自杀成功");break;case KILL_BY_WALL:printf("撞墙啦");break;}SetPos(0, 27);//释放蛇的节点pSnakeNode cur = ps->_psnake;while (cur)//循环全部释放{pSnakeNode Next = cur->next;free(cur);cur = Next;}ps->_psnake = NULL;
}

=====================================
test.c

#define _CRT_SECURE_NO_WARNINGS
#include "snake.h"
//Win32,API,Windows 32位接口。//宽字符类型,一个汉字占用两个字符。
// 一个字母宽一个字符,一个汉字占两个字符
//wchar_t宽字符类型□☆★¤◎㊣
//setlocale(LC_ALL,"");//适应中文环境
//宽字符的打印,前缀加上L
//int main()
//{
//	SetPos(10, 10);
//	setlocale(LC_ALL, "");
//	wchar_t ch1 = L'●';
//	wprintf(L"%lc\n", ch1);//打印时printf前边加w,打印时前边大写L,类型为lc=
//	return 0;
//}void test()
{char ch = 0;do{Snake snake = { 0 };//创建贪吃蛇//1,游戏开始——初始化游戏GameStart(&snake);//getchar();//设置光标状态是否成功可以检查一下,用getchar阻塞程序运行//2,游戏运行——正常运行GameRun(&snake);//3,游戏结束——如何结束,释放资源GameOver(&snake);SetPos(20, 15);printf("是否想再来一把?(Y/N):");ch = getchar();getchar();//清理‘/n’。} while (ch == 'Y' || ch == 'y');
}int main()
{srand((unsigned int)time(NULL));//设置程序适应本地化setlocale(LC_ALL, "");test();return 0;
}
//地图,长为宽的2倍

相关文章:

C语言贪吃蛇(有详细注释)

这个贪吃蛇是在比特特训营里学到的&#xff0c;同时我还写了用EasyX图形库实现的图形化贪吃蛇&#xff0c;含有每个函数的实现以及游戏中各种细节的讲解&#xff0c;感兴趣的可以去看一看。 贪吃蛇小游戏 实现效果 以下就是源码&#xff0c;感兴趣的小伙伴可以cv自己玩一玩改…...

MUI框架从新手入门【webapp开发教程】

文章目录 MUI -最接近原生APP体验的高性能前端框架APP开发3.25 开发记录miu框架介绍头部/搜索框&#xff1a;身体>轮播图轮播图设置数据自动跳转&#xff1a;九宫格图片九宫格图文列表底部选项卡按钮选择器手机模拟器 心得与总结&#xff1a;MUI框架在移动应用开发中的应用M…...

HNU-计算机网络-讨论课2

第二次 有关网络智能、安全以及未来网络的讨论 一、必选问题&#xff08;每组自由选择N个&#xff0c;保证组内每人负责1个&#xff09; 网络的发展促进信息的传播&#xff0c;极大提高了人类的感知能力&#xff0c;整个世界都被纳入人类的感知范围。但人们对信息系统以及数据…...

西南科技大学信号与系统A实验一(信号的产生与时域运算)

目录 一、实验目的 二、实验原理 三、实验内容 四、思考题 一、实验目的 1、 掌握用matlab软件产生基本信号的方法。 2、 应用matlab软件实现信号的加、减、乘、反褶、移位、尺度变换及卷积运算 二、实验原理 (一) 产生信号波形的方法 利用Matlab软件的信号处…...

代码随想录二刷 |字符串 |翻转字符串里的单词

代码随想录二刷 &#xff5c;字符串 &#xff5c;翻转字符串里的单词 题目描述解题思路 & 代码实现移除多个空格将整个字符串翻转将每个单词翻转 题目描述 151.翻转字符串里的单词 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成…...

低调使用。推荐一个 GPT4 Turbo、Vision、GPTs、DELL·E3 等所有最新功能同步可用国内网站

在 11 月 6 日&#xff0c;万众期待的 OpenAI DevDay&#xff0c;ChatGPT 发布了一系列新的产品&#xff0c;其中推出了 GPT4 Turbo&#xff0c;并且将GPT4 Vision&#xff0c;DELLE3 等等能力全部集合到一起&#xff0c;不需要再分开使用&#xff0c;原来的局限的文本聊天也进…...

基于视觉传感器的自主扫雷机器人设计与实现

摘要&#xff1a; 在当今的世界安全形势下&#xff0c;扫雷小车的出现可以减少各国人员在扫雷过程中的人员伤亡&#xff0c;扫雷小车实用性能强更适合在军事化领域或者是民用领域上应用。让它具有光明的发展前景。针对这一情况&#xff0c;本毕业设计就对自主扫雷小车进行研究…...

计算机新建盘符和重新分配盘符的大小

一、新建盘符 有些电脑刚买来时候&#xff0c;只有一个C盘分区&#xff0c;此时最好增加几个分区方便使用。 注意&#xff1a;分区操作要慎重&#xff0c;不要轻易去试。这里只针对购买的电脑厂家未做分区&#xff0c;只有一个C盘的情况。 如果自己电脑的分区本身已经满足你…...

windows 查看mysql的错误日志

查找错误日志文件存储路径 用到的软件&#xff1a;everything 官网 voidtools 下载路径 https://www.voidtools.com/Everything-1.4.1.1024.x64-Setup.exe 直接点击下载即可 运行效果如下 我们知道mysql有个配置文件是my.ini&#xff0c;里面配置了相关信息 我们需要先…...

java多线程CountDownLatch简单测试

学习java多线程&#xff0c;请同时参阅 Java多线程 信号量和屏障实现控制并发线程数量&#xff0c;主线程等待所有线程执行完毕1 CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后再继续执行。当所有的线程都已经完成任务&#xff0c;然后在CountDownLatch上…...

npm,yarn,pnpm 清理缓存

目录 1&#xff0c;为什么要清理缓存1&#xff0c;缓存文件太多&#xff0c;影响系统运行2&#xff0c;不同源会有区别 2&#xff0c;命令2.1&#xff0c;npm2.2&#xff0c;yarn2.3&#xff0c;pnpm 1&#xff0c;为什么要清理缓存 1&#xff0c;缓存文件太多&#xff0c;影响…...

【数据结构】二叉排序树(c风格、结合c++引用)

目录 1 基本概念 结构体定义 各种接口 2 二叉排序树的构建和中序遍历 递归版单次插入 非递归版单次插入 3 二叉排序树的查找 非递归版本 递归版本 4 二叉排序树的删除&#xff08;难点&#xff09; 1 基本概念 普通二叉排序树是一种简单的数据结构&#xff0c;节点的值…...

SpringCloudSleuth+Zipkin 整合及关键包汇总

背景 整合了一下 SpringCloudSleuth Zipkin&#xff0c;本来是很简单的东西&#xff0c;但是最终导出依赖包时没注意&#xff0c;导致目标服务始终没有被纳入 Zipkin 的链路追踪中&#xff0c;本文记录这个过程及关键依赖包。 部署zipkin 官网下载最新的 zipkin 可执行包&a…...

腾讯面试笔试题2023.11.30

给定一个由整数组成的非空数组所表示的非负整数如[1,2,3]&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外&#xff0c;这个整数不会以零开头。 &#xff08;要求只能操作数组&#xff0c;不…...

cesium 融合视频

0 如果是文件&#xff0c;那相当的简单 和untiy 一样&#xff0c;可以添加材质后&#xff0c;将image 直接给材质赋值上&#xff0c;其中abcd 是四个点&#xff0c;这四个点要经过计算 <video id"video" style"display:none" controls loop autoplay&…...

微信小程序踩坑记录

一、引言 作者在开发微信小程序《目的地到了》的过程中遇到过许多问题&#xff0c;这里讲讲一些技术和经验问题。 基本目录机构&#xff1a; 二、问题 1、定位使用 获取定位一定要在app.json里面申明&#xff0c;不然是没办法获取定位信息的 "requiredPrivateInfos"…...

H5 uniapp 接入wx sdk

uniapp因为要兼容小程序等&#xff0c;会重写wx对象&#xff0c;导致引入的jweixin-1.6.0.js中对象不生效。 综合网络资料&#xff0c;有两种解决方案&#xff1a; 一&#xff0c;通过npm工具引入 npm install jweixin-module --save 实际上是借用了wx的另一个对象jWeixin …...

ubuntu离线安装包

方便快捷方式 查看依赖 apt-cache depends 包名(gcc或language-pack-zh-hans)下载deb及其依赖包 # 下载.deb包到指定目录 cd /var/cache/apt/archives apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-repl…...

电脑如何录音?适合初学者的详细教程

“电脑怎么录音呀&#xff1f;参加了一个学校举办的短视频大赛&#xff0c;视频拍摄都很顺利&#xff0c;音乐却出了问题&#xff0c;朋友说可以用电脑录制一段音乐应付一下&#xff0c;可是我不会操作&#xff0c;有哪位大佬教教我&#xff01;” 声音是一种强大的媒介&#…...

从零开始的C++(二十)

哈希&#xff1a; 用于unorder_map和unorder_set&#xff0c;其本身是一种思想&#xff0c;即通过一个值利用某种算法去映射到另一个值上。利用哈希思想具体实现的是哈希表。 哈希通常函数&#xff1a;插入和查找 1.插入&#xff1a;用某种算法算出插入值对应的插入下标。 …...

shell编程系列(8)-使用sed处理文本

文章目录 引言sed用法详解在文本中定位打印文本替换文本删除文本新增文本 结语 引言 在日常工作学习中我们都会遇到要编辑文本的场景&#xff0c;例如我们要用vim或者nano等命令去编辑代码&#xff0c;处理文本文件等&#xff0c;这些命令的特点都是需要我们进行交互式的实时处…...

NDK是什么?有什么用?需要掌握什么技术栈?

文章目录 NDK使用NDK的优点使用NDK需要掌握的知识C/C的编译原理C/C基本语法和编写能力原生共享库&#xff1a;原生静态库&#xff1a;Java 原生接口 (JNI)&#xff1a;应用二进制接口 (ABI)&#xff1a; CMakeLLDB参考 NDK NDK&#xff08;Native Development Kit&#xff0c;…...

《代码长寿经:程序员养生指南》

嘿&#xff0c;代码海洋的航行者们&#xff01;你们是否有过熬夜加班后&#xff0c;头发渐渐稀疏、眼镜度数直线上升&#xff0c;还不小心多了几斤“编码赘肉”的经历&#xff1f;程序员这个行业&#xff0c;似乎人均亚健康&#xff0c;有人戏称程序员的职业发展路径是&#xf…...

统计素数并求和(Python)

题目描述 统计素数并求和 本题要求统计给定整数 M M M 和 N N N 区间内素数的个数并对它们求和。 输入格式: 输入在一行中给出两个正整数 M M M 和 N ( 1 ≤ M ≤ N ≤ 500 ) N(1≤M≤N≤500) N(1≤M≤N≤500)。 输出格式: 在一行中顺序输出 M M M 和 N N N 区间内…...

新建的springboot项目中application.xml没有绿色小叶子(不可用)

经常有朋友会遇到新建了一个springboot项目&#xff0c;发现为啥我创建的application.xml配置文件不是绿色的&#xff1f;&#xff1f;&#xff1f; 下面教大家如何解决&#xff0c;这也是博主在做测试的时候遇到的&#xff1a; 将当前位置application.xml删掉&#xff0c;重新…...

powershell获取微软o365 21v日志

0x00 背景 o365 21v为o365的大陆版本&#xff0c;主要给国内用户使用。微软提供了powershell工具和接口获取云上日志。微软o365国内的代理目前是世纪互联。本文介绍如何用powershell和配置证书拉取云上日志。 0x01 实践 第一步&#xff0c;ip权限开通&#xff1a; 由世纪互联…...

整体迁移SVN仓库到新的windows服务器

一、背景 公司原有的SVN服务器年代比较久远经常出现重启情况&#xff0c;需要把SVN仓库重新迁移到新的服务器上&#xff0c;在网上也搜到过拷贝Repositories文件直接在新服务器覆盖的迁移方案&#xff0c;但考虑到原有的操作系统和现有的操作系统版本不一致&#xff0c;SVN版本…...

D365 CRM Power Platform 后端开发概览

博主十年前写的后端技术文章大部分都out-of-date啦&#xff0c;有些东西还能在PP系统中继续沿用&#xff0c;大部分东西都变成old fashion了。 博主后续争取多找些时间&#xff0c;将之前的后端开发文档都翻新一遍&#xff0c;争取与时俱进&#xff0c;让它们还能继续使用下个…...

【Java 并发编程】进程线程、lock、设计模式、线程池...

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从入门到入坟 Java 并发编程 并发编程多线程的入门类和接口线程组和线程优先级线程的状态及主要转化方法线程间的通信重排序和 happens-beforevolatilesynchronized 与锁CAS 与原子操作AQS计划任务Stream 并行计…...

【axios】拦截器:axios.interceptors.request.use|axios.interceptors.response.use

文章目录 概述设置拦截器Axios 拦截器的实现任务注册任务编排任务调度 来源 概述 axios有请求拦截器&#xff08;request&#xff09;、响应拦截器&#xff08;response&#xff09;、axios自定义回调处理&#xff08;这里就是我们常用的地方&#xff0c;会将成功和失败的回调…...