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倍

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

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

相关文章

Windows系列:windows server 2016 下域环境的搭建(完整版)

windows server 2016 下域环境的搭建&#xff08;完整版&#xff09; windows server 2016 下域环境的搭建在搭建之前简单介绍一下基础知识&#xff1a;一、环境介绍 &#xff1a;1.这里用拓扑图进行展示&#xff1a;2.所有环境配置如下 二、搭建主域&#xff1a;一. 创建主域1…

Java+SSM springboot+MySQL家政服务预约网站设计en24b

随着社区居民对生活品质的追求以及社会老龄化的加剧&#xff0c;社区居民对家政服务的需求越来越多&#xff0c;家政服务业逐渐成为政府推动、扶持和建设的重点行业。家政服务信息化有助于提高社区家政服务的工作效率和质量。 本次开发的家政服务网站是一个面向社区的家政服务网…

华为云之云桌面Workspace的使用体验

华为云之云桌面Workspace的使用体验 一、云桌面Workspace介绍1.云桌面简介2.云桌面特点3. 云桌面应用场景①远程移动办公②协同办公③安全办公④公用终端⑤图形制作渲染 二、本次实践介绍1. 本次实践目的2. 本次实践环境 三、购买云桌面1. 进入华为云的云桌面购买界面2. 选择购…

C# Onnx 百度飞桨开源PP-YOLOE-Plus目标检测

目录 效果 模型信息 项目 代码 下载 C# Onnx 百度飞桨开源PP-YOLOE-Plus目标检测 效果 模型信息 Inputs ------------------------- name&#xff1a;image tensor&#xff1a;Float[1, 3, 640, 640] name&#xff1a;scale_factor tensor&#xff1a;Float[1, 2] ----…

服务器之间的conda环境迁移

有的时候python环境中可能包含了我们编译好的很多库文件&#xff0c;如果在别的服务器想直接使用环境就会比较困难些。最好的办法就是直接迁移环境。而传统的迁移方法导出“*.yaml”环境配置的这种方法&#xff0c;实际是需要重新安装环境&#xff0c;对于这种安装好的环境是不…

数据结构:图文详解顺序表的各种操作(新增元素,查找元素,删除元素,给指定位置元素赋值)

目录 一.顺序表的概念 二.顺序表的实现 新增元素 默认尾部新增 指定位置添加元素 查找元素 查找是否存在 查找元素对应的位置 查找指定位置对应的元素 删除元素 获取顺序表长度 清空顺序表 一.顺序表的概念 在线性数据结构中&#xff0c;我们一般分为俩类&#xf…

程序员也需要养生——程序员睡不好,重视一下你的情绪吧

程序员也需要养生——程序员睡不好&#xff0c;重视一下你的情绪吧 睡眠是一个复杂的系统工程&#xff0c;可以促进生长发育&#xff0c;修复受损的组织。促进大脑细胞的修复等等。在情绪的失调会影响到我们的睡眠状况。 一、心情差&#xff0c;压力大&#xff0c;睡不好跟这…

项目设计---MQ

文章目录 一. 项目描述二. 核心技术三. 需求分析概要设计四. 详细设计4.1 服务器模块4.1.1 内存管理4.1.2 硬盘管理4.1.2.1 数据库管理4.1.2.2 文件管理 4.1.3 消息转发 4.2 客户端模块4.2.1 连接管理4.2.2 信道管理 4.3 公共模块4.3.1 通信协议4.3.2 序列化/反序列化 一. 项目…

利润大增,MAU膝斩,谋求转型的新氧头顶“荆棘王冠”

撰稿|行星 来源|贝多财经 近日&#xff0c;医疗美容服务平台新氧科技&#xff08;NASDAQ:SY&#xff0c;下称“新氧”&#xff09;发布了2023年第三季度未经审计的财务业绩报告。 财报显示&#xff0c;新氧于2023年第三季度实现收入3.85亿元&#xff0c;同比增长19.2%&#x…

【玩转 EdgeOne】| 腾讯云下一代边缘加速CDN EdgeOne 是安全加速界的未来吗?

