小项目特供 贪吃蛇游戏(基于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)
117         getSkill();
118     setCursor(scorePos.x, scorePos.y);
119     setColor(0x7);
120     printf("%d", score);
121 }
122
123 void gameOver()
124 {
125     if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
126     {
127         system("CLS");
128         return;
129     }
130
131     exit(0);
132 }
133
134 /************游戏框架及功能************/
135
136 //变量初始化及界面初始化
137 void init()
138 {
139     pauseTime = PAUSE_TIME;
140     skill = 0;
141     score = 0;
142     snakeLen = 1;
143     header = 0;
144     tail = snakeLen - 1;
145
146     hideCursor();//隐藏光标
147     createWindow();    //绘制背景
148 }
149
150 //贪吃蛇移动
151 //return:1为成功,0为失败
152 int move(char direction)
153 {
154     //新蛇头
155     int tx = snake[header].x;
156     int ty = snake[header].y;
157     //上72下80左75右77
158     switch (direction)
159     {
160         case 72: tx--; break;
161         case 80: tx++; break;
162         case 75: ty--; break;
163         case 77: ty++; break;
164     }
165
166     //判断是否撞墙或撞到自己
167     if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
168     {
169         gameOver();
170         return 0;
171     }
172
173     //新蛇头绘制(此时未refresh模型标识)
174     setCursor(tx, ty);
175     setColor(snakeHead.color);
176     printf("%s", snakeHead.ch);
177     //原蛇头重绘制
178     setCursor(snake[header].x, snake[header].y);
179     printf("%s", snakeBody.ch);
180
181     //蛇头更新-队首移动
182     header = header == 0 ? SNAKE_MAXLEN - 1 : header - 1;
183     //旧编号位置更正
184     int preNum = map[tx][ty].order;    //蛇头位置旧编号
185     snake[preNum].x = snake[header].x;
186     snake[preNum].y = snake[header].y;
187     map[snake[preNum].x][snake[preNum].y].order = preNum;
188     //蛇头位置更正
189     snake[header].x = tx;
190     snake[header].y = ty;
191     map[tx][ty].order = header;    //蛇头位置新编号
192
193     //判断是否吃到食物
194     if (map[tx][ty].flag == food.flag)
195     {
196         snakeLen++;    //蛇身加长
197         createFood();    //随机生成食物
198         //更新-score
199         alterScore(1);
200     }
201     else {
202         //删除蛇尾
203         setCursor(snake[tail].x, snake[tail].y);
204         map[snake[tail].x][snake[tail].y].flag = 0;
205         printf(" ");
206         tail = tail == 0 ? SNAKE_MAXLEN - 1 : tail - 1;
207     }
208
209     //更新-蛇头模型标识
210     map[tx][ty].flag = snakeBody.flag;
211
212     return 1;
213 }
214
215 //随机生成食物
216 void createFood()
217 {
218     int order;    //新食物对应的坐标编号
219     int range;    //新食物所在范围
220     srand((unsigned)time(NULL));    //初始种子
221     range = SNAKE_MAXLEN - snakeLen;    //食物生成范围
222     if (tail < header)
223         order = rand() % range + tail + 1;
224     else {
225         order = rand() % range;
226         if (order >= header)
227             order += snakeLen;
228     }
229     //绘制食物
230     int tx = snake[order].x;
231     int ty = snake[order].y;
232     setCursor(tx, ty);
233     setColor(food.color);
234     printf("%s", food.ch);
235     map[tx][ty].flag = food.flag;
236 }

Util.c

  第三个是主函数及初始化部分

 1 #include "catalog.h"
 2
 3 int snakeLen;    //贪吃蛇长度
 4 int direction;    //贪吃蛇移动方向
 5 int header, tail;    //蛇头蛇尾下标
 6 int score;    //分数
 7 int skill;    //技能开关
 8 int pauseTime;    //暂停时间(Ms)
 9 HANDLE hConsole;
