贪吃蛇游戏(C语言实现)

目录

  • 游戏效果展示
  • 文件
  • 代码的展示
    • test.c
    • Snake.c
    • Snake.h
  • 下一个坐标不是食物

游戏效果展示

QQ录屏20240507163633

文件

在这里插入图片描述

代码的展示

test.c

#define _CRT_SECURE_NO_WARNINGS#include<locale.h>
//设置本地化
#include"Snake.h"//游戏的测试逻辑
void test()
{int ch = 0;do {system("cls");//每次上来清理一下屏幕的信息//创建贪吃蛇snake snake = {0};//初始化游戏//1.打印环境界面//2.功能介绍//3.绘制地图//4. 创建蛇//5.创建食物//6.设置游戏的相关信息//开始游戏GameStart(&snake);//运行游戏GameRun(&snake);//结束游戏GameEnd(&snake);SetPos(20,15);printf("再来一局吗(Y/N):");ch = getchar();while (getchar() != '\n');//防止输入太多的字符而出现的bug} while (ch == 'Y' || ch == 'y');SetPos(0, 27);
}
int main()
{//设置本地化环境setlocale(LC_ALL,"");//生成随机数srand((unsigned int)time(NULL));//测试的逻辑test();return 0;
}

Snake.c

#define _CRT_SECURE_NO_WARNINGS#include"Snake.h"//坐标的定位
//定位光标的位置
void SetPos(short x, short y)
{//获取标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定位光标的位置COORD pos = { x, y };SetConsoleCursorPosition(houtput, pos);
}//欢迎界面的打印
void WelComeToGame()
{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 CreatMap()
{//上int i = 0;for (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);}
}//初始化蛇身
void InitSnake(psnake ps)
{int i = 0;psnakenode cur = NULL;for (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->_phead == NULL)//空链表{ps->_phead = cur;}else//非空链表{cur->next = ps->_phead;ps->_phead = cur;}}//打印蛇身cur = ps->_phead;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//设置蛇的属性ps->_dir = RIGHT;//默认蛇的方向是向右的ps->_food_weight = 10;//每个食物的分数ps->_score = 0;//开始总分为0ps->_status = OK;//蛇的状态是正常的ps->_time_sleep = 200;//睡眠时间为200ms
}//创建食物
void CreatFood(psnake ps)
{int x = 0;int y = 0;//生成的x是2的倍数// x - 2~54// y - 1~25again:do{//创建的食物的节点不能和蛇身重叠x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);psnakenode cur = ps->_phead;while (cur){if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}//创建食物的节点psnakenode pfood = (psnakenode)malloc(sizeof(snakenode));if (pfood == NULL){//开辟失败perror("CreatFood::malloc");return;}//开辟成功pfood->x = x;pfood->y = y;pfood->next = NULL;SetPos(x, y);//定位坐标,打印节点wprintf(L"%lc", FOOD);ps->_food = pfood;//食物的信息记录到food(贪吃蛇)里面去
}//游戏的初始化
void GameStart(psnake ps)
{//1.先设置窗口的大小,再隐藏光标system("mode con cols=100 lines=30");system("title 贪吃蛇");//设置窗口的名称HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//得到屏幕的句柄//隐藏光标操作CONSOLE_CURSOR_INFO cursoninfo;//控制光标信息的结构体GetConsoleCursorInfo(houtput, &cursoninfo);//得到控制台的光标信息cursoninfo.bVisible = false;//将光标设置为不可见(隐藏控制台光标)SetConsoleCursorInfo(houtput, &cursoninfo);//设置控制台光标的状态(光标为隐藏)//2.打印环境界面和功能介绍WelComeToGame();//3.创建地图CreatMap();//4.创建蛇InitSnake(ps);//5.创建食物CreatFood(ps);
}//打印帮助信息
void PrintHelpInfo()
{SetPos(64, 15);wprintf(L"%ls",L"不能穿墙,不能咬到自己");SetPos(64, 16);wprintf(L"%ls", L"↑ . ↓ . ← . → .来控制蛇的移动");SetPos(64, 17);wprintf(L"%ls", L"按F3加速,F4减速");SetPos(64, 18);wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏");SetPos(64, 19);wprintf(L"%ls", L"英雄不问出处制作");
}#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1) ? 1 : 0)
//获取按键的情况,按了是真,没按是假
//?在:之前//按了空格键的情况
void Pause()
{while (1){Sleep(200);//睡眠200msif (KEY_PRESS(VK_SPACE)){break;}}
}//判断下一个坐标是否是食物
//返回值判断真假,是否有食物
int NextIsFood(psnakenode pn, psnake ps)
{return (pn->x == ps->_food->x && pn->y == ps->_food->y);//如果下一个节点是食物就吃掉食物
}//下一个坐标是食物就吃掉食物
void EatFood(psnakenode pn, psnake ps)
{//把食物的节点头插ps->_food->next = ps->_phead;ps->_phead = ps->_food;//释放下一个节点的地址,因为下一个节点和食物的节点冲突了free(pn);pn = NULL;//把蛇打印出来psnakenode cur = ps->_phead;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//吃掉一个食物要加分ps->_score += ps->_food_weight;//一个食物吃掉后重新创建一个食物CreatFood(ps);
}//下一个坐标不是食物
void NoFood(psnakenode pn, psnake ps)
{//头插法pn->next = ps->_phead;ps->_phead = pn;psnakenode cur = ps->_phead;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("  ");//释放最后一个节点free(cur->next);//把倒数第二个节点的下一个节点的地址置为NULLcur->next = NULL;
}//检测蛇是否撞墙
void KillByWall(psnake ps)
{if (ps->_phead->x == 0 || ps->_phead->y == 0 ||ps->_phead->x == 56 || ps->_phead->y == 26){ps->_status = KILL_BY_WALL;}
}//检测蛇是否撞到自己
void KillByMyself(psnake ps)
{psnakenode cur = ps->_phead->next;//蛇头的下一个节点和蛇头的节点的坐标是否相同while (cur){if (cur->x == ps->_phead->x && cur->y == ps->_phead->y){ps->_status = KILL_BY_MYSELF;break;//撞到了就跳出循环}cur = cur->next;}
}//蛇的移动 -- 走一步
//蛇的移动控制着蛇的主逻辑
void SnakeMove(psnake ps)
{//创建一个节点,表示蛇即将到的下一个节点psnakenode pNextnode = (psnakenode)malloc(sizeof(snakenode));if (pNextnode == NULL){perror("SnakeMove::malloc");return;}//创建节点成功//蛇的方向switch (ps->_dir){case UP:pNextnode->x = ps->_phead->x;pNextnode->y = ps->_phead->y - 1;break;case DOWN:pNextnode->x = ps->_phead->x;pNextnode->y = ps->_phead->y + 1;break;case LEFT:pNextnode->x = ps->_phead->x - 2;pNextnode->y = ps->_phead->y;break;case RIGHT:pNextnode->x = ps->_phead->x + 2;pNextnode->y = ps->_phead->y;break;}//检查下一个节点是否是食物if (NextIsFood(pNextnode, ps)){EatFood(pNextnode, ps);}else{NoFood(pNextnode, ps);}//判断蛇是否撞墙KillByWall(ps);//判断蛇是否撞到自己KillByMyself(ps);}//游戏运行的逻辑
void GameRun(psnake ps)
{//打印帮助信息PrintHelpInfo();do{//打印总分数和食物的分数SetPos(64, 10);printf("总分数是:%d\n", ps->_score);SetPos(64, 11);printf("当前食物的分数是:%2d\n", 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 = EXIT;}else if (KEY_PRESS(VK_F3)){//加速if (ps->_time_sleep > 80){ps->_time_sleep -= 30;ps->_food_weight += 2;}}else if (KEY_PRESS(VK_F4)){//减速if (ps->_food_weight > 2){ps->_time_sleep += 30;ps->_food_weight -= 2;}}//蛇走一步的过程SnakeMove(ps);Sleep(ps->_time_sleep);//蛇走完一步再让蛇睡眠一下,可以达到蛇动态的移动过程	} while (ps->_status == OK);
}//游戏善后的工作
//游戏的状态是因为什么而结束的
void GameEnd(psnake ps)
{SetPos(24, 12);//定位到屏幕的正中央然后打印switch (ps->_status){case KILL_BY_MYSELF:wprintf(L"您撞到了自己,游戏结束\n");break;case KILL_BY_WALL:wprintf(L"您撞到墙上,游戏结束\n");break;case EXIT:wprintf(L"您主动结束游戏\n");break;}//释放掉蛇身的节点psnakenode cur = ps->_phead;while (cur){psnakenode Del = cur;cur = cur->next;free(Del);}
}

Snake.h

#define _CRT_SECURE_NO_WARNINGS
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
#include<stdbool.h>//#define 后面不用打括号//定位,Y是X的两倍
#define POS_X 24
#define POS_Y 5#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'//类型的声明 //蛇的方向
enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
};//蛇的状态
//撞到自己,撞到墙,正常运行,正常退出
enum STATUS
{OK,//正常运行EXIT,//正常退出KILL_BY_WALL,//撞到墙KILL_BY_MYSELF//撞到自己
};//蛇身的节点类型
typedef struct SnakeNode
{int x;int y;//坐标struct SnakeNode* next;//指向下一个节点的指针
}snakenode,* psnakenode;//typedef struct SnakeNode* pSnake; == 上面的写法 //贪吃蛇
typedef struct SnakeList
{psnakenode _phead;//指向蛇头节点的指针psnakenode _food;//指向食物节点的指针enum DIRECTION _dir;//蛇的方向enum STATUS _status;//蛇的状态int _food_weight;//一个食物的分数int _score;//总分数int _time_sleep;//休息的时间,时间越短,速度越快,时间越长,速度越慢
}snake,* psnake;//函数的声明//坐标的定位
//定位光标的位置
void SetPos(short x, short y);//游戏的初始化
void GameStart(psnake ps);//欢迎界面的打印
void WelComeToGame();//创建地图
void CreatMap();//初始化蛇身
void InitSnake(psnake ps);//创建食物
void CreatFood(psnake ps);//游戏运行的逻辑
void GameRun(psnake ps);//蛇的移动 -- 走一步
void SnakeMove(psnake ps);//判断下一个坐标是否是食物
//pn是下一个节点的指针
int NextIsFood(psnakenode pn, psnake ps);//下一个坐标是食物就吃掉食物
void EatFood(psnakenode pn, psnake ps);//下一个坐标不是食物
void NoFood(psnakenode pn, psnake ps);//检测蛇是否撞墙
void KillByWall(psnake ps);//检测蛇是否撞到自己
void KillByMyself(psnake ps);//游戏善后的工作
void GameEnd(psnake ps);

下一个坐标不是食物

在这里插入图片描述
打印前四个节点,打印完第四个节点退出循环,把cur下一个节点打印成空,也就是最后一个节点打印成空释放最后一个节点,把倒数第二个节点的下一个节点的地址置为NULL,倒数第二个节点不用打印,之前打印了前5个节点,节点不会消失,所以倒数第二个节点存在

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

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

相关文章

2024最佳项目管理软件整理

在项目管理领域&#xff0c;选择合适的任务管理软件对于提高团队效率和确保项目顺利进行至关重要。 以下是一些优秀的项目任务管理软件&#xff0c;以及它们的官网地址和特点介绍 序号软件名称官网地址特点介绍1zz-planhttps://zz-plan.com/一款在线甘特图协作软件&#xff0c…

c# - - - winform程序四个角添加圆角效果

winform 给窗体四个角添加圆角效果。 在窗体 Load 事件中添加如下代码&#xff1a; // 创建了一个圆角矩形的路径&#xff0c;并将其设置为控件的形状 System.Drawing.Drawing2D.GraphicsPath path new System.Drawing.Drawing2D.GraphicsPath(); int radius 30; path.AddAr…

ssm123基于java web的网上书城系统的设计与实现+vue

基于java web的网上书城系统的设计与实现vue 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;商品交易当然也不能排除在外&#xff0c;随着商品交易管理的不断成熟&#xff0c;它彻底改变了…

基于FPGA的视频矩阵切换方案

一、单个显示设备的系统方案&#xff1a;会议室只有1个显示设备 会议室的信号源有很多&#xff0c;但是显示设备只有1个&#xff0c;这个时候最佳方案是使用切换器。 &#xff08;1&#xff09;切换器&#xff08;控制方式&#xff1a;遥控器、软件、机箱面板、中控&#xff…

DS高阶:B树系列

一、常见的搜索结构 1、顺序查找 时间复杂度&#xff1a;O(N) 2、二分查找 时间复杂度&#xff1a;O(logN) 要求&#xff1a;&#xff08;1&#xff09;有序 &#xff08;2&#xff09;支持下标的随机访问 3、二叉搜索树&#xff08;BS树&#xff09; 时间复杂…

外卖系统微信小程序支付

微信小程序支付时序图 其中第9.步骤就是微信小程序前端调用wx.requestPayment

Python运维之协程

目录 一、定义协程 二、并发 三、异步请求 协程是一种轻量级的线程&#xff0c;它通过保存和恢复寄存器上下文和栈来实现调度切换&#xff0c;从而保留函数执行的状态。 这种机制使得协程在处理I/O密集型任务时效率较高&#xff0c;因为它们可以在I/O操作期间让出CPU&#…

Linux学习笔记(3)---- Debian测试网速指令及查看是否千兆网卡

测试网速指令 在Debian系统中&#xff0c;测网速的指令主要有以下几种方法&#xff1a; 使用speedtest-cli工具&#xff1a; speedtest-cli是一个常用的网络速度测试工具&#xff0c;可以通过命令行进行安装和运行。首先&#xff0c;需要安装speedtest-cli&#xff1a; sud…

卷积神经网络边缘识别

为什卷积神经网络能够识别图片呢&#xff1f;是基于图片相似度比较&#xff0c;两张图片的点击越大说明两张图片越像&#xff0c;比如我们那狗胡子的图片去比较&#xff0c;如果相似度很高&#xff0c;就是认为这个动物更像狗。点积越大&#xff0c;图片越相似&#xff0c;这个…

2024第八季完美童模 【星光】品牌赛区 【直通】赛 完美收官

2024年5月1日&#xff0c;春风徐徐的【星光品牌赛区】热闹非凡&#xff0c;备受瞩目的第八季完美童模【星光品牌赛区】赛区【直通赛】在这一天正式拉开了帷幕。比赛现场&#xff0c;童模们身着华服&#xff0c;在舞台上演绎了“亚特兰蒂斯”的时尚主题赛。 参赛选手们身着带有海…

Qt---项目的创建及运行

一、创建第一个Qt程序 1. 点击创建项目后&#xff0c;选择项目路径以及给项目起名称 名称&#xff1a;不能有中文、不能有空格 路径&#xff1a;不能有中文路径 2. 默认创建有窗口类myWidget&#xff0c;基类有三种选择&#xff1a;QWidget、QMainWindow、QDialog 3. m…

【Unity Animation 2D】Unity Animation 2D骨骼绑定与动画制作

一、图片格式为png格式&#xff0c;并且角色各部分分离 图片参数设置 需要将Sprite Mode设置为Single&#xff0c;否则图片不能作为一个整体 1、创建骨骼 1.1 旋转Create Bone&#xff0c;点击鼠标左键确定骨骼位置&#xff0c;移动鼠标再次点击鼠标左键确定骨骼&#xff0c…

探秘未来科技:数字化无人巡检的奇妙之旅

嘿&#xff0c;朋友们&#xff01;下午茶时间到&#xff01;趁着这会儿咱们来聊一个超级炫酷的话题——数字化无人巡检。想象一下&#xff0c;那些曾经需要人工跋山涉水、风吹日晒的巡检工作&#xff0c;现在正被一群“智能小分队”悄悄接手&#xff0c;是不是觉得既神奇又方便…

三极管 导通条件

一、三极管理解 三极管是电子行业常用的元器件之一&#xff0c;他是一种电流型控制的器件&#xff0c;他有三种工作状态&#xff1a;截止区&#xff0c;放大区、饱和区。当三极管当做开关使用时&#xff0c;他工作在饱和区。下面简短讲解三极管作为开关使用的方法&#xff0c;只…

JSP ssm 智能水表管理myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSP ssm 智能水表管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采…

Electron学习笔记(三)

文章目录 相关笔记笔记说明 五、界面1、获取 webContents 实例&#xff08;1&#xff09;通过窗口对象的 webContent 属性获取 webContent 实例&#xff1a;&#xff08;2&#xff09;获取当前激活窗口的 webContents 实例&#xff1a;&#xff08;3&#xff09;在渲染进程中获…

252 基于MATLAB的自适应差分阈值法检测心电信号的QRS波

基于MATLAB的自适应差分阈值法检测心电信号的QRS波&#xff0c;QRS波群反映左、右心室除极电位和时间的变化&#xff0c;第一个向下的波为Q波&#xff0c;向上的波为R波&#xff0c;接着向下的波是S波。通过GUI进行数据处理&#xff0c;展示心率和QRS。程序已调通&#xff0c;可…

域控安全 ----> Ntds.dit文件抓取

大家还记得内网渗透的初衷吗&#xff1f;&#xff1f;&#xff1f; 找到域馆&#xff0c;拿下域控&#xff01;&#xff01; 拿下了域控就是拿下了整个域&#xff01;&#xff01; 但是大家知道拿下域环境之后应该怎么操作吗(灵魂拷问)&#xff1f;&#xff1f;&#xff1f; …

升级! 测试萌新Python学习之连通数据库Pymsql增删改及封装(四)

pymysql 数据库概述python对数据库的增删改查pymysql核心操作事务事务操作pymysql工具类封装每日复习ChatGPT的回答 数据库概述 分类 关系型数据库: 安全 如, mysql oracle SQLite…database tables 行列 非关系型数据库: 高效 如, redis mongoDB…数据存储结构多样 键值对…

字符串函数(一):strcpy(拷贝),strcat(追加),strcmp(比较),及strncpy,strncat,strncmp

字符串函数 一.strcpy&#xff08;字符串拷贝&#xff09;1.函数使用2.模拟实现 二.strcat&#xff08;字符串追加&#xff09;1.函数使用2.模拟实现 三.strcmp&#xff08;字符串比较&#xff09;1.函数使用2.模拟实现 四.strncpy1.函数使用2.模拟实现 五.strncat1.函数使用2.…