小项目特供 贪吃蛇游戏(基于C语言)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小项目特供 贪吃蛇游戏(基于C语言)相关的知识,希望对你有一定的参考价值。

  C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次。

  是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第二天写了第二版和第三版。

  相信C语言写个小游戏或小项目是大多数计算机相关专业的学生都做的事情,但是作为一个数学专业的学生,我们教研室的老师对C语言的要求也就比较低了,大一没有让我们做个小项目实践一次。至今为止用C/C++做过的三个小项目(大作业),一个是外校同学让我帮忙写的学生信息管理系统(天呐,这名字都被大学用烂了...),一个是本校计院的同学让我帮忙写的链表设计的大作业,实话说,真的很无聊...

  最后一个小项目就是贪吃蛇了,比前两个有意思多了,强烈建议大学老师让学生做些简单的界面程序而非黑框框下的所谓管理系统....让学生体会到乐趣才是真谛啊。

 


 

  附:源码及游戏程序下载地址:贪吃蛇  访问密码 51b4

  


 

  

 第一版

  首先是第一版的源码奉上,因为没有学过MFC,这一版是借鉴了其他网站上的C语言贪吃蛇算法思路和图形写成的。

  我认为这里的贪吃蛇算法思路非常棒,虽然不知道这种算法的来由但是我对此算法创始人由衷敬佩...

    这里的算法思路其实是将图上每一个点的二维坐标转换成一维序列,然后通过一维序列映射地图上的每一个坐标

    最让我敬佩的地方就是在蛇头重绘的时候,这里的贪吃蛇移动地图上的二维坐标和原始地图的一维序列将随着蛇头的移动而不断发生交替改变,以适应贪吃蛇循环队列的算法要求。

  操作说明:WSAD控制方向。

  

