欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言彩色版贪吃蛇——图形界面Easyx的简单使用

程序员文章站 2024-03-18 11:52:22
...

大一上大概12月份学完了C语言,基本语法与知识已经基本具备,可以用C语言写出基本的贪吃蛇游戏,但是基础C语言的可视化与交互功能实在是太弱了,为了写出有色彩的游戏,需要在网上安装一个Easyx的插件,具体Easyx如何使用参见https://zhuanlan.zhihu.com/p/24826034点击打开链接

然后编程软件我用的是VS 2017(因为Dev C++不支持Easyx) VS安装入口:点击打开链接

程序实现了用户登陆与注册,用户数据保存到文件,高分榜等较为简单的功能,整个代码不算注释大概三百五十行。

游戏效果大概是这样:

C语言彩色版贪吃蛇——图形界面Easyx的简单使用
C语言彩色版贪吃蛇——图形界面Easyx的简单使用
介绍一下游戏思路:先想清楚完成贪食蛇这个游戏需要哪些元素,游戏需要满足哪些功能,再敲代码把它们逐渐实现。
首先我们需要基础元素:地图(墙),然后是食物,一条蛇。 然后是功能:1.移动蛇   2.蛇的长大(吃果子) 3.蛇的死活(撞墙或者自食)具体代码见下(有详细注释)。
然后是图像的处理:1.注意Eaxyx的点是像素点,与控制台的点不一样,用的时候要记得乘个系数转化
2.你可以选择用Easyx的函数画地图(就像我的代码一样,很随便而简陋),也可以选择去网上找图然后贴上去(可以做的很精美,想在同学面前秀一秀的注意了)
3.用户登陆与注册的部分界面用Easyx的InputBox,然后用文件读入读出的方式,把用户数据存入单独的文件中,更方便的办法是弄一个二进制文件,把用户账号和密码弄成结构存进去。
4.高分榜的实现:每次用户结束游戏后,把榜上分数从文件中读下来然后与用户本次分数比较,排序然后再重新写入文件中。


*****************************************************我是分割线************************************************************

****************************************************************************************************************************


咳咳,在后台收到了一些同学的评论,现在作为一条在大学已经摸爬滚打快一年的资深咸鱼决定在这里集中更新一下,什么觉得time flies,什么回顾以前的代码觉得很菜的口水话我就不说了,进入正题:

1.有同学说在VS上运行我的代码出现了 debug assertion failed的错误;这个错误一般是因为访问了不该访问的文件或内存地址。首先看代码知道我创建了两个文本文件,scores.txt与Users1.txt分别用来储存用户的得分与用户的账号和密码,而这两个文件是既要读出,又要写入的,而且我在代码中是调用了两个文件的内容的,所以:你必须要事先创建scores.txt与Users.txt两个文本文件,不然代码中调用了文件指针fp,而它却指向了空的内容,就会出现debug assertion failed(指针越界)的错误。

emmmm,具体如何添加文本文件如下图所示:在实用工具的文本文件中把文件名修改为scores.txt与Users.txt,(你也可以改成别的,但代码中调用的文件名也要相应改动)

C语言彩色版贪吃蛇——图形界面Easyx的简单使用

整个项目的布局应该是这样的:如下图所示

C语言彩色版贪吃蛇——图形界面Easyx的简单使用

当我们注册了账号名为123,密码名为123的用户时,并且用它玩出了3分的高分时,再打开下图的这两个文本文件,就会发现它已经出现了改动(原本都是空的)。如下图所示:

C语言彩色版贪吃蛇——图形界面Easyx的简单使用

C语言彩色版贪吃蛇——图形界面Easyx的简单使用

这次更新就到这里,谢谢各位小老板的观看!

不定期更新,欢迎留言讨论,哈哈。

//代码如下:
#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;
}//降序排序