大一上大概12月份学完了C语言,基本语法与知识已经基本具备,可以用C语言写出基本的贪吃蛇游戏,但是基础C语言的可视化与交互功能实在是太弱了,为了写出有色彩的游戏,需要在网上安装一个Easyx的插件,具体Easyx如何使用参见https://zhuanlan.zhihu.com/p/24826034点击打开链接
然后编程软件我用的是VS 2017(因为Dev C++不支持Easyx) VS安装入口:点击打开链接
程序实现了用户登陆与注册,用户数据保存到文件,高分榜等较为简单的功能,整个代码不算注释大概三百五十行。
游戏效果大概是这样:
介绍一下游戏思路:先想清楚完成贪食蛇这个游戏需要哪些元素,游戏需要满足哪些功能,再敲代码把它们逐渐实现。
首先我们需要基础元素:地图(墙),然后是食物,一条蛇。 然后是功能:1.移动蛇
2.蛇的长大(吃果子)
3.蛇的死活(撞墙或者自食)
具体代码见下(有详细注释)。
然后是图像的处理:1.注意Eaxyx的点是像素点,与控制台的点不一样,用的时候要记得乘个系数转化
2.你可以选择用Easyx的函数画地图(就像我的代码一样,很随便而简陋),也可以选择去网上找图然后贴上去(可以做的很精美,想在同学面前秀一秀的注意了)
3.用户登陆与注册的部分界面用Easyx的InputBox,然后用文件读入读出的方式,把用户数据存入单独的文件中,更方便的办法是弄一个二进制文件,把用户账号和密码弄成结构存进去。
4.高分榜的实现:每次用户结束游戏后,把榜上分数从文件中读下来然后与用户本次分数比较,排序然后再重新写入文件中。
//代码如下: #include <graphics.h> // 引用图形库头文件 #include <conio.h> #include <stdio.h> #include <windows.h> #include <time.h> #include <conio.h> #include<stdlib.h> #define frame_height 30 //define map size #define frame_width 30 #define UP 'w' //define operate key #define DOWN 's' #define LEFT 'a' #define RIGHT 'd' #define SIZE 16 #define N 4 FILE *fp; int i, j, k, m, n, s[N]; char s1[5], s2[5]; char ch = UP; //initial direction int grow = 0; //flag: if snake grow struct Food { int x; int y; }food; struct Snake { int x[50]; int y[50]; int len; int speed; }snake; //snake[0] is head typedef struct The_users //用于储存用户账号密码 { char id[11];//ID char pwd[20];//password }users; users a, b;//成员变量,用来登陆与注册 void init_map(void); void update_food(void); void move_snake(void); int is_alive(void); void get_speed(void); void gotoxy(int x, int y); void redraw_map(void); void menu(); void registers(); void Login(); //void Create_File(); void score(); int compInc(const void *a, const void *b); int compDec(const void *a, const void *b); int main() { initgraph(640, 480);//创建绘图窗口 menu(); score(); return 0; } void redraw_map(void) { //initial bar for (j = 0; j<frame_width; j++) { moveto(j*SIZE, 0); setfillcolor(BLUE); fillrectangle(j*SIZE, 0, j*SIZE + SIZE, SIZE); moveto(j*SIZE, (frame_height - 1)*SIZE); setfillcolor(BLUE); fillrectangle(j*SIZE, (frame_height - 1)*SIZE, j*SIZE + SIZE, (frame_height - 1)*SIZE + SIZE); } for (i = 1; i<frame_height - 1;) { moveto(0, i*SIZE); setfillcolor(BLUE); fillrectangle(0, i*SIZE, 0 + SIZE, i*SIZE + SIZE); moveto((frame_width - 1)*SIZE, i*SIZE); setfillcolor(BLUE); fillrectangle((frame_width - 1)*SIZE, i*SIZE, (frame_width - 1)*SIZE + SIZE, i*SIZE + SIZE); i = i + 1; } } void init_map(void) { //initial food srand((unsigned int)time(NULL)); food.x = rand() % (frame_height - 2) + 1; food.y = rand() % (frame_width - 2) + 1; moveto(food.y*SIZE, food.x*SIZE); setfillcolor(RED); fillcircle(food.y *SIZE + SIZE / 2, food.x*SIZE + SIZE / 2, SIZE / 2); //initial snake snake.x[0] = (frame_height) / 2; snake.y[0] = (frame_width) / 2; moveto(snake.y[0] * SIZE, snake.x[0] * SIZE); setfillcolor(GREEN); fillcircle(snake.y[0] * SIZE + SIZE / 2, snake.x[0] * SIZE + SIZE / 2, SIZE / 2); snake.len = 3; snake.speed = 200; for (k = 1; k<snake.len; k++) { snake.x[k] = snake.x[k - 1] + 1; snake.y[k] = snake.y[k - 1]; moveto(snake.y[k] * SIZE, snake.x[k] * SIZE); setfillcolor(GREEN); fillcircle(snake.y[k] * SIZE + SIZE / 2, snake.x[k] * SIZE + SIZE / 2, SIZE / 2); } //initial bar for (j = 0; j<frame_width; j++) { moveto(j*SIZE, 0); setfillcolor(BLUE); fillrectangle(j*SIZE, 0, j*SIZE + SIZE, SIZE); moveto(j*SIZE, (frame_height - 1)*SIZE); setfillcolor(BLUE); fillrectangle(j*SIZE, (frame_height - 1)*SIZE, j*SIZE + SIZE, (frame_height - 1)*SIZE + SIZE); } for (i = 1; i<frame_height - 1;) { moveto(0, i*SIZE); setfillcolor(BLUE); fillrectangle(0, i*SIZE, 0 + SIZE, i*SIZE + SIZE); moveto((frame_width - 1)*SIZE, i*SIZE); setfillcolor(BLUE); fillrectangle((frame_width - 1)*SIZE, i*SIZE, (frame_width - 1)*SIZE + SIZE, i*SIZE + SIZE); i = i + 1; } } //generate food void update_food() { if (snake.x[0] == food.x&&snake.y[0] == food.y) { food.x = rand() % (frame_height - 2) + 1; food.y = rand() % (frame_width - 2) + 1; for (k = 1; k<snake.len; k++) { if (snake.x[k] == food.x&&snake.y[k] == food.y) { food.x = rand() % (frame_height - 2) + 1; food.y = rand() % (frame_width - 2) + 1; } } moveto(food.y*SIZE, food.x*SIZE); setfillcolor(RED); fillcircle(food.y*SIZE + SIZE / 2, food.x*SIZE + SIZE / 2, SIZE / 2); snake.len++; grow = 1; } } //move snake void move_snake() { if (_kbhit()) ch = _getch(); if (!grow) { moveto(snake.y[snake.len - 1] * SIZE, snake.x[snake.len - 1] * SIZE); setfillcolor(BLACK); solidrectangle(snake.y[snake.len - 1] * SIZE, snake.x[snake.len - 1] * SIZE, snake.y[snake.len - 1] * SIZE + SIZE, snake.x[snake.len - 1] * SIZE + SIZE); } for (k = snake.len - 1; k>0; k--) { snake.x[k] = snake.x[k - 1]; snake.y[k] = snake.y[k - 1]; } switch (ch) { case UP: snake.x[0]--; break; case DOWN: snake.x[0]++; break; case LEFT: snake.y[0]--; break; case RIGHT: snake.y[0]++; break; default: break; } moveto(snake.y[0] * SIZE, snake.x[0] * SIZE); setfillcolor(GREEN); fillcircle(snake.y[0] * SIZE + SIZE / 2, snake.x[0] * SIZE + SIZE / 2, SIZE / 2); grow = 0; } //is alive int is_alive(void) { if (snake.x[0] == 0 || snake.x[0] == frame_height - 1 || snake.y[0] == frame_width - 1 || snake.y[0] == 0) return 0; for (k = 1; k<snake.len; k++) if (snake.x[k] == snake.x[0] && snake.y[k] == snake.y[0]) return 0; return 1; } //speed up void get_speed(void) { if (snake.len <= 6) snake.speed = 200; else if (snake.len <= 10) snake.speed = 100; else if (snake.len <= 20) snake.speed = 50; else if (snake.len <= 30) snake.speed = 30; else snake.speed = 20; } //move cursor void gotoxy(int x, int y) { HANDLE hout; COORD cor; hout = GetStdHandle(STD_OUTPUT_HANDLE); cor.X = y; cor.Y = x; SetConsoleCursorPosition(hout, cor); } void menu() { InputBox(s1, 5, "请输入数字:1.开始游戏2.高分榜3.退出游戏"); int x, y[3]; sscanf_s(s1, "%d", &x);//将用户输入转化为数字 if (x == 1) { InputBox(s2, 5, "请输入数字:1.注册2.登陆"); sscanf_s(s2, "%d", &x); if (x == 1) { registers(); Login(); } else if (x == 2) { Login(); } init_map(); //初始化地图 while (1) { update_food(); //是否产生食物 get_speed(); //获取速度 move_snake(); //移动蛇身 redraw_map();//重绘地图 Sleep(snake.speed); //移动速度 if (!(is_alive())) //蛇的死活(撞墙或自食) break; } closegraph();//关闭绘图窗口 printf("Game Over!\n"); printf("你的得分:%d", snake.len - 3); _getch(); } else if (x == 2) { closegraph(); printf(" 排行榜\n"); fopen_s(&fp, "scores.txt", "r"); for (x = 0; x < N - 1; x++) { fscanf_s(fp, "%d", &y[x]); printf("%d\n", y[x]); } fclose(fp); _getch(); } else { closegraph(); } } void registers()//注册账号密码 { fopen_s(&fp, "Users1.txt", "r"); fscanf_s(fp, "%s%s", b.id, sizeof(b.id), b.pwd, sizeof(b.pwd)); InputBox(a.id, 11, "请输入账号"); while (1) { if (strcmp(a.id, b.id) != 0)//如果两串字符串不相等 { if (!feof(fp))//如果未至文件末尾 { fscanf_s(fp, "%s%s", b.id, sizeof(b.id), b.pwd, sizeof(b.pwd)); } else break; } else { outtextxy(220, 200, "此用户名已被注册"); fclose(fp); _getch(); exit(0); } } fclose(fp); InputBox(a.pwd, 10, "请输入密码"); fopen_s(&fp, "Users1.txt", "a"); fprintf_s(fp, "%s %s\n", a.id, a.pwd); outtextxy(220, 200, "账号注册成功!"); fclose(fp); } void Login()//登陆账号密码 { fopen_s(&fp, "Users1.txt", "r"); fscanf_s(fp, "%s%s", b.id, sizeof(b.id), b.pwd, sizeof(b.pwd)); InputBox(a.id, 11, "请输入账号"); while (1) { if (strcmp(a.id, b.id) == 0) break;//如果找到了这个用户名 else { if (!feof(fp))//如果文件未读完 fscanf_s(fp, "%s%s", b.id, sizeof(b.id), b.pwd, sizeof(b.pwd)); else { outtextxy(220, 200, "此用户名不存在!"); fclose(fp); _getch(); exit(0); } } } InputBox(a.pwd, 20, "请输入密码"); if (strcmp(a.pwd, b.pwd) == 0)//如果密码匹配 { fclose(fp); outtextxy(250, 200, "登陆成功!"); initgraph(640, 480); } else { outtextxy(220, 200, "密码不正确"); _getch(); exit(0); } } void score() { fopen_s(&fp, "scores.txt", "r"); for (n = 0; n < N - 1; n++) { fscanf_s(fp, "%d", &m); s[n] = m; } s[N - 1] = snake.len - 3; qsort(s, N, sizeof(s[0]), compDec); fclose(fp); fopen_s(&fp, "scores.txt", "w"); for (n = 0; n < N - 1; n++) { fprintf_s(fp, "%d\n", s[n]); } fclose(fp); } int compInc(const void *a, const void *b) { return *(int *)a - *(int *)b; }//升序排序 int compDec(const void *a, const void *b) { return *(int *)b - *(int *)a; }//降序排序