技术分享
  1 #include <stdio.h>
  2 #include <ctype.h>
  3 #include <conio.h>
  4 #include <time.h>
  5 #include <windows.h>
  6 
  7 //背景宽-高
  8 #define HEIGHT 20
  9 #define WIDTH 20
 10 //地图中心
 11 #define XCENTER HEIGHT/2
 12 #define YCENTER WIDTH/2
 13 //最大蛇长
 14 #define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
 15 //坐标->编号
 16 #define NUM(x,y) ((x-1)*(WIDTH-2)+(y-1))
 17 
 18 //模型
 19 struct Model{
 20     char *ch;
 21     int color;
 22     char flag;
 23 }
 24 border = { "", 4, 1 },
 25 background = { "", 2, 2 },
 26 snakeHead = { "", 0xE, 3 },
 27 snakeBody = { "", 0xE, 3 },
 28 food = { "", 0xC, 4 };
 29 
 30 int snakeLen = 3;    //贪吃蛇长度
 31 
 32 //地图
 33 struct Map {
 34     int flag;    //模型标识
 35     int num;    //坐标编号
 36 }map[WIDTH][HEIGHT];
 37 
 38 //坐标
 39 //贪吃蛇移动范围(循环队列),分数位置
 40 struct Coordinate{
 41     int x, y;
 42 }snake[SNAKE_MAXLEN], scorePos;
 43 
 44 
 45 int score;    //分数
 46 int header, tail;    //蛇头蛇尾下标
 47 HANDLE hConsole;
 48 
 49 void setCursor(int x, int y)
 50 {
 51     //参数x为行,y为列-与光标设置相反
 52     COORD coord;
 53     coord.X = 2*y;    //宽字符决定占两列
 54     coord.Y = x;
 55     SetConsoleCursorPosition(hConsole, coord);
 56 }
 57 
 58 void setColor(int color)
 59 {
 60     SetConsoleTextAttribute(hConsole, color);
 61 }
 62 
 63 //随机生成食物
 64 void createFood()
 65 {
 66     int num;    //新食物对应的坐标编号
 67     int range;    //新食物所在范围
 68     srand((unsigned)time(NULL));    //初始种子
 69     range = SNAKE_MAXLEN - snakeLen;    //食物生成范围
 70     if (tail < header)
 71         num = rand() % range + tail + 1;
 72     else {
 73         num = rand() % range;
 74         if (num >= header)
 75             num += snakeLen;
 76     }
 77     //绘制食物
 78     int tx = snake[num].x;
 79     int ty = snake[num].y;
 80     setCursor(tx, ty);
 81     setColor(food.color);
 82     printf("%s", food.ch);
 83     map[tx][ty].flag = food.flag;
 84 }
 85 
 86 //游戏结束
 87 void gameOver()
 88 {
 89     setCursor(XCENTER, YCENTER - 4);
 90     setColor(0xC);
 91     
 92     printf("Game Over!");
 93     getch();
 94     exit(0);    //结束程序
 95 }
 96 
 97 void move(char direction)
 98 {
 99     //新蛇头
100     int tx = snake[header].x;
101     int ty = snake[header].y;
102     switch (direction) 
103     {
104         case w:
105             tx--; break;
106         case s:
107             tx++; break;
108         case a:
109             ty--; break;
110         case d:
111             ty++; break;
112     }
113 
114     //判断是否会出界或撞到自己
115     if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
116         gameOver();
117 
118     //新蛇头绘制(此时未refresh模型标识)
119     setCursor(tx, ty);
120     setColor(snakeHead.color);
121     printf("%s", snakeHead.ch);    
122     //原蛇头重绘制
123     setCursor(snake[header].x, snake[header].y);
124     printf("%s", snakeBody.ch);    //小方块
125 
126     //蛇头更新-队首移动
127     header = header == 0 ? SNAKE_MAXLEN - 1 : header - 1;
128     //旧编号位置更正
129     int preNum = map[tx][ty].num;    //蛇头位置旧编号
130     snake[preNum].x = snake[header].x;
131     snake[preNum].y = snake[header].y;
132     map[snake[preNum].x][snake[preNum].y].num = preNum;
133     //蛇头位置更正
134     snake[header].x = tx;
135     snake[header].y = ty;
136     map[tx][ty].num = header;    //蛇头位置新编号
137 
138     //判断是否吃到食物
139     if (map[tx][ty].flag == food.flag)
140     {
141         createFood();    //随机生成食物
142         snakeLen++;    //蛇身加长
143         //更新-score
144         setCursor(scorePos.x, scorePos.y);
145         printf("%d", ++score);
146     }
147     else {    
148         //删除蛇尾
149         setCursor(snake[tail].x, snake[tail].y);
150         map[snake[tail].x][snake[tail].y].flag = background.flag;
151         setColor(background.color);
152         printf("%s", background.ch);
153         tail = tail == 0 ? SNAKE_MAXLEN - 1 : tail - 1;
154     }
155 
156     //更新-蛇头模型标识
157     map[tx][ty].flag = snakeBody.flag;
158 }
159 
160 //初始化界面
161 void init() 
162 {
163     CONSOLE_CURSOR_INFO cci;    //光标信息
164     header = 0;
165     tail = snakeLen - 1;
166 
167     //设置光标不可见
168     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
169     GetConsoleCursorInfo(hConsole, &cci);
170     cci.bVisible = 0;
171     SetConsoleCursorInfo(hConsole, &cci);
172 
173     //dos命令设置窗口大小
174     system("mode con:cols=100 lines=32");
175 
176     //绘制背景
177     for (int x = 0; x < HEIGHT; x++)
178     {
179         for (int y = 0; y < WIDTH; y++)
180         {
181             if (x == 0 || y == 0 || x == HEIGHT - 1 || y == WIDTH - 1)
182             {
183                 map[x][y].flag = border.flag;
184                 setColor(border.color);
185                 printf("%s", border.ch);
186             }
187             else {
188                 int num = NUM(x,y);
189                 snake[num].x = x;
190                 snake[num].y = y;
191                 //背景设置
192                 map[x][y].num = num;
193                 map[x][y].flag = background.flag;
194                 setColor(background.color);
195                 printf("%s", background.ch);
196             }
197         }
198         printf("\\n");
199     }
200 
201     //绘制初始贪吃蛇
202     setCursor(XCENTER, YCENTER - snakeLen / 2);
203     header = NUM(XCENTER, YCENTER - 1);    //蛇头位置
204     tail = header + snakeLen - 1;
205     setColor(snakeBody.color);
206     for (int i = header; i <= tail; i++)
207     {
208         if (i == header) printf("%s", snakeHead.ch);
209         else printf("%s", snakeBody.ch);
210         map[snake[i].x][snake[i].y].flag = snakeBody.flag;
211     }
212 
213     //随机生成食物
214     createFood();
215 
216     //其他信息
217     setCursor(XCENTER - 1, WIDTH + 2);
218     printf("   score: 0");
219     setCursor(XCENTER, WIDTH + 2);
220     printf("   Author: InkMark");
221     setCursor(XCENTER + 1, WIDTH + 2);
222     printf("   Blog: www.cnblogs.com/inkblots");
223     //分数位置
224     scorePos.x = XCENTER - 1;
225     scorePos.y = WIDTH + 7;
226 }
227 
228 
229 int main()
230 {
231     //方向及其他初始化
232     char direction = a;
233     init();
234     
235     char ch = tolower(getch());
236     if (ch == a || ch == w || ch == s)
237         direction = ch;
238 
239     while (1) {
240         if (kbhit()) {
241             ch = tolower(getch());
242             if (ch ==  )
243                 ch = getch();    //实现空格-暂停
244             if(ch == a || ch == d || ch == w || ch==s)
245                 if (ch + direction != 234 && ch + direction != 197)
246                     direction = ch;    //不为反向时改变方向
247         }
248         move(direction);
249         Sleep(500);
250     }
251 
252     return 0;
253 }
= 。=

 

  


 

 

  第二版:

  第二版在第一版的算法基础上改进了图形界面和源码管理,新增了“加速”技能(比较方便实现)。

  控制方向也改为方向键了。

 

  第二版源码分为三个文件,运行源码需要链接一次。

  先是一个头文件,定义了要用到的库文件,常用常量和结构体,以及声明main中要用到的函数

  