10
11 extern Model border, snakeHead, snakeBody, food;
12 extern Map map[HEIGHT][WIDTH];
13 extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
14
15 //初始化方案
16 void scheme()
17 {
18     //变量初始化及界面初始化
19     init();
20
21     //绘制初始贪吃蛇
22     setCursor(XCENTER, YCENTER - snakeLen / 2);
23     header = ORDER(XCENTER, YCENTER - snakeLen / 2);    //蛇头位置
24     tail = header + snakeLen - 1;
25     setColor(snakeBody.color);
26     for (int i = header; i <= tail; i++)
27     {
28         if (i == header) printf("%s", snakeHead.ch);
29         else printf("%s", snakeBody.ch);
30         map[snake[i].x][snake[i].y].flag = snakeBody.flag;
31     }
32
33     //随机生成食物
34     createFood();
35
36     //初始方向处理
37     direction = 75;
38     char ch = getch();
39     control(ch);
40 }
41
42
43 int main()
44 {
45     //初始方案
46     scheme();
47
48     while (1) {
49         if (kbhit()) {
50             char ch = getch();
51             if (ch == ‘ ‘) MessageBox(NULL, "           暂停中...\n  请单击确定继续游戏", "暂停游戏", MB_OK);
52             if (skill == 1 && (ch == ‘s‘ || ch == ‘S‘))
53                 pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / 2 : PAUSE_TIME;
54             else control(ch);    //控制方向
55         }
56         if (move(direction))
57             Sleep(pauseTime);
58         else scheme();
59     }
60
61     return 0;
62 }

SnakeMain.c



第三版:

  第三版加入了菜单,优化了部分界面,并将游戏分为两个基本模式。

  

  和第二版一样,分为三个文件

  头文件:

  

 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 int mode;
