C语言零基础项目:贪吃蛇!详细思路+源码分享
ztj100 2024-10-29 18:21 30 浏览 0 评论
每天一个C语言小项目,提升你的编程能力!
贪吃蛇游戏大家应该都不陌生了,要说没玩过的话,可能你是15后吧?
贪吃蛇游戏最初为单机模式,后续又陆续推出团战模式、赏金模式、挑战模式等多种玩法。
用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。
贪吃蛇的唯一的目标就是长成最长的一条蛇!滑动摇杆控制小蛇走位,吃掉地图上彩色的小圆点,就会变长。
效果展示:
改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难。如果有编程技术比较强大的伙伴也可以去尝试一下哦!做出一个趋近完美的贪吃蛇那可就是能力的展现啦~
本项目编译环境:Visual Studio 2019/2022,EasyX插件
代码展示:
#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
////////////////////////////////////////////
//格子类,定义一个格子的属性及行为
////////////////////////////////////////////
class Cell
{
public:
friend class GameArea; //设置友元函数
?
void setxy(short x, short y) //设置格子左上角坐标
{
m_x = x, m_y = y;
}
void setfull(short full) //设置格子属性,0为空,1为障碍,2为食物
{
m_full = full;
}
void display(COLORREF color) //设置格子颜色并显示
{
m_color = color;
setfillstyle(m_color);
bar(m_x, m_y, m_x+7, m_y+7);
}
void LaserDisplay() //显示镭射状态的格子
{
IMAGE image(10,10);
SetWorkingImage(&image);
DWORD* pMem = GetImageBuffer(&image);
for(int i = 0; i < 10 * 10; i++)
pMem[i] = BGR(RGB(0, 0, i * 256 / (10*10) ));
SetWorkingImage(NULL);
putimage(m_x,m_y,&image);
}
short ReturnFull() //返回格子状态
{
return m_full;
}
Cell() //构造函数
{
m_x = 0,m_y = 0,m_full = 0;
m_color = BLACK;
}
?
private:
?
short m_x; //格子的左上角X坐标
short m_y; //格子的左上角Y坐标
short m_full; //0为空,1为阻挡,2为食物
COLORREF m_color; //格子颜色
};
////////////////////////////////////////////
//游戏区类,编写有关游戏区的一些操作
////////////////////////////////////////////
class GameArea //游戏区域
{
public:
?
Cell m_game[60][60]; //定义游戏区域(由360个格子组成)
?
friend void MessageDispose(); //设置友元函数
?
bool CreatFood() //产生随机食物
{
srand(time(NULL)); //初始化随机数种子
m_random1 = rand()%58+1; //随机生成一个0 - 58的整数
m_random2 = rand()%58+1; //随机一个0 - 58的整数
if(m_game[m_random2][m_random2].m_full == 0) //检查生成的食物坐标是否在障碍上
{
m_game[m_random1][m_random2].display(GREEN);
m_game[m_random1][m_random2].m_full = 2;
return true;
}
//如果随机的食物正好出现在蛇身上,则进入下面的循环寻找可以生成食物的地方
for(m_random1 = 1;m_random1 < 59;m_random1++)
{
for(m_random2 = 1;m_random2 < 59;m_random2++)
{
if(m_game[m_random2][m_random2].m_full == 0)
{
m_game[m_random1][m_random2].display(GREEN);
m_game[m_random1][m_random2].m_full = 2;
return true;
}
}
}
//如果没有找到可以生成食物的地方,则通关
return false; //返回false即表示通关
}
void DelFood() //删除食物
{
m_game[m_random1][m_random2].m_full = 0; //设置为0即代表格子属性为空
}
void ChangeColor(int flag1,int flag2,COLORREF color) //设置指定格子的颜色
{
m_game[flag1][flag2].display(color);
}
void Init() //初始化GAME区域
{
int flag1,flag2; //标识变量
BeginBatchDraw(); //开始批量绘图
setfillstyle(BLACK); //设置当前颜色
bar(0,0,600,600); //画无边框填充矩形(在这里的用途是用黑色清空游戏区域)
for(flag1 = 0;flag1 < 60;flag1++)
{
for(flag2 = 0;flag2 < 60;flag2++)
{
if(flag1 == 0 || flag1 == 59 || flag2 == 0 || flag2 == 59) //创建边界
{
m_game[flag1][flag2].setfull(1);
m_game[flag1][flag2].setxy(flag1*10,flag2*10);
m_game[flag1][flag2].display(RGB(237,28,36));
}
else //创建游戏区域
{
m_game[flag1][flag2].setfull(0);
m_game[flag1][flag2].setxy(flag1*10,flag2*10);
m_game[flag1][flag2].display(BLACK);
}
}
}
CreatFood();
EndBatchDraw();
}
?
private:
?
int m_random1, m_random2;
};
////////////////////////////////////////////
//蛇类,定义蛇的数据结构以及蛇的行为
////////////////////////////////////////////
class Snake
{
public:
?
int toward; //蛇头朝向
friend void MessageDispose();
friend int HitDetect();
friend void ReInit();
Snake()
{
head = NULL;
last = NULL;
now = NULL;
}
void Init() //初始化蛇的结构
{
if(head!=NULL) //重玩游戏时,释放原先的链表所有结点
{
for(now = head->next;now->next != NULL;now = now->next)
{
free(now->prior);
}
}
head = (struct node*)malloc(sizeof(struct node)); //为蛇头分配内存
head->prior = NULL;
head->m_x = 300;
head->m_y = 300;
now = (struct node*)malloc(sizeof(struct node));
head->next = now;
now->prior = head;
now->next = NULL;
now->m_x = 300;
now->m_y = 290;
last = now;
toward = DOWN;
}
void SnakeAdd()
{
now = head; //当前指向蛇头
now->prior = (struct node*)malloc(sizeof(struct node)); //为新增的结点分配内存
now = now->prior; //让当前指向新分配的结点
now->prior = NULL; //置空当前结点的前趋
now->next = head; //让当前结点的后继指向蛇头
switch(toward) //根据当前蛇头方向确定新增部分的坐标
{
case UP:
now->m_x = head->m_x;
now->m_y = head->m_y -10;
break;
case DOWN:
now->m_x = head->m_x;
now->m_y = head->m_y + 10;
break;
case LEFT:
now->m_x = head->m_x - 10;
now->m_y = head->m_y;
break;
case RIGHT:
now->m_x = head->m_x + 10;
now->m_y = head->m_y;
break;
}
head = now; //设置当前结点为蛇头
?
}
void SnakeDel() //释放蛇尾结点(删除蛇尾)
{
last = last->prior;
free(last->next);
last->next = NULL;
}
void SnakeMove() //蛇身移动一格
{
SnakeAdd(); //增加蛇头
SnakeDel(); //删除蛇尾
}
?
private:
?
struct node //蛇身链表
{
int m_x;
int m_y;
struct node *next; //下个结点
struct node *prior; //上个结点
};
struct node *head;
struct node *last;
struct node *now;
};
////////////////////////////////////////////
//游戏类,用来初始化游戏的参数,及实现其他游戏操作
////////////////////////////////////////////
class Game
{
public:
?
void Init()
{
closegraph();
initgraph(800,600);
setbkmode(TRANSPARENT); //设置输出文字背景为透明
LOGFONT f;
getfont(&f); // 获取当前字体设置
f.lfHeight = 50; // 设置字体高度为 48(包含行距)
_tcscpy(f.lfFaceName, _T("黑体")); // 设置字体为“黑体”
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
setfont(&f); // 设置字体样式
}
void FailGame() //游戏失败显示的画面
{
setcolor(RED);
setfont(70, 0, _T("微软雅黑"));
outtextxy(150, 265, _T("YOU LOSE!"));
}
void WinGame() //游戏胜利时显示的画面
{
setcolor(RED);
setfont(70, 0, _T("微软雅黑"));
outtextxy(150, 265, _T("YOU WIN!"));
FlushBatchDraw();
Sleep(10000);
exit(0);
}
};
////////////////////////////////////////////
//管理区类,定义管理区域的相关操作
////////////////////////////////////////////
class ManageArea
{
public:
?
friend void MessageDispose();
?
void TimeAdd(double add) //增加时间(可在类外直接调用实现动态刷新时间)
{
m_time += add;
DisplayTime();
}
void ScoreAdd(short add) //增加分数(可在类外直接调用实现动态刷新分数)
{
m_score += add;
DisplayScore();
}
void DisplayPause() //显示暂停或者开始
{
BeginBatchDraw();
_stprintf(m_str_score, _T("%d"), m_score);
setfont(25, 0, _T("微软雅黑"));
setfillstyle(m_bgcolor);
bar(625,490,800,515);
setcolor(BLUE);
if(m_pause)
outtextxy(625, 490, _T("开始(P键)"));
else
outtextxy(625, 490, _T("暂停(P键)"));
EndBatchDraw();
}
void Init() //初始化管理界面
{
m_time = 0.0;
m_score = 0;
m_leave = 1;
m_pause = false;
_stprintf(m_str_score, _T("%d"), m_score); //格式化转换类型
_stprintf(m_str_time, _T("%.1lf"), m_time);
m_bgcolor = BLACK;
BeginBatchDraw();
setfillstyle(BLACK);
bar(601,0,800,600);
setfont(60, 0, _T("微软雅黑"));
setcolor(GREEN);
outtextxy(625, 30, _T("贪吃蛇"));
setfont(30, 0, _T("微软雅黑"));
setcolor(RGB(128,0,255));
outtextxy(625, 140, _T("制作:轻雨漫步"));
setfont(25, 0, _T("微软雅黑"));
setcolor(BLUE);
outtextxy(625, 430, _T("时间:"));
outtextxy(625, 460, _T("分数:"));
outtextxy(625, 490, _T("暂停(P键)"));
outtextxy(625, 520, _T("重新游戏(R键)"));
setcolor(RED);
outtextxy(720, 400, m_str_leave);
outtextxy(680, 460, m_str_score);
outtextxy(680, 430, m_str_time);
EndBatchDraw();
}
?
private:
?
double m_time;
short m_score;
short m_leave;
bool m_pause;
TCHAR m_str_leave[2], m_str_time[33], m_str_score[5];
COLORREF m_bgcolor;
?
void DisplayTime() //显示当前耗时
{
BeginBatchDraw();
_stprintf(m_str_time, _T("%.1lf"), m_time);
setfont(25, 0, _T("微软雅黑"));
setfillstyle(m_bgcolor);
bar(680,430,800,455);
setcolor(RED);
outtextxy(680,430,m_str_time);
EndBatchDraw();
}
void DisplayScore() //显示当前分数
{
BeginBatchDraw();
_stprintf(m_str_score, _T("%d"), m_score);
setfont(25, 0, _T("微软雅黑"));
setfillstyle(m_bgcolor);
bar(680,460,800,485);
setcolor(RED);
outtextxy(680,460,m_str_score);
EndBatchDraw();
}
};
?
?
////////////////////////////////////////////
//声明游戏需要的类
////////////////////////////////////////////
?
Game game; //用于初始化游戏、设置游戏相关参数
GameArea a; //用于初始化游戏区域,设置,改变游戏区域相关参数
ManageArea manager; //用于初始化管理区域,设置管理区相关参数
Snake s; //用于初始化蛇,数据化蛇,操作蛇
?
////////////////////////////////////////////
//游戏的消息控制,流程控制函数
////////////////////////////////////////////
void MessageDispose() //消息处理函数
{
char c;
s.now = NULL;
bool Keepdown = false;
?
while(true)
{
Keepdown = false; //是否持续按W A S D 中的一个按键
if(kbhit())
{
switch(c = getch()) //处理按键消息(W A S D)
{
case 'w':
case 'W':
if(s.toward == UP)Keepdown = true;
else if(s.toward != DOWN&&s.toward != UP)s.toward = UP;
break;
case 's':
case 'S':
if(s.toward == DOWN)Keepdown = true;
else if(s.toward != UP&&s.toward != DOWN)s.toward = DOWN;
break;
case 'a':
case 'A':
if(s.toward == LEFT)Keepdown = true;
else if(s.toward != RIGHT&&s.toward != LEFT)s.toward = LEFT;
break;
case 'd':
case 'D':
if(s.toward == RIGHT)Keepdown = true;
else if(s.toward != LEFT&&s.toward != RIGHT)s.toward = RIGHT;
break;
case 'p':
case 'P':
manager.m_pause = !manager.m_pause; //设置暂停或开始
manager.DisplayPause(); //显示暂停或开始
break;
case 'r':
case 'R':
ReInit();
break;
}
}
if(true == manager.m_pause) //如果暂停,直接进行下次循环
{
continue;
}
BeginBatchDraw();
switch(a.m_game[s.head->m_x/10][s.head->m_y/10].ReturnFull()) //检测蛇头遇到的情况
{
case 2: //遇到食物,蛇身加长
a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
s.SnakeAdd(); //蛇增长
a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
a.DelFood(); //删除食物
if(a.CreatFood() == false) //创建新食物,并检查是否通关
{
game.WinGame(); //游戏通关(当地图没地方创建食物时)
}
manager.ScoreAdd(1); //加一分
break;
case 0:
a.m_game[s.last->m_x/10][s.last->m_y/10].setfull(0); //设置蛇尾经过处无障碍
a.ChangeColor(s.last->m_x/10,s.last->m_y/10,BLACK);
s.SnakeMove(); //蛇移动一次
a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
a.m_game[s.head->next->m_x/10][s.head->next->m_y/10].setfull(1); //设置蛇头经过处有障碍
break;
case 1: //遇到障碍物
game.FailGame();
a.ChangeColor(s.head->m_x/10,s.head->m_y/10,RGB(255,127,39));
FlushBatchDraw();
{
char c = ' ';
while(c != 'r' && c != 'R') //当游戏失败时,按R键可重新进行游戏
{
if(kbhit())
{
c = getch();
}
Sleep(10);
}
}
ReInit(); //重新开始游戏
break;
}
EndBatchDraw();
if(Keepdown==false)
{
Sleep(100);
manager.TimeAdd(0.1); //增加时间
}
else //当持续按下按方向键时
{
Sleep(40); //适当休眠可以增加游戏流畅性
manager.TimeAdd(0.04); //增加时间
}
}
}
////////////////////////////////////////////
//游戏初始化函数
////////////////////////////////////////////
void ReInit()
{
a.Init(); //初始化游戏区
s.Init(); //初始化蛇
manager.Init(); //初始化管理区
//绘制蛇的开始状态
s.now = s.head;
a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
s.now = s.last;
a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
}
////////////////////////////////////////////
//main函数,程序入口
////////////////////////////////////////////
int main(void)
{
game.Init(); //初始化游戏参数、设置
ReInit(); //初始化其他
MessageDispose(); //消息处理函数
?
return 0;
}?
大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在里面交流提问编程问题哦!
对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!
相关推荐
- 离谱!写了5年Vue,还不会自动化测试?
-
前言大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。Playwright是一个功能强大的端到...
- package.json 与 package-lock.json 的关系
-
模块化开发在前端越来越流行,使用node和npm可以很方便的下载管理项目所需的依赖模块。package.json用来描述项目及项目所依赖的模块信息。那package-lock.json和...
- Github 标星35k 的 SpringBoot整合acvtiviti开源分享,看完献上膝盖
-
前言activiti是目前比较流行的工作流框架,但是activiti学起来还是费劲,还是有点难度的,如何整合在线编辑器,如何和业务表单绑定,如何和系统权限绑定,这些问题都是要考虑到的,不是说纯粹的把a...
- Vue3 + TypeScript 前端研发模板仓库
-
我们把这个Vue3+TypeScript前端研发模板仓库的初始化脚本一次性补全到可直接运行的状态,包括:完整的目录结构所有配置文件研发规范文档示例功能模块(ExampleFeature)...
- Vue 2迁移Vue 3:从响应式到性能优化
-
小伙伴们注意啦!Vue2已经在2023年底正式停止维护,再不升级就要面临安全漏洞没人管的风险啦!而且Vue3带来的性能提升可不是一点点——渲染速度快40%,内存占用少一半,更新速度直接翻倍!还在...
- VUE学习笔记:声明式渲染详解,对比WEB与VUE
-
声明式渲染是指使用简洁的模板语法,声明式的方式将数据渲染进DOM系统。声明式是相对于编程式而言,声明式是面向对象的,告诉框架做什么,具体操作由框架完成。编程式是面向过程思想,需要手动编写代码完成具...
- 苏州web前端培训班, 苏州哪里有web前端工程师培训
-
前端+HTML5德学习内容:第一阶段:前端页面重构:PC端网站布局、HTML5+CSS3基础项目、WebAPP页面布局;第二阶段:高级程序设计:原生交互功能开发、面向对象开发与ES5/ES6、工具库...
- 跟我一起开发微信小程序——扩展组件的代码提示补全
-
用户自定义代码块步骤:1.HBuilderX中工具栏:工具-代码块设置-vue代码块2.通过“1”步骤打开设置文件...
- JimuReport 积木报表 v1.9.3发布,免费可视化报表
-
项目介绍积木报表JimuReport,是一款免费的数据可视化报表,含报表、大屏和仪表盘,像搭建积木一样完全在线设计!功能涵盖:数据报表、打印设计、图表报表、门户设计、大屏设计等!...
- 软开企服开源的无忧企业文档(V2.1.3)产品说明书
-
目录1....
- 一款面向 AI 的下一代富文本编辑器,已开源
-
简介AiEditor是一个面向AI的下一代富文本编辑器。开箱即用、支持所有前端框架、支持Markdown书写模式什么是AiEditor?AiEditor是一个面向AI的下一代富文本编辑...
- 玩转Markdown(2)——抽象语法树的提取与操纵
-
上一篇玩转Markdown——数据的分离存储与组件的原生渲染发布,转眼已经鸽了大半年了。最近在操纵mdast生成md文件的时候,心血来潮,把玩转Markdown(2)给补上了。...
- DeepseekR1+ollama+dify1.0.0搭建企业/个人知识库(入门避坑版)
-
找了网上的视频和相关文档看了之后,可能由于版本不对或文档格式不对,很容易走弯路,看完这一章,可以让你少踩三天的坑。步骤和注意事项我一一列出来:1,前提条件是在你的电脑上已配置好ollama,dify1...
- 升级JDK17的理由,核心是降低GC时间
-
升级前后对比升级方法...
- 一个vsCode格式化插件_vscode格式化插件缩进量
-
ESlint...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
【VueTorrent】一款吊炸天的qBittorrent主题,人人都可用
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)