技术分享
 1 #ifndef CATALOG_H
 2 #define CATALOG_H
 3 
 4 #include<stdio.h>
 5 #include<conio.h>
 6 #include<time.h>
 7 #include<windows.h>
 8 
 9 //背景上下伸展长度
10 #define TOP_EXTEND 3
11 #define BOTTOM_EXTEND 3
12 //背景宽-高
13 #define WIDTH 33
14 #define HEIGHT 20
15 //地图中心
16 #define XCENTER ((HEIGHT + 1)/2 + TOP_EXTEND)
17 #define YCENTER (WIDTH + 1)/2
18 //最大蛇长
19 #define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
20 //坐标->序号
21 #define ORDER(x,y) ((x - TOP_EXTEND - 1) * (WIDTH - 2) + (y - 1))
22 //点:在移动范围内
23 #define IN_RANGE(x,y) (x > TOP_EXTEND && x < HEIGHT + TOP_EXTEND - 1 && y > 0 && y < WIDTH - 1)
24 //默认暂停时间
25 #define PAUSE_TIME 500
26 
27 /*全局变量*/
28 extern int snakeLen;
29 extern int direction;
30 extern int header, tail;
31 extern int score;
32 extern int skill;
33 extern int pauseTime;
34 extern HANDLE hConsole;
35 
36 //模型
37 typedef struct Model {
38     char *ch;
39     int color;
40     int flag;
41 }Model;
42 
43 //地图
44 typedef struct Map {
45     int flag;    //模型标识
46     int order;    //序号
47 }Map;
48 
49 //坐标
50 //贪吃蛇移动范围(循环队列),分数位置
51 typedef struct Coordinate {
52     int x, y;
53 }Coordinate;
54 
55 
56 /******界面设定******/
57 
58 void setCursor(int x, int y);
59 
60 void setColor(int color);
61 
62 void control(char ch);
63 
64 /******框架及功能******/
65 
66 void init();
67 
68 int move(char direction);
69 
70 void createFood();
71 
72 
73 #endif
catalog.h

 

  第二个是功能部分源码

 