35 extern HANDLE hConsole;
36
37 //模型
38 typedef struct Model {
39     char *ch;
40     int color;
41     int flag;
42 }Model;
43
44 //地图
45 typedef struct Map {
46     int flag;    //模型标识
47     int order;    //序号
48 }Map;
49
50 //坐标
51 //贪吃蛇移动范围(循环队列),分数位置
52 typedef struct Coordinate {
53     int x, y;
54 }Coordinate;
55
56
57 /******界面设定******/
58
59 extern void setCursor(int x, int y);
60
61 extern void setColor(int color);
62
63 extern void control(char ch);
64
65 /******框架及功能******/
66
67 extern void init();
68
69 extern int move(char direction);
70
71 extern void createFood();
72
73
74 #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, dotPos;
 11
 12 #define UP 4    //向上偏移量
 13 #define LEFT 6    //左移偏移量
 14
 15 /************游戏界面设定************/
 16
 17 //隐藏光标
 18 void hideCursor()
 19 {
 20     CONSOLE_CURSOR_INFO cci;    //光标信息
 21     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 22     GetConsoleCursorInfo(hConsole, &cci);
 23     cci.bVisible = 0;
 24     SetConsoleCursorInfo(hConsole, &cci);
 25 }
 26
 27 //设置光标位置
 28 void setCursor(int x, int y)
 29 {
 30     //参数x为行,y为列-与光标设置相反
 31     COORD coord;
 32     coord.X = 2 * y;    //宽字符决定占两列
 33     coord.Y = x;
 34     SetConsoleCursorPosition(hConsole, coord);
 35 }
 36
 37 //设置文字颜色
 38 void setColor(int color)
 39 {
 40     SetConsoleTextAttribute(hConsole, color);
 41 }
 42
 43 //绘制游戏窗口(包括dos环境初始窗口)
 44 void createWindow()
 45 {
 46     //dos命令设置窗口大小
 47     system("mode con:cols=72 lines=28");
 48
 49     //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
 50     setColor(0x7);
 51     printf("╔════════════════╦════════════════╗\n");    //0~34
 52     for (int i = 1; i < TOP_EXTEND; i++)
 53         printf("║                                ║                                ║\n");
 54     printf("╠════════════════╩════════════════╣\n");
 55     for (int i = 1; i < HEIGHT - 1; i++)
 56         printf("║                                                                  ║\n");
 57     printf("╠═════════════════════════════════╣\n");
 58     for (int i = 1; i < BOTTOM_EXTEND; i++)
 59         printf("║                                                                  ║\n");
 60     printf("╚═════════════════════════════════╝\n");
 61     setCursor(HEIGHT + TOP_EXTEND, 1);
 62     printf(" 操作指南:上下键及回车键选择.");
 63     setCursor(HEIGHT + TOP_EXTEND + 1, 1);
 64     printf(" Version : 3.0");
 65
 66     for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
 67     {
 68         for (int y = 0; y < WIDTH; y++)
 69             if (IN_RANGE(x, y))
 70             {
 71                 int order = ORDER(x, y);
 72                 snake[order].x = x;
 73                 snake[order].y = y;
 74                 //背景设置
 75                 map[x][y].order = order;
 76                 map[x][y].flag = 0;
 77             }
 78             else map[x][y].flag = border.flag;
 79     }
 80     //其他信息
 81     setColor(0x7);
 82     setCursor(1, 1);
 83     printf("          你的分数:0");
 84     setCursor(2, 1);
 85     printf("          技能:无");
 86     setCursor(1, YCENTER + 1);
 87     printf("        Author: InkMark");
 88     setCursor(2, YCENTER + 1);
 89     printf(" Blog: www.cnblogs.com/inkblots");
 90
 91     //分数位置
 92     scorePos.x = 1; scorePos.y = 11;
 93     skillPos.x = 2; skillPos.y = 9;
 94 }
 95
 96 void menuButton(char ch)
 97 {
 98     int tx = dotPos.x;
 99     int ty = dotPos.y;
100     if (ch == 72)    tx--;
101     else tx++;
102
103     if (tx > XCENTER - UP && tx < XCENTER - UP + 4)
104     {
105         setCursor(dotPos.x, dotPos.y);
106         printf(" ");
107         setCursor(tx, ty);
108         printf("●");
109         dotPos.x = tx;
110         dotPos.y = ty;
111     }
112 }
113
114 //绘制菜单并进行选择
115 void menu()
116 {
117     //╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
118     setCursor(XCENTER - UP, YCENTER - LEFT);
119     printf("╔═════════╗");    //11
120     for (int i = 1; i <= 3; i++)
121     {
122         setCursor(XCENTER - UP + i, YCENTER - LEFT);
123         printf("║                  ║");
124     }
125     setCursor(XCENTER - UP + 4, YCENTER - LEFT);
126     printf("╚═════════╝");
127
128     dotPos.x = XCENTER - UP + 1;
129     dotPos.y = YCENTER - 4;
130     setCursor(dotPos.x, dotPos.y);
131     printf("●  1.死亡模式");
132     setCursor(XCENTER - UP + 2, YCENTER - 2);
133     printf("2.技能模式");
134     setCursor(XCENTER - UP + 3, YCENTER - 2);
135     printf("3.退出游戏");
136
137     char ch;
138     while ((ch = getch()) != 13)    //确定键:13
139     {
140         if (ch != -32) continue;
141         ch = getch();
142         if (ch == 72 || ch == 80)
143             menuButton(ch);
144     }
145
146     for (int i = 0; i < 5; i++)
147     {
148         setCursor(XCENTER - UP + i, YCENTER - LEFT);
149         printf("                      ");
150     }
151
152     mode = dotPos.x - XCENTER + UP;
153     if (mode == 3) exit(0);
154 }
155
156 //控制键
157 void control(char ch)
158 {
159     //本应取方向键高位再取低位,在此以简便为主
160     if (ch != -32) return;
161     ch = getch();
162     //上72下80左75右77
163     if (ch == 72 || ch == 80 || ch == 75 || ch == 77)    //低位相同
164         if (ch + direction != 152)
165             direction = ch;    //不为反向时改变方向
166 }
167
168 /************游戏信息输出************/
169
170 void getSkill()
171 {
172     setCursor(skillPos.x, skillPos.y);
173     printf("加速(S键)");
174     skill = 1;    //加速技能开启
175 }
176
177 void alterScore(int addition)
178 {
179     score += addition;
180     if (mode == 2 && score >= 8)
181         getSkill();
182     setCursor(scorePos.x, scorePos.y);
183     setColor(0x7);
184     printf("%d", score);
185 }
186
187 void printInfo()
188 {
189     //╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
190     int col = 28;
191     setCursor(HEIGHT + TOP_EXTEND - 1, col);
192     printf("╦");
193     setCursor(HEIGHT + TOP_EXTEND, col);
194     printf("║");
195     setCursor(HEIGHT + TOP_EXTEND + 1, col);
196     printf("║  模 式");
197     if (mode == 1) {
198
199         setCursor(HEIGHT + TOP_EXTEND, 1);
200         printf(" 操作指南:方向键控制,空格可暂停.");
201         setCursor(HEIGHT + TOP_EXTEND, col + 1);
202         printf("  无 尽");
203     }
204     else {
205         setCursor(HEIGHT + TOP_EXTEND, 1);
206         printf(" 操作指南:方向键控制,空格可暂停,8分后有惊喜.");
207         setCursor(HEIGHT + TOP_EXTEND, col + 1);
208         printf("  技 能");
209     }
210     setCursor(HEIGHT + TOP_EXTEND + 2, col);
211     printf("╩");
212 }
213
214 void gameOver()
215 {
216     if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
217     {
218         system("CLS");
219         return;
220     }
221
222     exit(0);
223 }
224
225 /************游戏框架及功能************/
226
227 //变量初始化及界面初始化
228 void init()
229 {
230     pauseTime = PAUSE_TIME;
231     skill = 0;
232     score = 0;
233     snakeLen = 1;
234     header = 0;
235     tail = snakeLen - 1;
236
237     hideCursor();//隐藏光标
238     createWindow();    //绘制背景
239
240     menu();    //菜单操作
241
242     printInfo();
243 }
244
245 //贪吃蛇移动
246 //return:1为成功,0为失败
247 int move(char direction)
248 {
249     //新蛇头
250     int tx = snake[header].x;
251     int ty = snake[header].y;
252     //上72下80左75右77
253     switch (direction)
254     {
255         case 72: tx--; break;
256         case 80: tx++; break;
257         case 75: ty--; break;
258         case 77: ty++; break;
259     }
260
261     //判断是否撞墙或撞到自己
262     if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
263     {
264         gameOver();
265         return 0;
266     }
267
268     //新蛇头绘制(此时未refresh模型标识)
269     setCursor(tx, ty);
270     setColor(snakeHead.color);
271     printf("%s", snakeHead.ch);
272     //原蛇头重绘制
273     setCursor(snake[header].x, snake[header].y);
274     printf("%s", snakeBody.ch);
275
276     //蛇头更新-队首移动
277     header = header == 0 ? SNAKE_MAXLEN - 1 : header - 1;
278     //旧编号位置更正
279     int preNum = map[tx][ty].order;    //蛇头位置旧编号
280     snake[preNum].x = snake[header].x;
281     snake[preNum].y = snake[header].y;
282     map[snake[preNum].x][snake[preNum].y].order = preNum;
283     //蛇头位置更正
284     snake[header].x = tx;
285     snake[header].y = ty;
286     map[tx][ty].order = header;    //蛇头位置新编号
287
288     //判断是否吃到食物
289     if (map[tx][ty].flag == food.flag)
290     {
291         snakeLen++;    //蛇身加长
292         createFood();    //随机生成食物
293         //更新-score
294         if(pauseTime == PAUSE_TIME) alterScore(1);
295         else alterScore(2);
296     }
297     else {
298         //删除蛇尾
299         setCursor(snake[tail].x, snake[tail].y);
300         map[snake[tail].x][snake[tail].y].flag = 0;
301         printf(" ");
302         tail = tail == 0 ? SNAKE_MAXLEN - 1 : tail - 1;
303     }
304
305     //更新-蛇头模型标识
306     map[tx][ty].flag = snakeBody.flag;
307
308     return 1;
309 }
310
311 //随机生成食物
312 void createFood()
313 {
314     int order;    //新食物对应的坐标编号
315     int range;    //新食物所在范围
316     srand((unsigned)time(NULL));    //初始种子
317     range = SNAKE_MAXLEN - snakeLen;    //食物生成范围
318     if (tail < header)
319         order = rand() % range + tail + 1;
320     else {
321         order = rand() % range;
322         if (order >= header)
323             order += snakeLen;
324     }
325     //绘制食物
326     int tx = snake[order].x;
327     int ty = snake[order].y;
328     setCursor(tx, ty);
329     setColor(food.color);
330     printf("%s", food.ch);
331     map[tx][ty].flag = food.flag;
332 }

