当前位置:   article > 正文

C语言零基础项目:贪吃蛇!详细思路+源码分享_c贪吃蛇源码

c贪吃蛇源码

每天一个C语言小项目,提升你的编程能力!

贪吃蛇游戏大家应该都不陌生了,要说没玩过的话,可能你是15后吧?

贪吃蛇游戏最初为单机模式,后续又陆续推出团战模式、赏金模式、挑战模式等多种玩法。

用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。

贪吃蛇的唯一的目标就是长成最长的一条蛇!滑动摇杆控制小蛇走位,吃掉地图上彩色的小圆点,就会变长。

效果展示:

改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难。如果有编程技术比较强大的伙伴也可以去尝试一下哦!做出一个趋近完美的贪吃蛇那可就是能力的展现啦~

本项目编译环境:Visual Studio 2019/2022,EasyX插件

代码展示:

  1. #include <graphics.h>
  2. #include <stdio.h>
  3. #include <conio.h>
  4. #include <time.h>
  5. #define UP 1
  6. #define DOWN 2
  7. #define LEFT 3
  8. #define RIGHT 4
  9. //格子类,定义一个格子的属性及行为
  10. class Cell
  11. {
  12. public:
  13. friend class GameArea; //设置友元函数
  14. void setxy(short x, short y) //设置格子左上角坐标
  15. {
  16. m_x = x, m_y = y;
  17. }
  18. void setfull(short full) //设置格子属性,0为空,1为障碍,2为食物
  19. {
  20. m_full = full;
  21. }
  22. void display(COLORREF color) //设置格子颜色并显示
  23. {
  24. m_color = color;
  25. setfillstyle(m_color);
  26. bar(m_x, m_y, m_x+7, m_y+7);
  27. }
  28. void LaserDisplay() //显示镭射状态的格子
  29. {
  30. IMAGE image(10,10);
  31. SetWorkingImage(&image);
  32. DWORD* pMem = GetImageBuffer(&image);
  33. for(int i = 0; i < 10 * 10; i++)
  34. pMem[i] = BGR(RGB(0, 0, i * 256 / (10*10) ));
  35. SetWorkingImage(NULL);
  36. putimage(m_x,m_y,&image);
  37. }
  38. short ReturnFull() //返回格子状态
  39. {
  40. return m_full;
  41. }
  42. Cell() //构造函数
  43. {
  44. m_x = 0,m_y = 0,m_full = 0;
  45. m_color = BLACK;
  46. }
  47. private:
  48. short m_x; //格子的左上角X坐标
  49. short m_y; //格子的左上角Y坐标
  50. short m_full; //0为空,1为阻挡,2为食物
  51. COLORREF m_color; //格子颜色
  52. };
  53. //游戏区类,编写有关游戏区的一些操作
  54. class GameArea //游戏区域
  55. {
  56. public:
  57. Cell m_game[60][60]; //定义游戏区域(由360个格子组成)
  58. friend void MessageDispose(); //设置友元函数
  59. bool CreatFood() //产生随机食物
  60. {
  61. srand(time(NULL)); //初始化随机数种子
  62. m_random1 = rand()%58+1; //随机生成一个0 - 58的整数
  63. m_random2 = rand()%58+1; //随机一个0 - 58的整数
  64. if(m_game[m_random2][m_random2].m_full == 0) //检查生成的食物坐标是否在障碍上
  65. {
  66. m_game[m_random1][m_random2].display(GREEN);
  67. m_game[m_random1][m_random2].m_full = 2;
  68. return true;
  69. }
  70. //如果随机的食物正好出现在蛇身上,则进入下面的循环寻找可以生成食物的地方
  71. for(m_random1 = 1;m_random1 < 59;m_random1++)
  72. {
  73. for(m_random2 = 1;m_random2 < 59;m_random2++)
  74. {
  75. if(m_game[m_random2][m_random2].m_full == 0)
  76. {
  77. m_game[m_random1][m_random2].display(GREEN);
  78. m_game[m_random1][m_random2].m_full = 2;
  79. return true;
  80. }
  81. }
  82. }
  83. //如果没有找到可以生成食物的地方,则通关
  84. return false; //返回false即表示通关
  85. }
  86. void DelFood() //删除食物
  87. {
  88. m_game[m_random1][m_random2].m_full = 0; //设置为0即代表格子属性为空
  89. }
  90. void ChangeColor(int flag1,int flag2,COLORREF color) //设置指定格子的颜色
  91. {
  92. m_game[flag1][flag2].display(color);
  93. }
  94. void Init() //初始化GAME区域
  95. {
  96. int flag1,flag2; //标识变量
  97. BeginBatchDraw(); //开始批量绘图
  98. setfillstyle(BLACK); //设置当前颜色
  99. bar(0,0,600,600); //画无边框填充矩形(在这里的用途是用黑色清空游戏区域)
  100. for(flag1 = 0;flag1 < 60;flag1++)
  101. {
  102. for(flag2 = 0;flag2 < 60;flag2++)
  103. {
  104. if(flag1 == 0 || flag1 == 59 || flag2 == 0 || flag2 == 59) //创建边界
  105. {
  106. m_game[flag1][flag2].setfull(1);
  107. m_game[flag1][flag2].setxy(flag1*10,flag2*10);
  108. m_game[flag1][flag2].display(RGB(237,28,36));
  109. }
  110. else //创建游戏区域
  111. {
  112. m_game[flag1][flag2].setfull(0);
  113. m_game[flag1][flag2].setxy(flag1*10,flag2*10);
  114. m_game[flag1][flag2].display(BLACK);
  115. }
  116. }
  117. }
  118. CreatFood();
  119. EndBatchDraw();
  120. }
  121. private:
  122. int m_random1, m_random2;
  123. };
  124. //蛇类,定义蛇的数据结构以及蛇的行为
  125. class Snake
  126. {
  127. public:
  128. int toward; //蛇头朝向
  129. friend void MessageDispose();
  130. friend int HitDetect();
  131. friend void ReInit();
  132. Snake()
  133. {
  134. head = NULL;
  135. last = NULL;
  136. now = NULL;
  137. }
  138. void Init() //初始化蛇的结构
  139. {
  140. if(head!=NULL) //重玩游戏时,释放原先的链表所有结点
  141. {
  142. for(now = head->next;now->next != NULL;now = now->next)
  143. {
  144. free(now->prior);
  145. }
  146. }
  147. head = (struct node*)malloc(sizeof(struct node)); //为蛇头分配内存
  148. head->prior = NULL;
  149. head->m_x = 300;
  150. head->m_y = 300;
  151. now = (struct node*)malloc(sizeof(struct node));
  152. head->next = now;
  153. now->prior = head;
  154. now->next = NULL;
  155. now->m_x = 300;
  156. now->m_y = 290;
  157. last = now;
  158. toward = DOWN;
  159. }
  160. void SnakeAdd()
  161. {
  162. now = head; //当前指向蛇头
  163. now->prior = (struct node*)malloc(sizeof(struct node)); //为新增的结点分配内存
  164. now = now->prior; //让当前指向新分配的结点
  165. now->prior = NULL; //置空当前结点的前趋
  166. now->next = head; //让当前结点的后继指向蛇头
  167. switch(toward) //根据当前蛇头方向确定新增部分的坐标
  168. {
  169. case UP:
  170. now->m_x = head->m_x;
  171. now->m_y = head->m_y -10;
  172. break;
  173. case DOWN:
  174. now->m_x = head->m_x;
  175. now->m_y = head->m_y + 10;
  176. break;
  177. case LEFT:
  178. now->m_x = head->m_x - 10;
  179. now->m_y = head->m_y;
  180. break;
  181. case RIGHT:
  182. now->m_x = head->m_x + 10;
  183. now->m_y = head->m_y;
  184. break;
  185. }
  186. head = now; //设置当前结点为蛇头
  187. }
  188. void SnakeDel() //释放蛇尾结点(删除蛇尾)
  189. {
  190. last = last->prior;
  191. free(last->next);
  192. last->next = NULL;
  193. }
  194. void SnakeMove() //蛇身移动一格
  195. {
  196. SnakeAdd(); //增加蛇头
  197. SnakeDel(); //删除蛇尾
  198. }
  199. private:
  200. struct node //蛇身链表
  201. {
  202. int m_x;
  203. int m_y;
  204. struct node *next; //下个结点
  205. struct node *prior; //上个结点
  206. };
  207. struct node *head;
  208. struct node *last;
  209. struct node *now;
  210. };
  211. //游戏类,用来初始化游戏的参数,及实现其他游戏操作
  212. class Game
  213. {
  214. public:
  215. void Init()
  216. {
  217. closegraph();
  218. initgraph(800,600);
  219. setbkmode(TRANSPARENT); //设置输出文字背景为透明
  220. LOGFONT f;
  221. getfont(&f); // 获取当前字体设置
  222. f.lfHeight = 50; // 设置字体高度为 48(包含行距)
  223. _tcscpy(f.lfFaceName, _T("黑体")); // 设置字体为“黑体”
  224. f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
  225. setfont(&f); // 设置字体样式
  226. }
  227. void FailGame() //游戏失败显示的画面
  228. {
  229. setcolor(RED);
  230. setfont(70, 0, _T("微软雅黑"));
  231. outtextxy(150, 265, _T("YOU LOSE!"));
  232. }
  233. void WinGame() //游戏胜利时显示的画面
  234. {
  235. setcolor(RED);
  236. setfont(70, 0, _T("微软雅黑"));
  237. outtextxy(150, 265, _T("YOU WIN!"));
  238. FlushBatchDraw();
  239. Sleep(10000);
  240. exit(0);
  241. }
  242. };
  243. //管理区类,定义管理区域的相关操作
  244. class ManageArea
  245. {
  246. public:
  247. friend void MessageDispose();
  248. void TimeAdd(double add) //增加时间(可在类外直接调用实现动态刷新时间)
  249. {
  250. m_time += add;
  251. DisplayTime();
  252. }
  253. void ScoreAdd(short add) //增加分数(可在类外直接调用实现动态刷新分数)
  254. {
  255. m_score += add;
  256. DisplayScore();
  257. }
  258. void DisplayPause() //显示暂停或者开始
  259. {
  260. BeginBatchDraw();
  261. _stprintf(m_str_score, _T("%d"), m_score);
  262. setfont(25, 0, _T("微软雅黑"));
  263. setfillstyle(m_bgcolor);
  264. bar(625,490,800,515);
  265. setcolor(BLUE);
  266. if(m_pause)
  267. outtextxy(625, 490, _T("开始(P键)"));
  268. else
  269. outtextxy(625, 490, _T("暂停(P键)"));
  270. EndBatchDraw();
  271. }
  272. void Init() //初始化管理界面
  273. {
  274. m_time = 0.0;
  275. m_score = 0;
  276. m_leave = 1;
  277. m_pause = false;
  278. _stprintf(m_str_score, _T("%d"), m_score); //格式化转换类型
  279. _stprintf(m_str_time, _T("%.1lf"), m_time);
  280. m_bgcolor = BLACK;
  281. BeginBatchDraw();
  282. setfillstyle(BLACK);
  283. bar(601,0,800,600);
  284. setfont(60, 0, _T("微软雅黑"));
  285. setcolor(GREEN);
  286. outtextxy(625, 30, _T("贪吃蛇"));
  287. setfont(30, 0, _T("微软雅黑"));
  288. setcolor(RGB(128,0,255));
  289. outtextxy(625, 140, _T("制作:轻雨漫步"));
  290. setfont(25, 0, _T("微软雅黑"));
  291. setcolor(BLUE);
  292. outtextxy(625, 430, _T("时间:"));
  293. outtextxy(625, 460, _T("分数:"));
  294. outtextxy(625, 490, _T("暂停(P键)"));
  295. outtextxy(625, 520, _T("重新游戏(R键)"));
  296. setcolor(RED);
  297. outtextxy(720, 400, m_str_leave);
  298. outtextxy(680, 460, m_str_score);
  299. outtextxy(680, 430, m_str_time);
  300. EndBatchDraw();
  301. }
  302. private:
  303. double m_time;
  304. short m_score;
  305. short m_leave;
  306. bool m_pause;
  307. TCHAR m_str_leave[2], m_str_time[33], m_str_score[5];
  308. COLORREF m_bgcolor;
  309. void DisplayTime() //显示当前耗时
  310. {
  311. BeginBatchDraw();
  312. _stprintf(m_str_time, _T("%.1lf"), m_time);
  313. setfont(25, 0, _T("微软雅黑"));
  314. setfillstyle(m_bgcolor);
  315. bar(680,430,800,455);
  316. setcolor(RED);
  317. outtextxy(680,430,m_str_time);
  318. EndBatchDraw();
  319. }
  320. void DisplayScore() //显示当前分数
  321. {
  322. BeginBatchDraw();
  323. _stprintf(m_str_score, _T("%d"), m_score);
  324. setfont(25, 0, _T("微软雅黑"));
  325. setfillstyle(m_bgcolor);
  326. bar(680,460,800,485);
  327. setcolor(RED);
  328. outtextxy(680,460,m_str_score);
  329. EndBatchDraw();
  330. }
  331. };
  332. //声明游戏需要的类
  333. Game game; //用于初始化游戏、设置游戏相关参数
  334. GameArea a; //用于初始化游戏区域,设置,改变游戏区域相关参数
  335. ManageArea manager; //用于初始化管理区域,设置管理区相关参数
  336. Snake s; //用于初始化蛇,数据化蛇,操作蛇
  337. //游戏的消息控制,流程控制函数
  338. void MessageDispose() //消息处理函数
  339. {
  340. char c;
  341. s.now = NULL;
  342. bool Keepdown = false;
  343. while(true)
  344. {
  345. Keepdown = false; //是否持续按W A S D 中的一个按键
  346. if(kbhit())
  347. {
  348. switch(c = getch()) //处理按键消息(W A S D)
  349. {
  350. case 'w':
  351. case 'W':
  352. if(s.toward == UP)Keepdown = true;
  353. else if(s.toward != DOWN&&s.toward != UP)s.toward = UP;
  354. break;
  355. case 's':
  356. case 'S':
  357. if(s.toward == DOWN)Keepdown = true;
  358. else if(s.toward != UP&&s.toward != DOWN)s.toward = DOWN;
  359. break;
  360. case 'a':
  361. case 'A':
  362. if(s.toward == LEFT)Keepdown = true;
  363. else if(s.toward != RIGHT&&s.toward != LEFT)s.toward = LEFT;
  364. break;
  365. case 'd':
  366. case 'D':
  367. if(s.toward == RIGHT)Keepdown = true;
  368. else if(s.toward != LEFT&&s.toward != RIGHT)s.toward = RIGHT;
  369. break;
  370. case 'p':
  371. case 'P':
  372. manager.m_pause = !manager.m_pause; //设置暂停或开始
  373. manager.DisplayPause(); //显示暂停或开始
  374. break;
  375. case 'r':
  376. case 'R':
  377. ReInit();
  378. break;
  379. }
  380. }
  381. if(true == manager.m_pause) //如果暂停,直接进行下次循环
  382. {
  383. continue;
  384. }
  385. BeginBatchDraw();
  386. switch(a.m_game[s.head->m_x/10][s.head->m_y/10].ReturnFull()) //检测蛇头遇到的情况
  387. {
  388. case 2: //遇到食物,蛇身加长
  389. a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
  390. s.SnakeAdd(); //蛇增长
  391. a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
  392. a.DelFood(); //删除食物
  393. if(a.CreatFood() == false) //创建新食物,并检查是否通关
  394. {
  395. game.WinGame(); //游戏通关(当地图没地方创建食物时)
  396. }
  397. manager.ScoreAdd(1); //加一分
  398. break;
  399. case 0:
  400. a.m_game[s.last->m_x/10][s.last->m_y/10].setfull(0); //设置蛇尾经过处无障碍
  401. a.ChangeColor(s.last->m_x/10,s.last->m_y/10,BLACK);
  402. s.SnakeMove(); //蛇移动一次
  403. a.ChangeColor(s.head->m_x/10,s.head->m_y/10,BLUE);
  404. a.m_game[s.head->next->m_x/10][s.head->next->m_y/10].setfull(1); //设置蛇头经过处有障碍
  405. break;
  406. case 1: //遇到障碍物
  407. game.FailGame();
  408. a.ChangeColor(s.head->m_x/10,s.head->m_y/10,RGB(255,127,39));
  409. FlushBatchDraw();
  410. {
  411. char c = ' ';
  412. while(c != 'r' && c != 'R') //当游戏失败时,按R键可重新进行游戏
  413. {
  414. if(kbhit())
  415. {
  416. c = getch();
  417. }
  418. Sleep(10);
  419. }
  420. }
  421. ReInit(); //重新开始游戏
  422. break;
  423. }
  424. EndBatchDraw();
  425. if(Keepdown==false)
  426. {
  427. Sleep(100);
  428. manager.TimeAdd(0.1); //增加时间
  429. }
  430. else //当持续按下按方向键时
  431. {
  432. Sleep(40); //适当休眠可以增加游戏流畅性
  433. manager.TimeAdd(0.04); //增加时间
  434. }
  435. }
  436. }
  437. //游戏初始化函数
  438. void ReInit()
  439. {
  440. a.Init(); //初始化游戏区
  441. s.Init(); //初始化蛇
  442. manager.Init(); //初始化管理区
  443. //绘制蛇的开始状态
  444. s.now = s.head;
  445. a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
  446. s.now = s.last;
  447. a.ChangeColor(s.now->m_x/10,s.now->m_y/10,BLUE);
  448. }
  449. //main函数,程序入口
  450. int main(void)
  451. {
  452. game.Init(); //初始化游戏参数、设置
  453. ReInit(); //初始化其他
  454. MessageDispose(); //消息处理函数
  455. return 0;
  456. }​

大家赶紧去动手试试吧!

此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!(↓↓↓↓↓↓)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/372595
推荐阅读
相关标签
  

闽ICP备14008679号