贪吃蛇(C语言实现)

  贪食蛇(也叫贪吃蛇)是一款经典的小游戏。

——————————————————————

  本博客实现使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏。

实行的基本功能:

•  贪吃蛇地图的绘制

•  蛇吃食物的功能(上、下、左、右方向键来控制蛇的方向)

•  蛇撞墙死亡

•  蛇撞自身死亡

•  计算得分

•  蛇身加速、减速

•  暂停游戏

主要框架(主要函数):

GameStrat();//游戏开始前的初始化
GameRun();//玩游戏的过程
GameEnd();//善后工作(节点的释放)

游戏流程设计:

参考代码:

snake.h

#pragma once#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <stdbool.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 GAME_STATUS
{OK=1,//正常运行ESC, //按了ESC键退出,正常退出KILL_BY_WALL,//撞墙KILL_BY_SELF //撞到自身
};//蛇行走的方向
enum DIRECTION
{UP=1,DOWN,LEFT,RIGHT
};//蛇身结点的定义
typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//贪吃蛇
typedef struct Snake
{pSnakeNode pSnake;//维护整条蛇的指针,是指向蛇头pSnakeNode pFood;//指向食物的指针int Score;//当前累积的分数int FoodWeight;//一个食物的分数int SleepTime;//蛇休眠的时间,休眠的时间越短,蛇的速度越快,休眠的时间越长,蛇的速度越慢enum GAME_STATUS status;//游戏当前的状态enum DIRECTION dir;//蛇当前走的方向//...
}Snake, * pSnake;//定位控制台光标位置
void SetPos(int x, int y);//游戏开始前的准备
void GameStart(pSnake ps);//打印欢迎界面
void WelcomeToGame();//绘制地图
void CreateMap();//初始化贪吃蛇
void InitSnake(pSnake ps);//创建食物
void CreateFood(pSnake ps);//游戏运行的整个逻辑
void GameRun(pSnake ps);//打印帮助信息
void PrintHelpInfo();//蛇移动的函数- 每次走一步
void SnakeMove(pSnake ps);//判断蛇头的下一步要走的位置处是否是食物
int NextIsFood(pSnake ps, pSnakeNode pNext);//下一步要走的位置处就是食物,就吃掉食物
void EatFood(pSnake ps, pSnakeNode pNext);//下一步要走的位置处不是食物,不吃食物
void NotEatFood(pSnake ps, pSnakeNode pNext);//检测是否撞墙
void KillByWall(pSnake ps);//检测是否撞自己
void KillBySelf(pSnake ps);//游戏结束的资源释放
void GameEnd(pSnake ps);

snake.c