Util.c

  主文件:

 

 1 #include "catalog.h"
 2
 3 int snakeLen;    //贪吃蛇长度
 4 int direction;    //贪吃蛇移动方向
 5 int header, tail;    //蛇头蛇尾下标
 6 int score;    //分数
 7 int skill;    //技能开关
 8 int pauseTime;    //暂停时间(Ms)
 9 int mode;
10 HANDLE hConsole;
11
12 extern Model border, snakeHead, snakeBody, food;
13 extern Map map[HEIGHT][WIDTH];
14 extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos;
15
16 //初始化方案
17 void scheme()
18 {
19     //变量初始化及界面初始化
20     init();
21
22     //绘制初始贪吃蛇
23     setCursor(XCENTER, YCENTER - snakeLen / 2);
24     header = ORDER(XCENTER, YCENTER - snakeLen / 2);    //蛇头位置
25     tail = header + snakeLen - 1;
26     setColor(snakeBody.color);
27     for (int i = header; i <= tail; i++)
28     {
29         if (i == header) printf("%s", snakeHead.ch);
30         else printf("%s", snakeBody.ch);
31         map[snake[i].x][snake[i].y].flag = snakeBody.flag;
32     }
33
34     //随机生成食物
35     createFood();
36
37     //初始方向处理
38     direction = 75;
39     char ch = getch();
40     control(ch);
41 }
42
43
44 int main()
45 {
46     //初始方案
47     scheme();
48
49     while (1) {
50         if (kbhit()) {
51             char ch = getch();
52             if (ch == ‘ ‘) MessageBox(NULL, "           暂停中...\n  请单击确定继续游戏", "暂停游戏", MB_OK);
53             if (mode == 2 && skill == 1 && (ch == ‘s‘ || ch == ‘S‘))
54                 pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / 2 : PAUSE_TIME;
55             else control(ch);    //控制方向
56         }
57         if (move(direction))
58             Sleep(pauseTime);
59         else scheme();
60     }
61
62     return 0;
63 }

