C语言经典项目 ---- 贪吃蛇

今天我们来回顾一下简单版贪吃蛇的基础实现

目录

1.基础功能介绍

2.游戏核心逻辑实现分析

2.0 准备工作

2.1 游戏主逻辑

2.2 游戏开始(GameStart)

2.2.1打印欢迎界面

2.2.2创建地图

2.2.3 初始化蛇身

2.2.4 创建第一个食物

2.3 游戏运行(GameRun)

2.3.1打印地图旁边的帮助信息

2.3.2 检测按键状态

2.3.3 蛇身移动

2.3.3.1 EatFood

2.3.3.2 NoFood

2.3.3.3 KillByWall

2.3.3.4 KillBySelf

2.4 游戏结束

3.完整代码

test.cpp

Snake.c

Snake.h


1.基础功能介绍

使⽤C语⾔在Windows环境的控制台中模拟实现经典⼩游戏贪吃蛇。
实现基本的功能:

贪吃蛇地图绘制

蛇吃⻝物的功能 (上、下、左、右⽅向键控制蛇的动作)

蛇撞墙死亡

蛇撞⾃⾝死亡

计算得分

蛇⾝加速、减速

暂停游戏

基础操作界面如上图所示:

2.游戏核心逻辑实现分析

##此游戏窗口设置为30行 100列,游戏地图大小设置为27行,58列

2.0 准备工作

在游戏开始之前,我们需要用结构体,枚举,链表对游戏状态,蛇身,方向以及贪吃蛇游戏各项数据的维护。

enum Game_Status//游戏状态
{
	OK,
	KILL_BY_WALL,
	KILL_BY_SELF,
	END_NORMAL
};
enum DIRECTION//移动方向
{
	UP=1,
	DOWN,
	LEFT,
	RIGHT
};

//创建链表节点
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode,* pSnakeNode;

//创建结构体来维护贪吃蛇所有需要的信息
typedef struct Snake
{
	pSnakeNode  _pSnake;//蛇头节点
	pSnakeNode  _Food;//食物节点
	int _Score;//总分数
	int _FoodWeight;//单个食物的分数
	enum DIRECTION _Dir;//方向
	enum Game_Status _Status;//游戏状态
	int _SleepTime;//休眠时间
}Snake,* pSnake;

由于涉及到光标位置设置,我们分装一个光标位置设定函数

//涉及到光标位置设定,我们在此分装一个函数
void SetPos(short x, short y)
{
	COORD pos = { x,y };
	//获取操作柄
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置光标坐标
	SetConsoleCursorPosition(hOutput, pos);
}

 涉及到多次宽字符的打印,我们提前用宏替换掉

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'

2.1 游戏主逻辑

程序开始就设置程序⽀持本地模式,然后进⼊游戏的主逻辑。
主逻辑分为3个过程:
游戏开始(GameStart)完成游戏的初始化
游戏运⾏(GameRun)完成游戏运⾏逻辑的实现
游戏结束(GameEnd)完成游戏结束的说明,实现资源释放

 

2.2 游戏开始(GameStart)

这个模块完成游戏的初始化任务:
控制台窗⼝⼤⼩的设置
控制台窗⼝名字的设置
⿏标光标的隐藏
打印欢迎界⾯
创建地图
初始化蛇身
创建第⼀个⻝物
void GameStart(pSnake ps)
{
    //设置控制台大小
    system("mode con cols=100 lines=30");
    //设置控制台名称
    system("title 贪吃蛇");

    //隐藏鼠标光标
    //获取标准输出柄
    HANDLE houtput =  GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(houtput,&CursorInfo);
    CursorInfo.bVisible = false;
    SetConsoleCursorInfo(houtput,&CursorInfo);

    //打印欢迎界⾯
    Welcome();
    //创建地图
    CreateMap();
    //初始化第蛇
    InitSnake(ps);
    //创建第⼀个⻝物
    CreateFood(ps);
}

2.2.1打印欢迎界面