技术分享
  1 #include "catalog.h"
  2 
  3 Model    border = { NULL, 0x7, 1 },
  4 snakeHead = { "", 0xE, 2 },
  5 snakeBody = { "", 0xE, 2 },
  6 food = { "", 0xC, 3 };
  7 
  8 Map map[HEIGHT][WIDTH];
  9 
 10 Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
 11 
 12 /************游戏界面设定************/
 13 
 14 //隐藏光标
 15 void hideCursor()
 16 {
 17     CONSOLE_CURSOR_INFO cci;    //光标信息
 18     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 19     GetConsoleCursorInfo(hConsole, &cci);
 20     cci.bVisible = 0;
 21     SetConsoleCursorInfo(hConsole, &cci);
 22 }
 23 
 24 //设置光标位置
 25 void setCursor(int x, int y)
 26 {
 27     //参数x为行,y为列-与光标设置相反
 28     COORD coord;
 29     coord.X = 2 * y;    //宽字符决定占两列
 30     coord.Y = x;
 31     SetConsoleCursorPosition(hConsole, coord);
 32 }
 33 
 34 //设置文字颜色
 35 void setColor(int color)
 36 {
 37     SetConsoleTextAttribute(hConsole, color);
 38 }
 39 
 40 //绘制游戏窗口(包括dos环境初始窗口)
 41 void createWindow()
 42 {
 43     //dos命令设置窗口大小
 44     system("mode con:cols=72 lines=27");
 45 
 46     //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
 47     setColor(0x7);
 48     printf("╔════════════════╦════════════════╗\\n");    //0~34
 49     for (int i = 1; i < TOP_EXTEND; i++)
 50         printf("║                                ║                                ║\\n");
 51     printf("╠════════════════╩════════════════╣\\n");
 52     for (int i = 1; i < HEIGHT - 1; i++)
 53         printf("║                                                                  ║\\n");
 54     printf("╠═════════════════════════════════╣\\n");
 55     for (int i = 1; i < BOTTOM_EXTEND; i++)
 56         printf("║                                                                  ║\\n");
 57     printf("╚═════════════════════════════════╝\\n");
 58     setCursor(HEIGHT + TOP_EXTEND, 1);
 59     printf(" 操作指南:方向键控制,空格可暂停,5分后可获得技能.");
 60     setCursor(HEIGHT + TOP_EXTEND + 1, 1);
 61     printf(" Version : 2.0");
 62 
 63     for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
 64     {
 65         for (int y = 0; y < WIDTH; y++)
 66             if (IN_RANGE(x, y))
 67             {
 68                 int order = ORDER(x, y);
 69                 snake[order].x = x;
 70                 snake[order].y = y;
 71                 //背景设置
 72                 map[x][y].order = order;
 73                 map[x][y].flag = 0;
 74             }
 75             else map[x][y].flag = border.flag;
 76     }
 77     //其他信息
 78     setColor(0x7);
 79     setCursor(1, 1);
 80     printf("          你的分数:0");
 81     setCursor(2, 1);
 82     printf("          技能:无");
 83     setCursor(1, YCENTER + 1);
 84     printf("        Author: InkMark");
 85     setCursor(2, YCENTER + 1);
 86     printf(" Blog: www.cnblogs.com/inkblots");
 87 
 88     //分数位置
 89     scorePos.x = 1; scorePos.y = 11;
 90     skillPos.x = 2; skillPos.y = 9;
 91 }
 92 
 93 //控制键
 94 void control(char ch)
 95 {
 96     //本应取方向键高位再取低位,在此以简便为主
 97     if (ch != -32) return;
 98     ch = getch();
 99     //上72下80左75右77
100     if (ch == 72 || ch == 80 || ch == 75 || ch == 77)    //低位相同
101         if (ch + direction != 152) direction = ch;    //不为反向时改变方向
102 }
103 
104 /************游戏信息输出************/
105 
106 void getSkill()
107 {
108     setCursor(skillPos.x, skillPos.y);
109     printf("加速(S键)");
110     skill = 1;    //加速技能开启
111 }
112 
113 void alterScore(int addition)
114 {
115     score += addition;
116     if (score >= 5)

以上是关于小项目特供 贪吃蛇游戏(基于C语言)的主要内容,如果未能解决你的问题,请参考以下文章

C语言项目:贪吃蛇游戏(双人模式),详细思路+源码分享

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

C语言实现贪吃蛇小游戏!(超简单详细)详细思路+源码分享

C语言贪吃蛇

C语言项目贪吃蛇游戏(下)

C语言课程设计,贪吃蛇应该怎么做?