评论

收藏

[C++] 贪吃蛇实现

编程语言 编程语言 发布于:2021-12-27 22:55 | 阅读数:447 | 评论:0

0.实现效果
模式选择:普通模式,穿墙模式,无敌模式。
DSC0000.png
进入游戏,有背景音乐。
DSC0001.png

1.准备工作:
easyx图形库安装,NSIS打包软件。
这两个在网上能找到教程安装。

2.关于贪吃蛇实现
在网上有很多教程,或多或少细节方面是有不同之处的,这里我借助easyx图形库进行实现,一是色彩不显得那么单调;二是不使用windows的光标控制函数等函数,这样就避免后面涉及线程的东西,上手方面会更简单一些。(线程这块不是太明白)

3.进入实战
注意:VS2019中.cpp才能运行easyx图形库,.c是不行的。
1.首先先绘个背景:
#include<iostream>
#include<easyx.h>
int main()
{
initgraph(640,480);//设置窗口大小,为640*480
  setbkcolor(WHITE);//设置窗口背景色为白色
  cleardevice();//刷新屏幕
  setbkmode(TRANSPARENT); //设置字体背景色为透明
  settextcolor(RED);  //设置字体颜色为红色
  outtextxy(200, 240, L"Enter键进入游戏"); 
  outtextxy(200, 280, L"字母键 W,S,A,D 方向键 上下左右 控制方向");
  getchar(); //按任意键继续
  return 0;
  }
关于函数怎么使用,网上有详细说明,这里就不一一具体说明了。
这里getchar()是为了不让图片加载就消失。
这样,我们就得到了一个窗口
DSC0002.png
当然,这个就比较单调,我们加个背景图(这个找张喜欢的图片)上去。
#include<iostream>
#include<easyx.h>
IMAGE img;
int main()
{
  cleardevice();  //刷新屏幕
  loadimage(&img, L"Image0.jpg", 640, 480);  //保存图片
  putimage(0, 0, &img);  //显示图片
  setbkmode(TRANSPARENT); //设置字体背景色为透明
  settextcolor(WHITE);  //设置字体颜色为红色
  outtextxy(170, 200, L"模式选择");
  outtextxy(170, 240, L"1.普通模式");
  outtextxy(170, 280, L"2.穿墙模式");
  outtextxy(170, 320, L"3.无敌模式");
  outtextxy(380, 220, L"游戏说明:");
  outtextxy(360, 280, L"Enter键进入游戏"); 
  outtextxy(300, 320, L"字母键 W,S,A,D 方向键 上下左右 控制方向");
  outtextxy(350, 360, L"长按方向加速,空格暂停");
  getchar(); //按任意键继续
  return 0;
  }
loadimage里的Image.jpg我是放在了项目所在的位置,就可以直接调用了。写绝对路径也是可以的,有一点要注意,就是路径要\\,比如D:\要写成D:\\
这里我踩的一个坑就是putimage的前两个参数,这两个参数代表的是图片左上角的坐标,全部设为0,图片才能全部加载出来。
DSC0003.png
然后我们把上面这个图片代码放在start函数中,在main中调用这个函数。
2.模式选择
void chose()
{
while (1)
  {
  switch (_getch())
  {
  case '1':
    start();
    outtextxy(160, 240, L"->");
    mode = 0;  //全局变量mode表示模式
    break;
  case '2':
    start();
    outtextxy(160, 280, L"->");
    mode = 1;
    break;
  case '3':
    start();
    outtextxy(160, 320, L"->");
    mode = 2;
    break;
  case 13:  //Enter键进入游戏
    return;
  deault:
    break;
  }
  }
  }