void Welcome()
{
	SetPos(40, 15);
	printf("欢迎来到贪吃蛇⼩游戏");
	SetPos(40, 25);//让按任意键继续的出现的位置好看点
	system("pause");
	system("cls");
	SetPos(25, 12);
	printf("⽤ ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
	SetPos(25, 13);
	printf("加速将能得到更⾼的分数。\n");
	SetPos(40, 25);//让按任意键继续的出现的位置好看点
	system("pause");
	system("cls");
}

2.2.2创建地图

void CreateMap()
{
	//行的数据是从56,0 56,26
	for (int i = 0; i <= 56; i += 2)
	{
		SetPos(i, 0);
		wprintf(L"%lc", WALL);
	}
	for (int i = 0; i <= 56; i += 2)
	{
		SetPos(i, 26);
		wprintf(L"%lc", WALL);
	}
	//列的数据是从0,25 ,56,25
	for (int i = 1; i <= 25; i ++)
	{
		SetPos(0,i);
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

2.2.3 初始化蛇身

蛇最开始⻓度为5节,每节对应链表的⼀个节点,蛇⾝的每⼀个节点都有⾃⼰的坐标。
创建5个节点,然后将每个节点存放在链表中进⾏管理。创建完蛇⾝后,将蛇的每⼀节打印在屏幕上。
蛇的初始位置从 (24,5) 开始。
再设置当前游戏的状态,蛇移动的速度,默认的⽅向,初始成绩,每个⻝物的分数。
游戏状态是:OK
蛇的移动速度:200毫秒
蛇的默认⽅向:RIGHT
初始成绩:0
每个⻝物的分数:10
void InitSnake(pSnake ps)
{
	pSnakeNode cur = NULL;
	//初始化蛇身节点
	for (int i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake()::malloc()");
			exit(1);
		}
		//设置节点位置
		cur->next = NULL;
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;

		//打印蛇身
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);

		//头插法
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake = cur;
		}
		else
		{
			cur->next = ps->_pSnake;
			ps->_pSnake = cur;
		}
	}
	//初始化蛇身数据
	ps->_Score = 0;
	ps->_Dir = RIGHT;
	ps->_SleepTime = 200;
	ps->_Status = OK;
	ps->_FoodWeight = 10;
}

2.2.4 创建第一个食物

首先随机创建在范围中的横竖坐标,然后判断是否和蛇身重复                                                           随后打印食物,注意不能打印在墙上

void CreateFood(pSnake ps)
{
	//选取食物的坐标
	int x = 0, y = 0;
again:
	do
	{
		x = rand() % 53 + 2;//2~54
		y = rand() % 25 + 1;//1~25
	} while (x % 2 != 0);
	//判断食物坐标是否与蛇身重合
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//将food结点放进去
	pSnakeNode newfoodnode = (pSnakeNode*)malloc(sizeof(SnakeNode));
	if (newfoodnode == NULL)
	{
		perror("CreateFood()::malloc");
		exit(1);
	}
	else {
		newfoodnode->x = x;
		newfoodnode->y = y;
		newfoodnode->next = NULL;
	}//打印食物
	SetPos(x, y);
	wprintf(L"%lc", FOOD);

	ps->_Food = newfoodnode;
}

2.3 游戏运行(GameRun)

游戏运⾏期间,右侧打印帮助信息,
根据游戏状态检查游戏是否继续,如果是状态是OK,游戏继续,否则游戏结束。
如果游戏继续,就是检测按键情况,确定蛇下⼀步的⽅向,或者是否加速减速,是否暂停或者退出游
戏。
需要的虚拟按键的罗列:
上:VK_UP
下:VK_DOWN
左:VK_LEFT
右:VK_RIGHT
空格:VK_SPACE
ESC:VK_ESCAPE
F3:VK_F3
F4:VK_F4
void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		SetPos(64, 10);
		printf("得分 = %d", ps->_Score);
		printf("每个食物分数 = %d", ps->_FoodWeight);
		if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NORMAL;
			break;
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (ps->_FoodWeight < 18)
			{
				ps->_SleepTime -= 30;
				ps->_FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			if (ps->_FoodWeight >2)
			{
				ps->_SleepTime += 30;
				ps->_FoodWeight -= 2;
			}
		}
		//蛇休眠
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

2.3.1打印地图旁边的帮助信息

