EasyX图形库实现贪吃蛇游戏

简介: EasyX图形库实现贪吃蛇游戏

⭐大家好,我是Dark Falme Masker,学习了动画制作及键盘交互之后,我们就可以开动利用图形库写一个简单的贪吃蛇小游戏,增加学习乐趣。

⭐专栏:EasyX部分小游戏实现详细讲解

最终效果如下

首先包含头文件

#include<stdio.h>

#include<easyx.h>

#include<conio.h>

#include<time.h>

✅我们将会使用rand函数生成随机数,来控制食物的随机生成,设置时间戳srand(time(NULL)),所以要包含time.h

int main()
{
  initgraph(800, 600);
  setbkcolor(RGB(164, 225, 202));
  cleardevice();
  closegraph();
  return 0;
}

🏅创建窗体,更换背景颜色。

将窗体划分为各个边长为40的正方形小格,方便后续表示蛇和食物。

👉为了方便后续可以修改每个小格的边长,可以将其定义一下

#define NodeWidth 40

然后划分分界线,让后续绘制出蛇和食物位置更加清晰。

void paintGrid()
{
  for (int y = 0; y <= 600; y += NodeWidth)
  {
    line(0, y, 800, y);
  }
  for (int x = 0; x <= 800; x += NodeWidth)
  {
    line(x, 0, x, 600);
  }
}

运行代码观察是否存在问题

📚接下来绘制蛇,蛇的起始长度设置为5,蛇是由五个连续的正方形小块构成,食物由一个正方形小块构成。我们可以盛情一个结构体变量,存放每个正方形小格子的左上角的坐标。

typedef struct {

   int x;

   int y;

}Node;

📜创建一个结构体数组,装着蛇的坐标信息,在第七行绘制出蛇的各个节点,如果数组第一个元素作为头节点,那么其余节点的x坐标是递减NodeWidth的,直接传格数,在绘制时乘以小方块宽度即可。

Node snake[100] = { {5,7},{4,7},{3,7},{2,7},{1,7} };

绘制蛇的函数

void paintSnake(Node* snake, int n)
{
  int left, top, right, bottom;
  for (int i = 0; i < n; i++)
  {
    left = snake[i].x * NodeWidth;
    top = snake[i].y * NodeWidth;
    right = (snake[i].x + 1) * NodeWidth;
    bottom = (snake[i].y + 1) * NodeWidth;
    solidrectangle(left, top, right, bottom);
  }
}

💭传入结构体指针及社的节点个数,即可在画面中绘制出一个长度为5格的蛇。

但是蛇是会移动的,所以要加上键盘交互功能,控制蛇的方向移动。

创建枚举

enum direction

{

   eUp,

   eDown,

   eLeft,

   eRight

};

📑一共有三种状况,在蛇移动时判断键盘是否控制蛇的移位,通过控制结构体数组内x,y的值就可以实现蛇的移动。

默认direction为右

   enum direction d = eRight;

判断玩家按下键盘的函数,传入枚举指针,改变枚举值,从而根据改变后的值改变更新蛇的位置的x,y坐标,再次绘制时设就可以转向。

void changeDirection(enum direction* pD)
{
  if (_kbhit() != 0)
  {
    char c = _getch();
    switch (c)
    {
    case'w':
      if (*pD != eDown)
        *pD = eUp;
      break;
    case's':
      if (*pD != eUp)
        *pD = eDown;
      break;
    case'a':
      if (*pD != eRight)
        *pD = eLeft;
      break;
    case'd':
      if (*pD != eLeft)
        *pD = eRight;
      break;
    }
  }
}

🔥改变direction后就可以更改蛇节点的参数,要注意的是,蛇头不可以向正在移动的方向的相反方向移动,这里要进行判断。

👑在移动时,后续节点覆盖前边的节点的位置,根据蛇头位置及移动方向生成新的节点位置作为蛇头,设置这个函数的返回值为NODE类型,记录蛇尾节点。

✨返回蛇尾节点,利用一个结构体变量接收,在判断蛇头吃掉食物结点之后就可以将返回的节点续上,并且++蛇的长度。

Node snakeMove(Node* snake, int length, int direction)
{
  Node tail = snake[length - 1];
  for (int i = length - 1; i > 0; i--)
  {
    snake[i] = snake[i - 1];
  }
  Node NewHead;
  NewHead = snake[0];
  if (direction == eUp)
  {
    NewHead.y--;
  }
  else if (direction == eDown)
  {
    NewHead.y++;
  }
  else if (direction == eLeft)
  {
    NewHead.x--;
  }
  else if (direction == eRight)
  {
    NewHead.x++;
  }
  snake[0] = NewHead;
  return tail;
}