这里的13表示enter键对应的数字。这里我踩的大坑就是开始写的这个'1'是1,导致键盘上的1对应的数值不是1,也就是按不动。一定要注意,键盘上数字和对应的数字不是一回事。
DSC0004.png
然后就可以在这三个模式进行切换,按Enter键进入游戏。
3.初始化游戏数据
游戏数据的话,我们需要一个围墙,一条蛇,分数显示。
围墙这里我们借用Map元素把整个框框包含在里面,然后分四类,分别是SPACE(空地),墙(WALL),蛇身(SNAKE),蛇头(HEAD),食物(FOOD)。
enum {
  SPACE, WALL, SNAKE, HEAD,FOOD  //依次代表空地,墙,蛇身,头,食物
};
#define ROW 48
#define COL 64
int map[ROW][COL];
int mode; //模式
int score; //分数
void DrawMap();//绘画界面
void Init();//初始化游戏界面
绘画:
void DrawMap()
{
  BeginBatchDraw(); //开始绘图
  settextcolor(RGB(238, 0, 0)); //设置字体颜色为红色
  cleardevice(); //刷新屏幕
  loadimage(&img, L"Image.jpg", 640, 480);  //保存图片
  putimage(0, 0, &img);  //显示图片
  WCHAR arr[10]; //保存分数
  wsprintf(arr, L"得分:%d", score); //分数放在arr中
  outtextxy(0, 0, arr); //显示分数
  for(int y=0;y<ROW;y++)
  for (int x = 0; x < COL; x++)
  {
    switch (map[y][x])
    {
    case SPACE:
    break;
    case WALL:
    setlinecolor(RED);  //边框线条颜色
    setfillcolor(RGB(187, 255, 255));  //填充颜色
    fillrectangle(x*10, y*10, x*10 + 10, y*10 + 10);  //画矩形
    break;
    case SNAKE:
    setlinecolor(RGB(78, 238, 148));
    setfillcolor(WHITE);
    fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
    break;
    case HEAD:
    switch (rand() % 7)
    {
    case 0:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RED);
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 1:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(WHITE);
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 2:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RGB(100,149,237));
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 3:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RGB(127,255,0));
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 4:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RGB(176,224,230));
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 5:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RGB(102,139,139));
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    case 6:
      setlinecolor(RGB(78, 238, 148));
      setfillcolor(RGB(46,139,87));
      fillrectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
      break;
    default:
      break;
    }
    break;
    }
  }
  EndBatchDraw(); //结束绘图
}
然后写初始化界面
void Init()
{
  srand((unsigned)time(NULL));//随机种子,给后面DrawMap中画蛇头使用
  memset(map, SPACE, sizeof(map));//初始化数组map为SPACE
  for (int x =0; x < COL; x++)
  map[0][x] = map[ROW - 1][x] = WALL;
  for (int y = 0; y < ROW; y++)
  map[y][0] = map[y][COL-1] = WALL;
}
先显示看看: DSC0005.png
然后发现不对劲,怎么会怎样?这也是一个坑,坑在哪,在我们设置地图数组的时候,如果直接按原地就搬尺寸就会发现原来的得分被覆盖了,那怎么改?
一是把原来的DrawMap给Wall的初始坐标修改,二是对Init中的两个for进行调整,x,y不再是从0,0开始,而是从0,2开始。(注意:二维数组左边代表纵坐标,右边代表横坐标)。
void Init()
{
  srand((unsigned)time(NULL));//随机种子,给后面DrawMap中画蛇头使用
  memset(map, SPACE, sizeof(map));//初始化数组map为SPACE
  for (int x =0; x < COL; x++)
  map[2][x] = map[ROW - 1][x] = WALL;
  for (int y = 2; y < ROW; y++)
  map[y][0] = map[y][COL-1] = WALL;
}
这样改到也可以,至少目前来说是可以,但是产生食物需要一个边界。这里我们的map[1][]和map[2][]是浪费了的。所以为了后续更好使用,这里我们干脆来个大修改:
#define ROW 46
#define COL 64
...
void Init()
{
  srand((unsigned)time(NULL));//随机种子,给后面DrawMap中画蛇头使用
  memset(map, SPACE, sizeof(map));//初始化数组map为SPACE
  for (int x =0; x < COL; x++)
    map[0][x] = map[ROW - 1][x] = WALL;
  for (int y = 0; y < ROW; y++)
    map[y][0] = map[y][COL-1] = WALL;
}
void DrawMap()
{
  BeginBatchDraw(); //开始绘图
  settextcolor(RGB(238, 0, 0)); //设置字体颜色为红色
  cleardevice(); //刷新屏幕
  loadimage(&img, L"Image.jpg", 640, 480);  //保存图片
  putimage(0, 0, &img);  //显示图片
  WCHAR arr[10]; //保存分数
  wsprintf(arr, L"得分:%d", score); //分数放在arr中
  outtextxy(0, 0, arr); //显示分数
  for (int y = 0; y < ROW; y++)
    for (int x = 0; x < COL; x++)
    {
      switch (map[y][x])
      {
      case SPACE:
        break;
      case WALL:
        setlinecolor(RED);  //边框线条颜色
        setfillcolor(RGB(187, 255, 255));  //填充颜色
        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);  //画矩形
        break;
      case SNAKE:
        setlinecolor(RGB(78, 238, 148));
        setfillcolor(WHITE);
        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
        break;
      case HEAD:
        switch (rand() % 7)
        {
        case 0:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RED);
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 1:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(WHITE);
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 2:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(100, 149, 237));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 3:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(127, 255, 0));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 4:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(176, 224, 230));
          fillrectangle(x * 10, y * 10+20, x * 10 + 10, y * 10 + 30);
          break;
        case 5:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(102, 139, 139));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 +30);
          break;
        case 6:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(46, 139, 87));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 +30);
          break;
        default:
          break;
        }
        break;
      }
    }
  EndBatchDraw(); //结束绘图
  }