SnakeMain.c

时间: 2024-10-05 13:20:39

小项目特供 贪吃蛇游戏(基于C语言)的相关文章

基于控制台实现贪吃蛇游戏

1).引言 学习编程,我个人觉得最好的办法就是根据自己的水平不断的给自己设定一个小目标.而这个小目标就是一个有意思的项目,通过完成这个项目,对自己的成果(也包括失败的)进行分析总结,从中提炼出对应的技术并分享出来,不断的往复,如此,为的就是让我们永远保持编写程序的兴趣和热情,完了,还提高我们的技术.而本文就是总结自己的一个小目标(基于控制台实现的贪吃蛇游戏而写的总结) 2).技术实现 大家小时候一定玩过贪吃蛇的游戏.贪吃蛇游戏的控制过程其实也不复杂.简单的可以概括为以下4个部分. 1.1  .组

小项目特供 简易迷宫(基于Java)

明天返校,于是昨天和今天简单熟系了一下JAVA的GUI,做了一个简易的迷宫小游戏(暂时没有时间实现随机迷宫及多关卡,仅供学习) 源码及运行文件(提供JRE8):简易迷宫  访问密码 8dd8 小项目特供 简易迷宫(基于Java)

结对-贪吃蛇游戏-结对项目总结

结对-贪吃蛇游戏-结对项目总结 1.编写目的 贪吃蛇游戏是一款内存小易操作的益智类小游戏,特别适合我们在压力大时作为一个缓解情绪的娱乐方式,既不沉迷又得到放松,随时随地都可以玩不需要网络. 2.设计思路 游戏通过控制贪吃蛇的移动方向决定它吃下去的东西来增加它的长度,使它逐渐变长,每吃下去一个随之增长一个长度,当贪吃蛇碰到墙壁或者自己本身则游戏结束. 3.游戏功能 通过UP上,DOWN下,life左,right右控制贪吃蛇的移动方向,每吃一个东西增加一个长度,碰到墙壁或自身则游戏结束 4.代码 下