创建食物

🏅创建食物是随机生成坐标,不可以超出创建的窗体大小而且不可以生成到蛇的身体上,可以使用三子棋的思路,设置死循环,直到生成满足我们需要的位置然后break。

Node createFood(Node* snake, int length)
{
  Node food;
  while (1)
  {
    food.x = rand() % (800 / NodeWidth);
    food.y = rand() % (600 / NodeWidth);
    int i;
    for (i = 0; i < length; i++)
    {
      if ((food.x == snake[i].x) && (food.y == snake[i].y))
      {
        break;
      }
    }
    if (i < length)
      continue;
    else
      break;
  }
  return food;
}

生成完成后返回创建出的食物的结构体变量

然后绘制出食物,利用不同颜色作为区分。

void paintFood(Node food)
{
  int left, right, top, bottom;
  left = food.x * NodeWidth;
  top = food.y * NodeWidth;
  right = (food.x + 1) * NodeWidth;
  bottom = (food.y + 1) * NodeWidth;
  setfillcolor(YELLOW);
  solidrectangle(left, top, right, bottom);
  setfillcolor(WHITE);
}

👉我们绘制出的蛇的身体是白色的,如果在这里更改了填充颜色,再次绘制蛇就变成和食物一样的颜色,所以在绘制食物后还要将填充颜色还原为白色。

判断是否吃掉食物及节点的续接。

Node lastTail = snakeMove(snake, length, d);

if (snake[0].x == food.x && snake[0].y == food.y)

{

       if (length < 100)

       {

          snake[length] = lastTail;

           length++;

        }

        food = createFood(snake, length);

}

在循环中不断判断,吃掉食物后就创建出新的食物。

☁️判断游戏结束

如果蛇吃掉自己的身体或者蛇头越界了,就表示游戏失败

bool IsGameover(Node* snake, int length)
{
  if (snake[0].x<0 ||snake[0].x>(800 / NodeWidth))
    return true;
  if (snake[0].y<0 || snake[0].y>(600 / NodeWidth))
    return true;
  for (int i = 1; i < length; i++)//0改为1
  {
    if (snake[0].x == snake[i].x && snake[0].y == snake[i].y)
      return true;
  }
  return false;
}

💡如果没有碰到墙或者遍历过程中蛇头没有和某蛇节点重合,才返回false,否则返回true,表示游戏失败。

判断失败后,重置蛇的节点,重新生成新的食物。

讲解到这里就结束啦

代码如下,大家可以运行看一看效果(用于使格子更加明显的线可以画也可以不画)