void PrintHelpInfo()
{
 //打印提⽰信息
 SetPos(64, 15);
 printf("不能穿墙,不能咬到⾃⼰\n");
 SetPos(64, 16);
 printf("⽤↑.↓.←.→分别控制蛇的移动.");
 SetPos(64, 17);
 printf("F3 为加速,F4 为减速\n");
 SetPos(64, 18);
 printf("ESC :退出游戏.space:暂停游戏.");
 SetPos(64, 20);
}

2.3.2 检测按键状态

我们需要检测按键状态来判断蛇的移动,那么我们会需要一个叫做GetAsyncKeyState(VK)函数来进行判断,它会返回二进制的最小一位,那么我们可以通过这个来分装一个宏:

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK))&0x1?1:0) 

这样按下会返回不等于0的数,反之返回0

2.3.3 蛇身移动

先创建下⼀个节点,根据移动⽅向和蛇头的坐标,蛇移动到下⼀个位置的坐标。
确定了下⼀个位置后,看下⼀个位置是否是⻝物(NextIsFood),是⻝物就做吃⻝物处理
(EatFood),如果不是⻝物则做前进⼀步的处理(NoFood)。
蛇⾝移动后,判断此次移动是否会造成撞墙(KillByWall)或者撞上⾃⼰蛇⾝(KillBySelf),从⽽影
响游戏的状态。
void SnakeMove(pSnake ps)
{
	//创建下一个节点
	pSnakeNode pNextNode = (pSnakeNode*)malloc(sizeof(SnakeNode));
	if (pNextNode == NULL)
	{
		perror("SnakeMove()::malloc");
		exit(1);
	}
	switch (ps->_Dir)
	{
	case UP:
		pNextNode->x = ps->_pSnake->x;
		pNextNode->y = ps->_pSnake->y - 1;
		break; 
	case DOWN:
		pNextNode->x = ps->_pSnake->x;
		pNextNode->y = ps->_pSnake->y + 1;
		break;
	case RIGHT:
		pNextNode->x = ps->_pSnake->x + 2;
		pNextNode->y = ps->_pSnake->y;
		break;
	case LEFT:
		pNextNode->x = ps->_pSnake->x - 2;
		pNextNode->y = ps->_pSnake->y;
		break;
	}
	if ((pNextNode->x == ps->_Food->x) &&
		(pNextNode->y == ps->_Food->y))
		EatFood(pNextNode, ps);
	else
		NoFood(pNextNode, ps);
	KillByWall(ps);
	KillBySelf(ps);
}
2.3.3.1 EatFood
void EatFood(pSnakeNode psn, pSnake ps)
{
	//头插
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;

	//打印蛇身
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		SetPos(cur->x,cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//加上得分
	ps->_Score += ps->_FoodWeight;
	//释放食物节点并重新创建食物
	free(ps->_Food);
	CreateFood(ps);
}
2.3.3.2 NoFood
void NoFood(pSnakeNode psn, pSnake ps)
{
	//头插
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;

	//打印
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}
2.3.3.3 KillByWall
int KillByWall(pSnake ps)
{
	if ((ps->_pSnake->x == 0)
		|| (ps->_pSnake->x == 56)
		|| (ps->_pSnake->y == 0)
		|| (ps->_pSnake->y == 26))
	{
		ps->_Status = KILL_BY_WALL;
		return 1;
	}
	return 0;
}
2.3.3.4 KillBySelf
int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if (ps->_pSnake->x == cur->x &&
			ps->_pSnake->y == cur->y)
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

2.4 游戏结束

游戏状态不再是OK(游戏继续)的时候,要告知游戏结束的原因,并且释放蛇⾝节点
void GameEnd(pSnake ps)
{
	SetPos(24, 12);
	switch (ps->_Status)
	{
	case KILL_BY_SELF:
		printf("您撞到自己了\n");
		break;
	case KILL_BY_WALL:
		printf("您撞墙了\n");
		break;
	case END_NORMAL:
		printf("退出\n");
		break;
	}

	//释放节点
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		pSnakeNode next = cur->next;
		free(cur);
		cur = next;
	}
}

3.完整代码

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"

