代码使用链表完成,比较容易理解,附上源码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
//定义蛇的方向
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
//蛇身节点
typedef struct SNAKE
{
int x;
int y;
struct SNAKE *next;
}snake;
typedef enum GAME_STATUS
{
normal = 0, //游戏正常
wall, //撞墙
oneself, //咬到自己
end, //主动退出
}game_status;
//全局变量
int score, add = 10; //总得分和每次吃食物得分
int status; //方向状态
int sleeptime = 200; //运行时间间隔
snake *head,*food; //蛇头指针和食物指针
snake *q; //遍历蛇身指针
game_status game = normal;
//函数声明
void Pos(int x,int y); //初始化坐标
void createMap(); //创建地图
void initSnake(); //初始化蛇
int biteSelf(); //判断是否咬到自己
void createFood(); //出现食物
void cantCrossWall(); //不能撞墙
void snakeMove(); //蛇移动
void Pause(); //暂停
void runGame(); //游戏运行
void initGame();
void endGame();
void gameStart();
void Pos(int x,int y)
{
COORD pos; //COORD坐标结构体
//HANDLE是一个Windows API 类型,用于表示一个句柄,在这里,它将用于存储标准输出设备的句柄
HANDLE output;
pos.X = x;
pos.Y = y;
output = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出设备的句柄
SetConsoleCursorPosition(output,pos); //将控制台光标设置为pos的坐标
}
void createMap()
{
//一个方块占两个字符
for(int i=0;i<58;i += 2)
{
Pos(i,0);
printf("■");
Pos(i,26);
printf("■");
}
for(int y=0;y<26;y++)
{
Pos(0,y);
printf("■");
Pos(56,y);
printf("■");
}
}
void initSnake()
{
snake *tail;
tail = (snake *)malloc(sizeof(snake));
tail->x = 24; //初始化的位置
tail->y = 5;
tail->next = NULL;
//蛇身初始化长度为5
for(int i=1;i<5;i++)
{
head = (snake*)malloc(sizeof(snake));
head->next = tail;
head->x = 24 + (i * 2);
head->y = 5;
//将新创建的节点地址赋给tail,也就是tail始终是最新的节点
tail = head;
}
while(tail != NULL)
{
Pos(tail->x,tail->y);
printf("■");
tail = tail->next;
}
}
int biteSelf()
{
snake *self;
self = head->next;
while(self != NULL)
{
//身子任意节点和头重合
if(self->x == head->x && self->y == head->y)
{
return 1;
}
self = self->next;
}
return 0;
}
void createFood()
{
snake *food_1;
int vaildPosition = 0;
static int seedInitalized = 0;
//只初始化一次srand()
if(!seedInitalized)
{
srand(time(NULL));
seedInitalized = 1;
}
while(!vaildPosition)
{
food_1 = (snake*)malloc(sizeof(snake));
//需要先让food_1初始化,否则可能会陷入死循环
do {
food_1->x = rand() % 52 + 2;
}while((food_1->x % 2) != 0);
food_1->y = rand() % 24 + 1;
vaildPosition = 1;
q = head;
//判断蛇神是否和食物重合,重合食物重新生成
while(q != NULL)
{
if(q->x == food_1->x && q->y == food_1->y)
{
vaildPosition = 0;
free(food_1);
break;
}
q = q->next;
}
}
Pos(food_1->x,food_1->y);
food = food_1;
printf("■");
}
void cantCrossWall() //不能穿墙
{
if(head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
{
game = wall;
endGame();
}
}
void snakeMove()
{
snake *nexthead; //表示新节点(从头插入)
cantCrossWall();
nexthead = (snake*)malloc(sizeof(snake));
if(status == UP)
{
//新节点的坐标
nexthead->x = head->x;
nexthead->y = head->y - 1;
}
else if(status == DOWN)
{
nexthead->x = head->x;
nexthead->y = head->y + 1;
}
else if(status == RIGHT)
{
nexthead->x = head->x + 2;
nexthead->y = head->y;
}
else if(status == LEFT)
{
nexthead->x = head->x - 2;
nexthead->y = head->y;
}
//如果新的头节点和食物重合
if(nexthead->x == food->x && nexthead->y == food->y)
{
//更新头节点
nexthead->next = head;
head = nexthead;
q = head;
while(q != NULL)
{
Pos(q->x,q->y);
printf("■");
q = q->next;
}
score = score + add;
createFood();
}
else
{
//释放尾节点
nexthead->next = head;
head = nexthead;
q = head;
while(q->next->next != NULL)
{
Pos(q->x,q->y);
printf("■");
q = q->next;
}
Pos(q->next->x,q->next->y);
printf(" ");
free(q->next);
q->next = NULL;
}
if(biteSelf() == 1)
{
game = oneself;
endGame();
}
}
void Pause()
{
while(1)
{
Sleep(300);
if(GetAsyncKeyState(VK_SPACE))
{
break;
}
}
}
void runGame()
{
Pos(64, 15);
printf("不能穿墙,不能咬到自己\n");
Pos(64, 16);
printf("用↑.↓.←.→分别控制蛇的移动.");
Pos(64, 17);
printf("F1 为加速,F2 为减速\n");
Pos(64, 18);
printf("ESC :退出游戏.space:暂停游戏.");
status = RIGHT;
while(1)
{
Pos(64, 10);
printf("得分:%d ", score);
Pos(64, 11);
printf("每个食物得分:%d分", add);
//上下左右互斥
if(GetAsyncKeyState(VK_UP) && status != DOWN)
{
status = UP;
}
else if(GetAsyncKeyState(VK_DOWN) && status != UP)
{
status = DOWN;
}
else if(GetAsyncKeyState(VK_LEFT) && status != RIGHT)
{
status = LEFT;
}
else if(GetAsyncKeyState(VK_RIGHT) && status != LEFT)
{
status = RIGHT;
}
else if(GetAsyncKeyState(VK_SPACE))
{
Pause();
}
else if(GetAsyncKeyState(VK_ESCAPE))
{
game = end;
break;
}
else if(GetAsyncKeyState(VK_F1))
{
if(sleeptime >= 50)
{
sleeptime -= 30;
add += 2;
}
}
else if(GetAsyncKeyState(VK_F2))
{
if(sleeptime < 350)
{
sleeptime += 30;
add -= 2;
}
else
{
sleeptime = 350;
add = 1;
}
}
Sleep(sleeptime);
snakeMove();
}
}
void initGame()
{
Pos(40, 12);
printf("欢迎来到贪食蛇游戏!");
system("pause");
system("cls");
Pos(25, 12);
printf("用↑.↓.←.→分别控制蛇的移动, F1 为加速,2 为减速\n");
Pos(25, 13);
printf("加速将能得到更高的分数。\n");
system("pause");
system("cls");
}
void endGame()
{
system("cls");
Pos(24,12);
if(game == wall)
{
printf("对不起,您撞到墙了。游戏结束.");
}
else if(game == oneself)
{
printf("对不起,您咬到自己了。游戏结束.");
}
else if(game == end)
{
printf("您的游戏已经结束了。");
}
Pos(24,13);
printf("您的得分是%d\n", score);
printf("close?[y]");
while (getchar() != 'y')
{
printf("close?[y]");
}
//释放蛇所有节点
snake * p = NULL;
q = head;
while(q != NULL)
{
p = q;
q = q->next;
free(p);
}
exit(0);
}
void gameStart()
{
system("mode con cols=100 lines=30"); //设置控制台尺寸
initGame();
createMap();
initSnake();
createFood();
}
int main()
{
gameStart();
runGame();
endGame();
return 0;
}