#define _CRT_SECURE_NO_WARNINGS 1#include "snake.h"void SetPos(int x,int y)
{//获得设备句柄HANDLE hanlde = GetStdHandle(STD_OUTPUT_HANDLE);//根据句柄设置光标的位置COORD pos = { x, y };SetConsoleCursorPosition(hanlde, pos);
}void WelcomeToGame()
{//欢迎信息SetPos(35, 10);printf("欢迎来到贪吃蛇小游戏\n");SetPos(38, 20);system("pause");system("cls");//功能介绍信息SetPos(15, 10);printf("用 ↑ . ↓ . ← . → 来控制蛇的移动,F3是加速,F4是减速");SetPos(15, 11);printf("加速能得到更高的分数");SetPos(38, 20);system("pause");system("cls");
}void CreateMap()
{int i = 0;//上SetPos(0, 0);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//下SetPos(0, 26);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//左for (i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%lc", WALL);}
}void InitSnake(pSnake ps)
{//创建5个蛇身的结点pSnakeNode cur = NULL;int i = 0;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake():malloc()");return;}cur->x = POS_X + 2 * i;cur->y = POS_Y;cur->next = NULL;//头插法if (ps->pSnake == NULL){ps->pSnake = cur;}else{cur->next = ps->pSnake;ps->pSnake = cur;}}//打印蛇身cur = ps->pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//贪吃蛇的其他信息初始化ps->dir = RIGHT;ps->FoodWeight = 10;ps->pFood = NULL;ps->Score = 0;ps->SleepTime = 200;ps->status = OK;
}void CreateFood(pSnake ps)
{int x = 0;int y = 0;again:do{x = rand() % 53 + 2;y = rand() % 24 + 1;} while (x % 2 != 0);//坐标和蛇的身体的每个节点的做坐标比较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;ps->pFood = pFood;SetPos(x, y);wprintf(L"%lc", FOOD);}void GameStart(pSnake ps)
{//设置控制台的信息,窗口大小,窗口名system("mode con cols=100 lines=30");system("title 贪吃蛇");//隐藏光标HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false;SetConsoleCursorInfo(handle, &CursorInfo);//打印欢迎信息WelcomeToGame();//绘制地图CreateMap();//初始化蛇InitSnake(ps);//创建食物CreateFood(ps);
}void PrintHelpInfo()
{SetPos(62, 15);printf("1.不能穿墙,不能咬到自己");SetPos(62, 16);printf("2.用 ↑.↓.←.→ 来控制蛇的移动"); SetPos(62, 17);printf("3.F3是加速,F4是减速");SetPos(62, 19);printf("版权@比特就业课");
}void pause()
{while (1){Sleep(100);if (KEY_PRESS(VK_SPACE)){break;}}
}int NextIsFood(pSnake ps, pSnakeNode pNext)
{if (ps->pFood->x == pNext->x && ps->pFood->y == pNext->y)return 1;//下一个坐标处是食物elsereturn 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;}ps->Score += ps->FoodWeight;//释放旧的食物free(ps->pFood);//新建食物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;//易错
}//检测是否撞墙
void 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;}
}//检测是否撞自己
void KillBySelf(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;return;}cur = cur->next;}
}void SnakeMove(pSnake ps)
{pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNext == NULL){perror("SnakeMove()::malloc()");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 LEFT:pNext->x = ps->pSnake->x-2;pNext->y = ps->pSnake->y;break;case RIGHT: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)
{//打印帮助信息PrintHelpInfo();do{//当前的分数情况SetPos(62, 10);printf("总分:%5d\n", ps->Score);SetPos(62, 11);printf("食物的分值:%02d\n", ps->FoodWeight);//检测按键//上、下、左、右、ESC、空格、F3、F4if (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 = ESC;break;}else if (KEY_PRESS(VK_SPACE)){//游戏要暂定pause();//暂定和回复暂定}else if(KEY_PRESS(VK_F3)){if (ps->SleepTime >= 80){ps->SleepTime -= 30;ps->FoodWeight += 2;}}else if (KEY_PRESS(VK_F4)){if (ps->FoodWeight > 2){ps->SleepTime += 30;ps->FoodWeight -= 2;}}//走一步SnakeMove(ps);//睡眠一下Sleep(ps->SleepTime);} while (ps->status == OK);
}void GameEnd(pSnake ps)
{SetPos(15, 12);switch (ps->status){case ESC:printf("主动退出游戏,正常退出\n");break;case KILL_BY_WALL:printf("很遗憾,撞墙了,游戏结束\n");break;case KILL_BY_SELF:printf("很遗憾,咬到自己了,游戏结束\n");break;}//释放贪吃蛇的链表资源pSnakeNode cur = ps->pSnake;pSnakeNode del = NULL;while (cur){del = cur;cur = cur->next;free(del);}free(ps->pFood);ps = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "snake.h"void test()
{//创建贪食蛇int ch = 0;do{Snake snake = { 0 };GameStart(&snake);//游戏开始前的初始化GameRun(&snake);//玩游戏的过程GameEnd(&snake);//善后的工作SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar();getchar();// 清理\n} while (ch == 'Y' || ch =='y');
}int main()
{//修改适配本地中文环境setlocale(LC_ALL, "");test();//贪吃蛇游戏的测试SetPos(0, 27);return 0;
}

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助

欢迎各位点赞,收藏和关注哦

如果有疑问或有不同见解,欢迎在评论区留言哦

后续我会一直分享双一流211西北大学软件(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享

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

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

相关文章

详解DNS服务

华子目录 概述产生原因作用连接方式 因特网的域名结构拓扑分类域名服务器类型划分 DNS域名解析过程分类解析图图过程分析注意 搭建DNS域名解析服务器概述安装软件bind服务中的三个关键文件 配置文件分析主配置文件共4部分组成区域配置文件作用区域配置文件示例分析正向解析反向…

动态规划 Leetcode 70 爬楼梯

爬楼梯 Leetcode 70 学习记录自代码随想录 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到…

SpringCloud 微服务架构编码构建

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第一篇&#xff0c;即不使用 SpringCloud 组件进行模块之间的调用&#xff0c;后续会有很多的文章循序渐…

️ IP代理实操指南:如何在爬虫项目中避免封禁和限制 ️‍♂️

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

moreutils yum安装

在基于RPM的Linux发行版中&#xff0c;如CentOS、Red Hat Enterprise Linux或Fedora&#xff0c;你可以使用yum&#xff08;在较旧版本中&#xff09;或dnf&#xff08;在较新版本中&#xff09;来安装moreutils软件包。不过需要注意的是&#xff0c;默认的官方仓库可能并未包含…

企业战略管理 找准定位 方向 使命 边界 要干什么事 要做多大的生意 资源配置投入

AI突破千行百业&#xff0c;也难打破护城河 作为每个企业或个人的立命生存之本&#xff0c;有的企业在某个领域长期努力筑起了高高的护城河。 战略是什么&#xff1f;用处&#xff0c;具体内容 企业战略是指企业为了实现长期目标&#xff0c;制定的总体规划和长远发展方向。…

通过Forms+Automate+Lists+审批,实现用车申请流程

因为Sham公司目前用的用车申请流程是使用的K2系统&#xff0c;用户申请后&#xff0c;我们还需要单独另行输入Excel来汇总申请记录&#xff0c;当然K2也能导出&#xff0c;但是需要每次导出也是很麻烦的&#xff0c;而且不灵活。 刚好最近发现Forms与Automate能联通&#xff0…

华容道问题求解_详细设计(六)之简单互动和动画

简单互动 为了增加趣味性&#xff0c;增加了简单的互动功能&#xff0c;即实现了一个简单的华容道游戏。在HrdGame中有两个鼠标操作的函数&#xff0c;在传入的控件中调用这个两个函数就可以了。 代码如下&#xff1a; Click事件 private void pnl_GameBoard_MouseClick(objec…

华为OD面试分享9(2024年)

1.3 告知简历筛选通过 1.8 资格面,就简单问了一下gap原因,离职原因,期望薪水,还问了一下技术栈 这期间本来在准备机试,结果机试我上半年考了一次,但是后面没去od,hr告知成绩好像还有效就没有重新机试。具体题目忘了。 1.17 技术一面 上来先自我介绍,然后问了一下上…

Java服务器-Disruptor使用注意

最近看了一下部署后台的服务器状况&#xff0c;发现我的一个Java程序其占用的CPU时长超过100%&#xff0c;排查后发现竟是Disruptor引起的&#xff0c;让我们来看看究竟为什么Disruptor会有这样的表现。 发现占用CPU时间超过100%的进程 首先是在服务器上用top命令查看服务器状…

C语言 寻找单身狗(2个

此题知识&#xff1a;a^0a;a^a0;传值调用和传址调用要分清作用 题目&#xff1a;在 1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;1&#xff0c;3&#xff0c;4&#xff0c;5这几个数字中找出只出现一次的数字并打印在屏幕上 解题思路&…

vue,provide和inject,备忘

在Vue.js应用中&#xff0c;provide 和 inject 是一对API&#xff0c;用于实现组件间的跨层级依赖注入。provide 在父组件中定义要向下传递的属性或方法&#xff0c;而 inject 在子组件中声明它需要从祖先组件那里注入的属性。 具体到您的例子&#xff1a; // 在根组件或任意…

超越基础:提升你的数据采集策略与IP代理的高级应用

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【AI辅助研发】-趋势:大势已来,行业变革

【AI辅助研发】-趋势&#xff1a;大势已来&#xff0c;行业变革 引言 在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;技术已逐渐渗透到各行各业&#xff0c;其中软件研发行业更是受益匪浅。AI辅助研发已成为大势所趋&#xff0c;不仅提高了软件开发的效…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:动态属性设置)

动态设置组件的属性&#xff0c;支持开发者在属性设置时使用if/else语法&#xff0c;且根据需要使用多态样式设置属性。 说明&#xff1a; 从API Version 11开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 attributeModifier attributeMo…

js之原型链

在JavaScript中&#xff0c;原型链是一种用于实现继承和属性查找的机制。每个对象都有一个内部属性[[Prototype]]&#xff0c;这个属性指向创建该对象时使用的构造函数的“prototype"属性。对象的方法和属性定义在它的原型对象上。 1.原型&#xff08;Prototypes&#xf…

RHCE——一、OpenEuler22.03安装部署及例行性任务

RHCE 一、OpenEuler22.03安装部署及例行性任务 一、网络服务1.准备工作2、RHEL9操作系统的安装部署3、配置并优化OpenEuler22.034、网络配置实验&#xff1a;修改网络配置 二、例行性工作1、 单一执行的例行性任务&#xff1a;at&#xff08;一次性&#xff09;at命令详解 2、循…

AI赋能下的研发新时代:2024年研发趋势展望

引言&#xff1a; 在技术的迅猛发展下&#xff0c;人工智能&#xff08;AI&#xff09;已经不再是科幻小说中的幻想&#xff0c;而是我们日常生活和工作中不可或缺的一部分。特别是在研发领域&#xff0c;AI的应用已经逐渐渗透到了各个环节&#xff0c;为科学家、工程师和研究…

[综述笔记]Graph Neural Networks in Network Neuroscience

论文网址&#xff1a;Graph Neural Networks in Network Neuroscience | IEEE Journals & Magazine | IEEE Xplore 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xf…

linux进程间通信-消息队列

Linux下使用C语言实现进程间的通讯-消息队列 Linux进程间通信-消息队列&#xff08;IPC、mq&#xff09;C/C代码接口 Linux 进程间的通信(三)—消息队列