#include<stdio.h>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#define NodeWidth 40
typedef struct {
  int x;
  int y;
}Node;
void paintGrid()
{
  for (int y = 0; y <= 600; y += NodeWidth)
  {
    line(0, y, 800, y);
  }
  for (int x = 0; x <= 800; x += NodeWidth)
  {
    line(x, 0, x, 600);
  }
}
void paintSnake(Node* snake, int n)
{
  int left, top, right, bottom;
  for (int i = 0; i < n; i++)
  {
    left = snake[i].x * NodeWidth;
    top = snake[i].y * NodeWidth;
    right = (snake[i].x + 1) * NodeWidth;
    bottom = (snake[i].y + 1) * NodeWidth;
    solidrectangle(left, top, right, bottom);
  }
}
enum direction
{
  eUp,
  eDown,
  eLeft,
  eRight
};
Node snakeMove(Node* snake, int length, int direction)
{
  Node tail = snake[length - 1];
  for (int i = length - 1; i > 0; i--)
  {
    snake[i] = snake[i - 1];
  }
  Node NewHead;
  NewHead = snake[0];
  if (direction == eUp)
  {
    NewHead.y--;
  }
  else if (direction == eDown)
  {
    NewHead.y++;
  }
  else if (direction == eLeft)
  {
    NewHead.x--;
  }
  else if (direction == eRight)
  {
    NewHead.x++;
  }
  snake[0] = NewHead;
  return tail;
}
void changeDirection(enum direction* pD)
{
  if (_kbhit() != 0)
  {
    char c = _getch();
    switch (c)
    {
    case'w':
      if (*pD != eDown)
        *pD = eUp;
      break;
    case's':
      if (*pD != eUp)
        *pD = eDown;
      break;
    case'a':
      if (*pD != eRight)
        *pD = eLeft;
      break;
    case'd':
      if (*pD != eLeft)
        *pD = eRight;
      break;
    }
  }
}
Node createFood(Node* snake, int length)
{
  Node food;
  while (1)
  {
    food.x = rand() % (800 / NodeWidth);
    food.y = rand() % (600 / NodeWidth);
    int i;
    for (i = 0; i < length; i++)
    {
      if ((food.x == snake[i].x) && (food.y == snake[i].y))
      {
        break;
      }
    }
    if (i < length)
      continue;
    else
      break;
  }
  return food;
}
void paintFood(Node food)
{
  int left, right, top, bottom;
  left = food.x * NodeWidth;
  top = food.y * NodeWidth;
  right = (food.x + 1) * NodeWidth;
  bottom = (food.y + 1) * NodeWidth;
  setfillcolor(YELLOW);
  solidrectangle(left, top, right, bottom);
  setfillcolor(WHITE);
}
bool IsGameover(Node* snake, int length)
{
  if (snake[0].x<0 ||snake[0].x>(800 / NodeWidth))
    return true;
  if (snake[0].y<0 || snake[0].y>(600 / NodeWidth))
    return true;
  for (int i = 1; i < length; i++)//0改为1
  {
    if (snake[0].x == snake[i].x && snake[0].y == snake[i].y)
      return true;
  }
  return false;
}
void reset(Node* snake, int* length, enum direction* d)
{
  snake[0] = Node{ 5,7 };
  snake[1] = Node{ 4,7 };
  snake[2] = Node{ 3,7 };
  snake[3] = Node{ 2,7 };
  snake[4] = Node{ 1,7 };
  *length = 5;
  *d = eRight;
}
int main()
{
  initgraph(800, 600);
  setbkcolor(RGB(164, 25, 202));
  cleardevice();
  paintGrid();
  Node snake[100] = { {5,7},{4,7},{3,7},{2,7},{1,7} };
  int length = 5;
  enum direction d = eRight;
  srand(unsigned int(time(NULL)));
  Node food = createFood(snake, length);
  while (1)
  {
    cleardevice();
    paintGrid();
    paintSnake(snake, length);
    paintFood(food);
    Sleep(500);
    changeDirection(&d);
    Node lastTail = snakeMove(snake, length, d);
    if (snake[0].x == food.x && snake[0].y == food.y)
    {
      if (length < 100)
      {
        snake[length] = lastTail;
        length++;
      }
      food = createFood(snake, length);
    }
    if (IsGameover(snake, length) == true)
    {
      reset(snake, &length, &d);
      food = createFood(snake, length);
    }
  }
  closegraph();
  return 0;
}
目录
相关文章
|
6月前
|
安全 Python Windows
游戏开发丨基于Tkinter的扫雷小游戏
游戏开发丨基于Tkinter的扫雷小游戏
115 3
|
6月前
|
Python
游戏开发丨基于Pygame的贪吃蛇小游戏
游戏开发丨基于Pygame的贪吃蛇小游戏
131 2
|
6月前
|
图形学
打地鼠游戏(使用Qt)
打地鼠游戏(使用Qt)
通过easyx窗口实现贪吃蛇
通过easyx窗口实现贪吃蛇
117 0
|
7月前
Qt+OpenGL 打砖块游戏
Qt+OpenGL 打砖块游戏
95 0
|
7月前
|
Python
100行代码,使用 Pygame 制作一个贪吃蛇小游戏!
100行代码,使用 Pygame 制作一个贪吃蛇小游戏!
130 0
|
7月前
|
图形学
【Unity3D开发小游戏】Unity3D零基础一步一步教你制作跑酷类游戏
【Unity3D开发小游戏】Unity3D零基础一步一步教你制作跑酷类游戏
|
机器学习/深度学习 C语言 C++
【c语言】五子棋(EasyX图形库+背景音乐)
【c语言】五子棋(EasyX图形库+背景音乐)
221 0
|
C语言 C++
为什么要学习easyx图形库,他是做什么的?值得吗?
首先,easyx仅支持C语言和C++,这对于学习C语言的新生来说很友好,在熟悉C语言的同时还可以提高写代码的能力,在熟悉C语言以后,就可以尝试写一写小游戏了,比如说扫雷,三子棋,魔塔,贪吃蛇,飞机大战等等,但是当我们写出来运行的时候可以发现,游戏的逻辑写的没有问题,也的确可以玩,但是界面和人物怪兽什么的都很丑,全是符号不好看,同时控制台一闪一闪的,对玩家来说体验感极差,这也就是我们为什么要学习easyx图形库。
258 1
|
C++ 开发者 Windows
C++实现贪吃蛇(含源代码)—基于easyx图形库
C++实现贪吃蛇(含源代码)—基于easyx图形库

相关实验场景

更多