这里特别要注意的是这个矩形四个角的坐标,要调对来。
DSC0006.png
这样,就得到了一个进去后的游戏界面。
4.造蛇
那蛇呢?对,现在开始造蛇,造蛇的话?可以用数组,但是超过数组区间就会崩溃,这里我们使用链表。
struct snake
{
  COORD pos;  //typedef struct _COORD {SHORT X;   SHORT Y;} COORD
  struct snake* next; //连接结点
};
struct snake* Head; //表示蛇头
void AddPoint(int x, int y); //增加结点
...
void AddPoint(int x, int y)
{
  struct snake* point = (struct snake*)malloc(sizeof(struct snake));
  if (point == NULL)
  {
    return;
  }
  else
  {
    point->pos.X = x;//这里X,Y分别代表纵坐标,横坐标
    point->pos.Y = y;
    if (Head == NULL)
    {
      Head = point;
      map[Head->pos.X][Head->pos.Y] = HEAD;
    }
    else
    {
      map[Head->pos.X][Head->pos.Y] = SNAKE;
      point->next = Head;
      Head = point;
      map[Head->pos.X][Head->pos.Y] = HEAD;
    }
  }
}
然后就可以得到这样的:
DSC0007.png
那蛇要怎么动呢,就是蛇头移动一个位置,然后那个新坐标就是蛇头,原蛇头为SNAKE,后面蛇尾释放置SPACE。
void DelPoint(); //删除结点
void ChangeDir(); //调整方向
void move(); //蛇动起来
char SnakeDir;//蛇的方向
int t1, t2; //代表时间
void DelPoint()
{
  if (Head == NULL || Head->next == NULL)
  {
    return;
  }
  struct snake* p = (struct snake*)malloc(sizeof(struct snake));
  struct snake* q = (struct snake*)malloc(sizeof(struct snake));
  if (p == NULL || q == NULL)
  {
    return;
  }
  p = Head;
  q = p->next;
  while (q->next)
  {
    p = p->next;
    q = p->next;
  }
  map[q->pos.X][q->pos.Y] = SPACE;
  free(q);
  q = NULL;
  p->next = NULL;
}
void move()
{
  struct snake* newpoint = (struct snake*)malloc(sizeof(struct snake));
  if (newpoint == NULL)
  {
    return;
  }
  switch (SnakeDir)
  {
  case 'D':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y + 1; //理清X,Y代表什么
    break;
  case 'A':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y - 1;
    break;
  case 'W':
    newpoint->pos.X = Head->pos.X - 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  case 'S':
    newpoint->pos.X = Head->pos.X + 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  default:
    break;
  }
  AddPoint(newpoint->pos.X, newpoint->pos.Y);
  DelPoint();
}
void ChangeDir()
{
  switch (_getch())
  {
  case 'A':
  case 'a':
  case 75:
    if (SnakeDir != 'D')
      SnakeDir = 'A';
    break;
  case 'D':
  case 'd':
  case 77:
    if (SnakeDir != 'A')
      SnakeDir = 'D';
    break;
  case 'W':
  case 'w':
  case 72:
    if (SnakeDir != 'S')
      SnakeDir = 'W';
    break;
  case 'S':
  case 's':
  case 80:
    if (SnakeDir != 'W')
      SnakeDir = 'S';
    break;
  case 32:  //空格
    _getch();
    break;
  default:
    break;
  }
}
这里的键盘上上、下、左、右分别对应数值72,80,75,77.
因为蛇动起来,自然就是while循环内一直走,碰到限制条件结束,然后我们这里要让他动起来,借助GetTickCount()函数,这个函数精度高
int main()
{
  initgraph(640, 480);
  start();
  outtextxy(160, 240, L"->");
  chose();
  Init();
  while (1)
  {
    DrawMap();
        if (_kbhit())
      {
        ChangeDir();
        move();
        t2 = GetTickCount();
        t1 = t2;
      }
      t2 = GetTickCount();
      if (t2 - t1 > 100)
      {
        move();
        t1 = t2;
      }
  }
  getchar();
  closegraph();
  return 0;
}
然后蛇就可以简单的动了。
5.加食物和模式选择
接下来就是造食物,顺便把限制条件给加上,就普通模式下撞墙或者撞到自己身体游戏结束,另外两个模式就是屏蔽游戏结束。
void Addfood()
{
  int x, y;
  do
  {
    x = rand() % (ROW-1)+1;
    y = rand() % (COL - 1) + 1;
  } while (map[x][y] != SPACE);
  map[x][y] = FOOD;
}
void move()
{
  struct snake* newpoint = (struct snake*)malloc(sizeof(struct snake));
  if (newpoint == NULL)
  {
    return;
  }
  switch (SnakeDir)
  {
  case 'D':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y + 1; //理清X,Y代表什么
    break;
  case 'A':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y - 1;
    break;
  case 'W':
    newpoint->pos.X = Head->pos.X - 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  case 'S':
    newpoint->pos.X = Head->pos.X + 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  default:
    break;
  }
  switch (map[newpoint->pos.X][newpoint->pos.Y])
  {
  case SPACE:
    AddPoint(newpoint->pos.X, newpoint->pos.Y);
    DelPoint();
    break;
  case SNAKE:
    if (mode==2)
    {
      AddPoint(newpoint->pos.X, newpoint->pos.Y);
      DelPoint();
    }
    else
    {
      PlaySound(NULL,0,0);
      MessageBox(GetHWnd(), L"游戏结束,继续努力", L"结果", MB_OK);
        exit(0);
    }
    break;
  case WALL:
    if (mode)
    {
      switch (SnakeDir)
      {
      case 'A':
        newpoint->pos.Y = COL - 2;
        break;
      case 'D':
        newpoint->pos.Y = 1;
        break;
      case 'W':
        newpoint->pos.X = ROW - 2;
        break;
      case 'S':
        newpoint->pos.X = 1;
        break;
      default:
        break;
      }
      AddPoint(newpoint->pos.X, newpoint->pos.Y);
      DelPoint();
    }
    else
    {
    PlaySound(NULL,0,0);
      MessageBox(GetHWnd(), L"游戏结束,继续努力", L"结果", MB_OK);
      exit(0);
    }
    break;
  case FOOD:
    score++;
    AddPoint(newpoint->pos.X, newpoint->pos.Y);
    Addfood();
    break;
  default:
    break;
  }
}
然后就是把main函数中进行调用一下。
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
int main()
{
  initgraph(640, 480);
  start();
  outtextxy(160, 240, L"->");
  chose();
  Init();
  while (1)
  {
    PlaySound(L"彩豆森林.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT | SND_LOOP);
    while (1)  
    {
      DrawMap();
      if (_kbhit())
      {
        ChangeDir();
        move();
        t2 = GetTickCount();
        t1 = t2;
      }
      t2 = GetTickCount();
      if (t2 - t1 > 100)
      {
        move();
        t1 = t2;
      }
    }
  }
  getchar();
  closegraph();
  return 0;
  }
然后加了个背景音乐进去,游戏结束把背景音乐停了。

6.源码
#include<iostream>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#include<Windows.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
using namespace std;
void start(); //开始界面
void Init(); //初始化游戏数据
void chose(); //选择界面
void DrawMap();//绘画界面
void Init();//初始化游戏界面
void Addfood();//添加食物
enum {
  SPACE, WALL, SNAKE, HEAD,FOOD  //依次代表空地,墙,蛇身,头
};
IMAGE img;
#define ROW 46
#define COL 64
int map[ROW][COL];
int mode; //模式
int score; //分数
char SnakeDir;//蛇的方向
int t1, t2; //代表时间
struct snake
{
  COORD pos;  //typedef struct _COORD {SHORT X;   SHORT Y;} COORD
  struct snake* next; //连接结点
};
struct snake* Head; //表示蛇头
void AddPoint(int x, int y); //增加结点
void DelPoint(); //删除结点
void ChangeDir(); //调整方向
void move(); //蛇动起来
int main()
{
  initgraph(640, 480);
  start();
  outtextxy(160, 240, L"->");
  chose();
  Init();
  while (1)
  {
    PlaySound(L"彩豆森林.wav", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT | SND_LOOP);
    while (1)
    {
      DrawMap();
      if (_kbhit())
      {
        ChangeDir();
        move();
        t2 = GetTickCount();
        t1 = t2;
      }
      t2 = GetTickCount();
      if (t2 - t1 > 100)
      {
        move();
        t1 = t2;
      }
    }
  }
  getchar();
  closegraph();
  return 0;
}
void start()
{
  cleardevice();
  loadimage(&img, L"Image0.jpg", 640, 480);  //保存图片
  putimage(0, 0, &img);  //显示图片
  setbkmode(TRANSPARENT); //设置字体背景色为透明
  settextcolor(WHITE);    //设置字体颜色为白色
  outtextxy(170, 200, L"模式选择");
  outtextxy(170, 240, L"1.普通模式");
  outtextxy(170, 280, L"2.穿墙模式");
  outtextxy(170, 320, L"3.无敌模式");
  outtextxy(380, 220, L"游戏说明:");
  outtextxy(360, 280, L"Enter键进入游戏"); 
  outtextxy(300, 320, L"字母键 W,S,A,D 方向键 上下左右 控制方向");
  outtextxy(350, 360, L"长按方向加速,空格暂停");
}
void chose()
{
  while (1)
  {
    switch (_getch())
    {
    case '1':
      start();
      outtextxy(160, 240, L"->");
      mode = 0;
      break;
    case '2':
      start();
      outtextxy(160, 280, L"->");
      mode = 1;
      break;
    case '3':
      start();
      outtextxy(160, 320, L"->");
      mode = 2;
      break;
    case 13:  //Enter键进入游戏
      return;
    deault:
      break;
    }
  }
}
void Init()
{
  srand((unsigned)time(NULL));//随机种子,给后面DrawMap中画蛇头使用
  memset(map, SPACE, sizeof(map));//初始化数组map为SPACE
  for (int x =0; x < COL; x++)
    map[0][x] = map[ROW - 1][x] = WALL;
  for (int y = 0; y < ROW; y++)
    map[y][0] = map[y][COL-1] = WALL;
  SnakeDir = 'D';
  AddPoint(5, 3);
  AddPoint(5, 4);
  AddPoint(5, 5);
  AddPoint(5, 6);
  Addfood();
}
void ChangeDir()
{
  switch (_getch())
  {
  case 'A':
  case 'a':
  case 75:
    if (SnakeDir != 'D')
      SnakeDir = 'A';
    break;
  case 'D':
  case 'd':
  case 77:
    if (SnakeDir != 'A')
      SnakeDir = 'D';
    break;
  case 'W':
  case 'w':
  case 72:
    if (SnakeDir != 'S')
      SnakeDir = 'W';
    break;
  case 'S':
  case 's':
  case 80:
    if (SnakeDir != 'W')
      SnakeDir = 'S';
    break;
  case 32:
    _getch();
    break;
  default:
    break;
  }
}
void AddPoint(int x, int y)
{
  struct snake* point = (struct snake*)malloc(sizeof(struct snake));
  if (point == NULL)
  {
    return;
  }
  else
  {
    point->pos.X = x;
    point->pos.Y = y;
    if (Head != NULL)
    {
      map[Head->pos.X][Head->pos.Y] = SNAKE;  //这里X,Y分别代表纵坐标,横坐标
    }
       point->next = Head;
       Head = point;
       map[Head->pos.X][Head->pos.Y] = HEAD;
  }
}
void DelPoint()
{
  if (Head == NULL || Head->next == NULL)
  {
    return;
  }
  struct snake* p = (struct snake*)malloc(sizeof(struct snake));
  struct snake* q = (struct snake*)malloc(sizeof(struct snake));
  if (p == NULL || q == NULL)
  {
    return;
  }
  p = Head;
  q = p->next;
  while (q->next)
  {
    p = p->next;
    q = p->next;
  }
  map[q->pos.X][q->pos.Y] = SPACE;
  free(q);
  q = NULL;
  p->next = NULL;
}
void Addfood()
{
  int x, y;
  do
  {
    x = rand() % (ROW-1)+1;
    y = rand() % (COL - 1) + 1;
  } while (map[x][y] != SPACE);
  map[x][y] = FOOD;
}
void move()
{
  struct snake* newpoint = (struct snake*)malloc(sizeof(struct snake));
  if (newpoint == NULL)
  {
    return;
  }
  switch (SnakeDir)
  {
  case 'D':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y + 1; //理清X,Y代表什么
    break;
  case 'A':
    newpoint->pos.X = Head->pos.X;
    newpoint->pos.Y = Head->pos.Y - 1;
    break;
  case 'W':
    newpoint->pos.X = Head->pos.X - 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  case 'S':
    newpoint->pos.X = Head->pos.X + 1;
    newpoint->pos.Y = Head->pos.Y;
    break;
  default:
    break;
  }
  switch (map[newpoint->pos.X][newpoint->pos.Y])
  {
  case SPACE:
    AddPoint(newpoint->pos.X, newpoint->pos.Y);
    DelPoint();
    break;
  case SNAKE:
    if (mode==2)
    {
      AddPoint(newpoint->pos.X, newpoint->pos.Y);
      DelPoint();
    }
    else
    {
      MessageBox(GetHWnd(), L"游戏结束,继续努力", L"结果", MB_OK);
        exit(0);
    }
    break;
  case WALL:
    if (mode)
    {
      switch (SnakeDir)
      {
      case 'A':
        newpoint->pos.Y = COL - 2;
        break;
      case 'D':
        newpoint->pos.Y = 1;
        break;
      case 'W':
        newpoint->pos.X = ROW - 2;
        break;
      case 'S':
        newpoint->pos.X = 1;
        break;
      default:
        break;
      }
      AddPoint(newpoint->pos.X, newpoint->pos.Y);
      DelPoint();
    }
    else
    {
      MessageBox(GetHWnd(), L"游戏结束,继续努力", L"结果", MB_OK);
      exit(0);
    }
    break;
  case FOOD:
    score++;
    AddPoint(newpoint->pos.X, newpoint->pos.Y);
    Addfood();
    break;
  default:
    break;
  }
}
void DrawMap()
{
  BeginBatchDraw(); //开始绘图
  settextcolor(RGB(238, 0, 0)); //设置字体颜色为红色
  cleardevice(); //刷新屏幕
  loadimage(&img, L"Image.jpg", 640, 480);  //保存图片
  putimage(0, 0, &img);  //显示图片
  WCHAR arr[10]; //保存分数
  wsprintf(arr, L"得分:%d", score); //分数放在arr中
  outtextxy(0, 0, arr); //显示分数
  for (int y = 0; y < ROW; y++)
    for (int x = 0; x < COL; x++)
    {
      switch (map[y][x])
      {
      case SPACE:
        break;
      case WALL:
        setlinecolor(RED);  //边框线条颜色
        setfillcolor(RGB(187, 255, 255));  //填充颜色
        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);  //画矩形
        break;
      case SNAKE:
        setlinecolor(RGB(78, 238, 148));
        setfillcolor(WHITE);
        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
        break;
      case HEAD:
        switch (rand() % 7)
        {
        case 0:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RED);
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 1:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(WHITE);
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 2:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(100, 149, 237));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 3:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(127, 255, 0));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
          break;
        case 4:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(176, 224, 230));
          fillrectangle(x * 10, y * 10+20, x * 10 + 10, y * 10 + 30);
          break;
        case 5:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(102, 139, 139));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 +30);
          break;
        case 6:
          setlinecolor(RGB(78, 238, 148));
          setfillcolor(RGB(46, 139, 87));
          fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 +30);
          break;
        default:
          break;
        }
        break;
      case FOOD:
        setlinecolor(WHITE);
        setfillcolor(RED);
        fillrectangle(x * 10, y * 10 + 20, x * 10 + 10, y * 10 + 30);
      }
    }
  EndBatchDraw(); //结束绘图
}
图片,歌曲要自己插入,图片格式要对,jpeg我试过不行,歌曲要是wav格式(直接修改没用,要借助格式转换器才行,这个搜一下就可以了)。

7.感想
这个小游戏拖了好长时间,又是长时间摸鱼....还是有很多地方还是不足的,至于那个贪吃蛇自己找路吃食物...目前实现不了,bfs不会用呀...
慢慢来吧。




如有不对,欢迎指正。


关注下面的标签,发现更多相似文章