void test()
{
    char ch;
    do {
        system("cls");
        Snake ps = { 0 };
        GameStart(&ps);
        GameRun(&ps);
        GameEnd(&ps);
        SetPos(20, 15);
        printf("再来一局吗(Y/N)?");
        ch = getchar();
        while (getchar() != '\n'); //把除了enter的字符全读掉
    } while (ch == 'Y' || ch == 'y');
        SetPos(0, 27);

}

int main()
{
    srand((unsigned int)time(NULL));
    //本地初始化
    setlocale(LC_ALL, "");
    test();
    return 0;
}

Snake.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"

void SetPos(short x, short y)
{
	COORD pos = { x,y };
	//获取操作柄
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置光标坐标
	SetConsoleCursorPosition(hOutput, pos);
}

void Welcome()
{
	SetPos(40, 15);
	printf("欢迎来到贪吃蛇⼩游戏");
	SetPos(40, 25);//让按任意键继续的出现的位置好看点
	system("pause");
	system("cls");
	SetPos(25, 12);
	printf("⽤ ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");
	SetPos(25, 13);
	printf("加速将能得到更⾼的分数。\n");
	SetPos(40, 25);//让按任意键继续的出现的位置好看点
	system("pause");
	system("cls");
}

void CreateMap()
{
	//行的数据是从56,0 56,26
	for (int i = 0; i <= 56; i += 2)
	{
		SetPos(i, 0);
		wprintf(L"%lc", WALL);
	}
	for (int i = 0; i <= 56; i += 2)
	{
		SetPos(i, 26);
		wprintf(L"%lc", WALL);
	}
	//列的数据是从0,25 ,56,25
	for (int i = 1; i <= 25; i ++)
	{
		SetPos(0,i);
		wprintf(L"%lc", WALL);
	}
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}


void InitSnake(pSnake ps)
{
	pSnakeNode cur = NULL;
	//初始化蛇身节点
	for (int i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake()::malloc()");
			exit(1);
		}
		//设置节点位置
		cur->next = NULL;
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;

		//打印蛇身
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);

		//头插法
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake = cur;
		}
		else
		{
			cur->next = ps->_pSnake;
			ps->_pSnake = cur;
		}
	}
	//初始化蛇身数据
	ps->_Score = 0;
	ps->_Dir = RIGHT;
	ps->_SleepTime = 200;
	ps->_Status = OK;
	ps->_FoodWeight = 10;
}

void CreateFood(pSnake ps)
{
	//选取食物的坐标
	int x = 0, y = 0;
again:
	do
	{
		x = rand() % 53 + 2;//2~54
		y = rand() % 25 + 1;//1~25
	} while (x % 2 != 0);
	//判断食物坐标是否与蛇身重合
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//将food结点放进去
	pSnakeNode newfoodnode = (pSnakeNode*)malloc(sizeof(SnakeNode));
	if (newfoodnode == NULL)
	{
		perror("CreateFood()::malloc");
		exit(1);
	}
	else {
		newfoodnode->x = x;
		newfoodnode->y = y;
		newfoodnode->next = NULL;
	}//打印食物
	SetPos(x, y);
	wprintf(L"%lc", FOOD);

	ps->_Food = newfoodnode;
}

