废话不多说,直接上代码:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<windows.h>
#define WIDE 42
#define HEIGHT 22
#define up 2
#define down 8
#define left 4
#define right 6//绝对方向 上下左右(相对蛇的方向为 前后左右)
int map[HEIGHT][WIDE];//地图
typedef struct Snake {//蛇的节点
int x;
int y;
struct Snake *next;
struct Snake *back;
}snake;
int Front = right;//当前蛇的方向
int hasFood = 0;//是否有食物
void InitSanke(snake *sHead);//初始化蛇
void Init(snake *sHead);//初始化地图
void Draw(snake *sHead);//绘制函数
void CreateFood();//产生食物
void Move(snake *sHead);//移动
void TurnMove(snake* sHead);//转向
int AddLength(snake *sHead, snake *s);//增加长度
int main()
{
snake *sHead = NULL, *s = NULL;
sHead = (snake*)malloc(sizeof(snake));
sHead->x = 10;
sHead->y = 20;
sHead->next = NULL;
sHead->back = NULL;
Init(sHead);
CreateFood();
Draw(sHead);
while (1)
{
system("cls");//Windows下的清屏函数
Move(sHead);
TurnMove(sHead);
if (AddLength(sHead, s) == 0)
break;
CreateFood();
Draw(sHead);
Sleep(500);//睡眠
}
return 0;
}
void InitSanke(snake *sHead)//初始化蛇 三个节点
{
snake *p, *q = NULL;
int i;
p = sHead;
for (i = 0; i < 3; i++)
{
q = (snake*)malloc(sizeof(snake));
q->x = 10;
q->y = 20 - i - 1;
q->next = NULL;
q->back = NULL;
p->next = q;
q->back = p;
p = p->next;
}
}
void Init(snake *sHead)//初始化地图
{
int i, j, x = 10, y = 20;
for (i = 0; i < HEIGHT; i++)
for (j = 0; j < WIDE; j++)
map[i][j] = 0;
for (i = 0; i < HEIGHT; i++)
{
map[i][0] = 1;
map[i][WIDE - 1] = 1;
}
for (i = 0; i < WIDE; i++)
{
map[0][i] = 1;
map[HEIGHT - 1][i] = 1;
}
InitSanke(sHead);
}
void Draw(snake *sHead)//画地图
{
int i, j;
snake *s = sHead;
while (s != NULL)
{
map[s->x][s->y] = 1;
s = s->next;
}
for (i = 0; i<HEIGHT; i++)
{
for (j = 0; j<WIDE; j++)
{
if (map[i][j] == 0)
printf(" ");//0表示什么都没有
if (map[i][j] == 1)
printf("*");//1表示蛇的节点和墙壁
if (map[i][j] == 2)
printf("+");//2表示食物
}
printf("\n");
}
for (i = 1; i<HEIGHT - 1; i++)
for (j = 1; j<WIDE - 1; j++)
{
if (map[i][j] != 2)//消除上一幅除过食物和墙壁以外的所有东西
map[i][j] = 0;
}
}
void CreateFood()//产生食物
{
int x, y;
srand((unsigned)(time(NULL)));
x = rand() % 20 + 1;
y = rand() % 40 + 1;
if (hasFood == 0)
{
map[x][y] = 2;
hasFood = 1;
}
}
void Move(snake *sHead)//简单的移动
{
snake *p = sHead;
while (p->next != NULL)
p = p->next;
switch (Front)
{
case up:
while (p->back != NULL)
{
p->x = p->back->x;
p->y = p->back->y;
p = p->back;
}
p->x--;
break;
case down:
while (p->back != NULL)
{
p->x = p->back->x;
p->y = p->back->y;
p = p->back;
}
p->x++;
break;
case left:
while (p->back != NULL)
{
p->x = p->back->x;
p->y = p->back->y;
p = p->back;
}
p->y--;
break;
case right:
while (p->back != NULL)
{
p->x = p->back->x;
p->y = p->back->y;
p = p->back;
}
p->y++;
break;
default:printf("error");
}
}
void TurnMove(snake* sHead)//转向
{
char ch;
while (_kbhit())
{
ch = _getche();
switch (ch)
{
case '2':
if (Front == left) { sHead->x++; sHead->y++; }
if (Front == right) { sHead->x++; sHead->y--; }
if (Front == left || Front == right)
Front = down;
break;
case '8':
if (Front == left) { sHead->x--; sHead->y++; }
if (Front == right) { sHead->x--; sHead->y--; }
if (Front == left || Front == right)
Front = up;
break;
case '4':
if (Front == up) { sHead->x++; sHead->y--; }
if (Front == down) { sHead->x--; sHead->y--; }
if (Front == up || Front == down)
Front = left;
break;
case '6':
if (Front == up) { sHead->x++; sHead->y++; }
if (Front == down) { sHead->x--; sHead->y++; }
if (Front == up || Front == down)
Front = right;
break;
}
}
}
int AddLength(snake *sHead, snake *s)//增加长度 同时判断是否撞到墙或者自己
{
snake *p;
int x = sHead->x - sHead->next->x;
int y = sHead->y - sHead->next->y;//通过头节点和第二节点的差值判断当前方向
p = sHead;
while (p->next != NULL)
p = p->next;
s = (snake*)malloc(sizeof(snake));
if (map[sHead->x][sHead->y] == 2)//吃到食物
{
s->x = (p->x - p->back->x) + p->x;
s->y = (p->y - p->back->y) + p->y;
p->next = s;
s->back = p;
s->next = NULL;
hasFood = 0;
map[sHead->x + x][sHead->y + y] = 0;
return 1;
}
else if (map[sHead->x][sHead->y] == 1)//撞到墙或者自己
return 0;
else
return -1;
}
注意这是在vs2017下的程序,如果在CodeBlocks中有些函数需要修改,例如_kbhit()改为kbhit()。
AddLength函数顺便进行了碰撞检测,并且通过头节点和第二节点X,Y坐标的差值判断dang。
需要注意的是绘制相对于后台数据计算晚一步,所以在进行碰撞检测时直接检测头部所在的位置的值而不是下一个位置的值。
这算是很简单的贪吃蛇了,可以帮助没有基础的人了解游戏循环的过程,当然也有很多厉害的大神的代码可以去参考。