Android快乐贪吃蛇游戏实战项目开发教程-01项目概述

一.项目简介贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏.我已经将做好的案例上传到了应用宝,大家可以下载下来把玩一下.为了和其它的贪吃蛇区别开来,我取名叫“快乐贪吃蛇”.应用宝链接:http://sj.qq.com/myapp/detail.htm?apkName=net.chengyujia.happysnake这里上两张截图先睹为快,哈哈.怎么玩大家应该都知道,不过我还是要多提一下.通过屏幕上的方向键控制蛇的前进方向.蛇每吃到一个食物身体会

WebGL实现HTML5的3D贪吃蛇游戏

js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型,多次想尝试提交个小游戏但总无法写出让自己满意还能控制在这么小的字节范围. 自己写不出来,站在巨人肩膀总是有机会吧,想起<基于HTML5的电信网管3D机房监控应用>这篇提到的threejs,babylonjs和Hightopo的几种基于WebGL的3D引擎,突然想挑战下自己实现个100行JS的3D小

A.探路者——贪吃蛇游戏(测评人:黄泽宇)

一.基于NABCD评论作品,及改进建议 每个小组评论其他小组Alpha发布的作品:1.根据(不限于)NABCD评论作品的选题:2.评论作品对选题的实现效果:3.就现有技术和工作量,不改变选题的主要方向,为该作品在beta版本可增减的功能提出改进意见. 1.根据(不限于)NABCD评论作品的选题. 根据探路者的Alpha发布选题背景及意义进行考量: 贪吃蛇游戏团队的选题背景及意义 NABCD标准考量 贪吃蛇作为一个经典的游戏,设计简单,实用和娱乐性高.对于贪吃蛇传统的玩法,大家众所周知,即:玩家通

手起刀落-一起来写经典的贪吃蛇游戏

回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效果吧!! 功能和小时候玩的贪吃蛇一样, 1.选择速度 slow normal fast 2.选择是否有墙作为障碍物 on off 看完效果就先附上地址喽:大山深处修炼的小龙虾,欢迎fork. 结构分解 如果构建一个简单的经典贪吃蛇游戏呢?我们根据面板可以分解出如下结构: 因为其他面板比较简单,我们重

Love2D游戏引擎制作贪吃蛇游戏

代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查看: for windows 预览游戏 love2d游戏引擎重要函数 详情: love2d wiki love.load:当游戏开始时被调用且仅调用一次 love.draw:回调函数,每帧更新一次游戏画面 love.update:回调函数,每帧更新一次游戏状态 love.keypressed:回调函

Qt版贪吃蛇游戏

Qt版贪吃蛇游戏 转载请标明出处:牟尼的专栏 http://blog.csdn.net/u012027907 最近在学习Qt,用了一个多月的时间掌握了Qt中最基本的知识,也完成了<Qt版音乐播放器>.<Qt版贪吃蛇游戏>.<Qt版双人俄罗斯方块>以及<Qt版科学计算器>等,之前在VC下写过这些程序,所以在Qt下只是改变了显示等语句,我写过<C++版贪吃蛇游戏>.<VC版贪吃蛇游戏>,当时将与显示等无关的东西封装起来,在Qt下直接用,只