void pause()
{
	while (1)
	{
		Sleep(200);
		if (KEY_PRESS(VK_SPACE))
			return;
	}
}
void GameStart(pSnake ps)
{
	//设置控制台大小
	system("mode con cols=100 lines=30");
	//设置控制台名称
	system("title 贪吃蛇");

	//隐藏鼠标光标
	//获取标准输出柄
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(houtput, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(houtput, &CursorInfo);

	//打印欢迎界⾯
	Welcome();
	//创建地图
	CreateMap();
	//初始化第蛇
	InitSnake(ps);
	//创建第⼀个⻝物
	CreateFood(ps);
}

void PrintHelpInfo()
{
	//打印提⽰信息
	SetPos(64, 15);
	printf("不能穿墙,不能咬到⾃⼰\n");
	SetPos(64, 16);
	printf("⽤↑.↓.←.→分别控制蛇的移动.");
	SetPos(64, 17);
	printf("F3 为加速,F4 为减速\n");
	SetPos(64, 18);
	printf("ESC :退出游戏.space:暂停游戏.");
	SetPos(64, 20);
}
void NoFood(pSnakeNode psn, pSnake ps)
{
	//头插
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;

	//打印
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

int KillByWall(pSnake ps)
{
	if ((ps->_pSnake->x == 0)
		|| (ps->_pSnake->x == 56)
		|| (ps->_pSnake->y == 0)
		|| (ps->_pSnake->y == 26))
	{
		ps->_Status = KILL_BY_WALL;
		return 1;
	}
	return 0;
}
int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if (ps->_pSnake->x == cur->x &&
			ps->_pSnake->y == cur->y)
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}
void EatFood(pSnakeNode psn, pSnake ps)
{
	//头插
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;

	//打印蛇身
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	//加上得分
	ps->_Score += ps->_FoodWeight;
	//释放食物节点并重新创建食物
	free(ps->_Food);
	CreateFood(ps);
}

void SnakeMove(pSnake ps)
{
	//创建下一个节点
	pSnakeNode pNextNode = (pSnakeNode*)malloc(sizeof(SnakeNode));
	if (pNextNode == NULL)
	{
		perror("SnakeMove()::malloc");
		exit(1);
	}
	switch (ps->_Dir)
	{
	case UP:
		pNextNode->x = ps->_pSnake->x;
		pNextNode->y = ps->_pSnake->y - 1;
		break;
	case DOWN:
		pNextNode->x = ps->_pSnake->x;
		pNextNode->y = ps->_pSnake->y + 1;
		break;
	case RIGHT:
		pNextNode->x = ps->_pSnake->x + 2;
		pNextNode->y = ps->_pSnake->y;
		break;
	case LEFT:
		pNextNode->x = ps->_pSnake->x - 2;
		pNextNode->y = ps->_pSnake->y;
		break;
	}
	if ((pNextNode->x == ps->_Food->x) &&
		(pNextNode->y == ps->_Food->y))
		EatFood(pNextNode, ps);
	else
		NoFood(pNextNode, ps);
	KillByWall(ps);
	KillBySelf(ps);
}



void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		SetPos(64, 10);
		printf("得分 = %d", ps->_Score);
		printf("每个食物分数 = %2d", ps->_FoodWeight);
		if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NORMAL;
			break;
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (ps->_FoodWeight < 18)
			{
				ps->_SleepTime -= 30;
				ps->_FoodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			if (ps->_FoodWeight >2)
			{
				ps->_SleepTime += 30;
				ps->_FoodWeight -= 2;
			}
		}
		//蛇休眠
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

void GameEnd(pSnake ps)
{
	SetPos(24, 12);
	switch (ps->_Status)
	{
	case KILL_BY_SELF:
		printf("您撞到自己了\n");
		break;
	case KILL_BY_WALL:
		printf("您撞墙了\n");
		break;
	case END_NORMAL:
		printf("退出\n");
		break;
	}

	//释放节点
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		pSnakeNode next = cur->next;
		free(cur);
		cur = next;
	}
}

Snake.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <stdbool.h>
#include <locale.h>
#include <time.h>

#define WALL L'□'
#define POS_X 24
#define POS_Y 5
#define BODY L'●'
#define FOOD L'★'

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK))&0x1?1:0) 
enum Game_Status//游戏状态
{
	OK,
	KILL_BY_WALL,
	KILL_BY_SELF,
	END_NORMAL
};
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

//创建链表节点
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

//创建结构体来维护贪吃蛇所有需要的信息
typedef struct Snake
{
	pSnakeNode  _pSnake;//蛇头节点
	pSnakeNode  _Food;//食物节点
	int _Score;//总分数
	int _FoodWeight;//单个食物的分数
	enum DIRECTION _Dir;//方向
	enum Game_Status _Status;//游戏状态
	int _SleepTime;//休眠时间
}Snake, * pSnake;

//设置光标位置
void SetPos(int x, int y);
//打印欢迎界面
void Welcome();
//创建地图
void CreateMap();
//初始化蛇身体
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);
//运行游戏
void GameRun(pSnake ps);
//结束游戏
void GameEnd(pSnake ps);

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值