小项目特供 贪吃蛇游戏(基于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
第二个是功能部分源码
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语言)的主要内容,如果未能解决你的问题,请参考以下文章