目录 前言边缘加速与安全加固边缘计算与CDN的融合EdgeOne优秀的安全特性EdgeOne卓越的性能表现灵活的配置和管理生态系统的支持与发展技术创新与未来展望EdgeOne试用结束语 前言 在当下互联网的迅猛发展的时刻&#xff0c;云计算和边缘计算技术的快速发展为网络加速领域带来了…

Linux下查看目录大小

查看目录大小 Linux下查看当前目录大小&#xff0c;可用一下命令&#xff1a; du -h --max-depth1它会从下到大的显示文件的大小。

WARNING: Access control is not enabled for the database.

MongoDB shell version v3.4.24 WARNING: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted. 1)未启用访问控制 2)读写访问不受限制 D:\MongoDB\Server\3.4\bin>mongo MongoDB shell version v3.4.24 c…

【Vulnhub 靶场】【DriftingBlues: 9 (final)】【简单】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/driftingblues-9-final,695/ 靶场下载&#xff1a;https://download.vulnhub.com/driftingblues/driftingblues9.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年05月09日 文件大小&#xff1a;738 …

【JavaEE】多线程 -- 死锁问题

目录 1. 问题引入 2.死锁问题的概念和原因 3. 解决死锁问题 1. 问题引入 在学习死锁之前, 我们先观察下面的代码能否输出正确的结果: 运行程序, 能正常输出结果: 这个代码只管上看起来, 好像是有锁冲突的, 此时的 locker 对象已经是加锁的状态, 在尝试对 locker 加锁, 不应该…

使用 OpenTelemetry 和 Golang

入门 在本文中&#xff0c;我将展示你需要配置和处理统计信息所需的基本代码。在这个简短的教程中&#xff0c;我们将使用 Opentelemetry 来集成我们的 Golang 代码&#xff0c;并且为了可视化&#xff0c;我们将使用 Jeager。 在开始之前&#xff0c;让我简要介绍一下什么是 …

go学习之json和单元测试知识

文章目录 一、json以及序列化1.概述2.json应用场景图3.json数据格式说明4.json的序列化1&#xff09;介绍2&#xff09;应用案例 5.json的反序列化1&#xff09;介绍2&#xff09;应用案例 二、单元测试1.引子2.单元测试-基本介绍3.代码实现4.单元测试的细节说明5.单元测试的综…

中国毫米波雷达产业分析4——毫米波雷达企业介绍

一、矽典微 &#xff08;一&#xff09;公司简介 矽典微致力于实现射频技术的智能化&#xff0c;专注于研发高性能无线技术相关芯片&#xff0c;产品广泛适用于毫米波传感器、下一代移动通信、卫星通信等无线领域。 整合自身在芯片、系统、软件、算法等领域的专业能力&#xf…

【论文速递】:老驾驶员轨迹数据中的异常行为检测

给定道路网络和一组轨迹数据&#xff0c;异常行为检测 &#xff08;ABD&#xff09; 问题是识别在行程中表现出明显方向偏差、急刹车和加速的驾驶员。ABD 问题在许多社会应用中都很重要&#xff0c;包括轻度认知障碍 &#xff08;MCI&#xff09; 检测和老年驾驶员的安全路线建…

Redis未授权访问-CNVD-2019-21763复现

Redis未授权访问-CNVD-2019-21763复现 利用项目&#xff1a; https://github.com/vulhub/redis-rogue-getshell 解压后先进入到 RedisModulesSDK目录里面的exp目录下&#xff0c;make编译一下才会产生exp.so文件&#xff0c;后面再利用这个exp.so文件进行远程代码执行 需要p…

Python基础语法之学习字符串格式化

Python基础语法之学习字符串格式化 一、代码二、效果 一、代码 # 通过m.n控制 a 123 b 123.444 c 123.555 print("限制为5:%5d" % a) print("限制为2:%2d" % a) print("限制为5.2:%5.2f" % b) print("限制为5.2:%5.2f" % c)二、效…