从无到有解析【贪吃蛇】

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。
P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

  

一、游戏设计与分析

这个游戏代码我们分成三个文件来完成。

  • Snake.h —— 游戏的头文件
     这个文件中包含游戏代码实现所需要的结构体定义以及函数声明。

  • Snake.c —— 游戏的源文件
     这个文件中是实现游戏操作的代码。

  • test.c —— 游戏的测试文件
     这个文件是用来检验代码能否正常运行。

1、地图

我们最终的贪吃蛇⼤纲要是这个样⼦,那我们的地图如何布置呢?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  这⾥不得不讲⼀下控制台窗⼝的⼀些知识,如果想在控制台的窗⼝中指定位置输出信息,我们得知道该位置的坐标,所以⾸先介绍⼀下控制台窗⼝的坐标知识。
  控制台窗⼝的坐标如下所⽰,横向的是X轴,从左向右依次增⻓,纵向是Y轴,从上到下依次增⻓。
在这里插入图片描述
  在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印⻝物使⽤宽字符★普通的字符是占⼀个字节的,这类宽字符是占⽤2个字节。

(1)、 <locale.h>本地化

  <locale.h>提供的函数⽤于控制C标准库中对于不同的地区会产⽣不⼀样⾏为的部分。
在标准中,依赖地区的部分有以下⼏项:
• 数字量的格式
• 货币量的格式
• 字符集
• ⽇期和时间的表⽰形式

类型

通过修改地区,程序可以改变它的⾏为来适应世界的不同区域。但地区的改变可能会影响库的许多部
分,其中⼀部分可能是我们不希望修改的。所以C语⾔⽀持针对不同的类项进⾏修改,下⾯的⼀个宏,
指定⼀个类项:
• LC_COLLATE:影响字符串⽐较函数strcoll() 和strxfrm() 。
• LC_CTYPE:影响字符处理函数的⾏为。
• LC_MONETARY:影响货币格式。
• LC_NUMERIC:影响printf() 的数字格式。
• LC_TIME:影响时间格式strftime() 和wcsftime() 。
• LC_ALL-针对所有类项修改,将以上所有类别设置为给定的语⾔环境。

(2)、 setlocale函数

1  char* setlocale (int category, const char* locale)

  setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。
  setlocale 的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参数是LC_ALL,就会影响所有的类项。
  C标准给第⼆个参数仅定义了2种可能取值:“C”(正常模式)和""(本地模式)。

 1 setlocale(LC_ALL, "C");

  当地区设置为"C"时,库函数按正常⽅式执⾏,⼩数点是⼀个点。
当程序运⾏起来后想改变地区,就只能显⽰调⽤setlocale函数。⽤""作为第2个参数,调⽤setlocale函数就可以切换到本地模式,这种模式下程序会适应本地环境。
  ⽐如:切换到我们的本地模式后就⽀持宽字符(汉字)的输出等。


 1. setlocale(LC_ALL, " ");//切换到本地环境

(3)、宽字符的打印

  那如果想在屏幕上打印宽字符,怎么打印呢?

  宽字符的字⾯量必须加上前缀“L”,否则C语⾔会把字⾯量当作窄字符类型处理。前缀“L”在单引号前⾯,表⽰宽字符,对应wprintf() 的占位符为 %lc 。在双引号前⾯,表⽰宽字符串,对应wprintf() 的占位符为%ls 。

 #include <stdio.h>
 #include<locale.h>
 
 int main() 
 {
 	setlocale(LC_ALL, "");
    wchar_t ch1 = L'●'; 
	wchar_t ch2 = L'⽐';
 	wchar_t ch3 = L'特';
 	wchar_t ch4 = L'★';
 	printf("%c%c\n", 'a', 'b');
 	
	wprintf(L"%lc\n", ch1);
 	wprintf(L"%lc\n", ch2);
 	wprintf(L"%lc\n", ch3);
 	wprintf(L"%lc\n", ch4);
 	return 0;
 }

在这里插入图片描述
  两个普通字符的大小等于一个宽字符的大小
在这里插入图片描述

2、游戏分析

(1)、Snake.h

  首先,在Snake.h中创建两个结构体:一个蛇的结构体;一个蛇的节点的结构体。

  • 蛇的节点的结构体
      整个蛇身可以看作是一个单链表,所有节点一次连接起来的。
      蛇的一个节点 要包括该点在控制台坐标系上的X轴值和Y轴值,以及该节点的下一个节点

如下:

//蛇身节点类型
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode, * PSnakeNode;
//PSnakeNode是指向该结构体的指针
//eg: PSnakeNode n 等同于 SnakeNode* n
  • 蛇身的结构体
      我们可以想象一下,将舍生看作是一个链表,游戏过程中要将蛇运动起来,要想完成贪吃蛇的运动,我们需要再蛇身中添加那些元素呢?

  整个蛇身要包含 指向蛇头的指针、指向食物节点的指针、蛇的移动方向、游戏状态、应该食物的分数、总成绩、休息时间。

//贪吃蛇
typedef struct Snake
{
	PSnakeNode pSnake; //指向蛇头的指针
	PSnakeNode pFood; //指向食物节点的指针
	enum DIRECTTON dir; //蛇移动的方向
	enum GAME_STATUS status; //游戏状态
	int food_weight; //一个食物的分数
	int score; //总成绩
	int sleep_time; //休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * PSnake;

完成结构体后,我们还要继续分析结构体中的元素。

  • 蛇的移动方向
//蛇移动的方向
enum DIRECTTON
{
	up = 1,
	down,
	left,
	right
};
  • 游戏状态
//游戏状态
//正常,撞墙,撞自己,正常退出,
enum GAME_STATUS
{
	ok,//正常
	KILL_BY_WALL,//撞墙
	KILL_BY_SELF,//撞自己
	END_NORMAL//正常退出
};

(2)、test.c

  在测试文件中,想要打印游戏地图,那要先适应本地化模式,所以我们在main函数中使用setlocale函数适配本地环境。
  为了方便之后的代码测试,我们在main函数中调用一个自定义函数test01。

void test01()
{
	//创建贪吃蛇
	Snake snake = { 0 };
	//一、初始化游戏
	GameStart(&snake);
	//二、运行游戏
	GameRun(&snake);
	//三、结束游戏——善后工作
	GameEnd(&snake);
}
int main()
{
	//先适配本地环境
	setlocale(LC_ALL, "");
	test01();
	return 0;
}

(3)、Snake.c

  接下来,我们简单的将代码的实现分为三部分:

  • 初始化游戏GameStart();

     1.打印环境界面和功能介绍
     2.绘制地图
     3.创建蛇
     4.创建食物
    
  • 运行游戏GameRun();

    1、键盘上的按键情况
    2、蛇每走一步的状态
    3、蛇上下左右走
    4、判断下一个节点是不是食物
    5、判断蛇有没有撞墙或者撞到自己
    
  • 结束游戏——善后工作GameEnd();

二、初始化游戏

在这里插入图片描述

1、打印环境界面和功能介绍

  我们要先获取控制板上光标的信息,对光标进行相应的操作。
这里所要用到的函数我在上一篇文章中已经详细解释过了,所以我们这里直接使用。

	//隐藏光标,将光标设置到指定位置
	//设置面板
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	//获取标准输出设备的句柄
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定义一个光标信息结构体
	CONSOLE_CURSOR_INFO cursor_info = { 0 };
	//获取光标信息
	GetConsoleCursorInfo(houtput, &cursor_info);
	//设置光标可见度
	cursor_info.bVisible = false;
	//设置光标信息
	SetConsoleCursorInfo(houtput, &cursor_info);

  我们要定位光标,在相应位置打印相应的文字。
这里可以创建一个函数SetPos,来定位光标

//获取光标位置
void SetPos(int x, int y)
{
	//获取标准输出设备的句柄
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置光标位置
	COORD pos = { x, y };
	SetConsoleCursorPosition(houtput, pos);
}

得到光标以后,就可以进行下一步操作:

void WelcomeToGame()
{
	SetPos(35, 12);
	wprintf(L"欢迎来到贪吃蛇小游戏\n");
	SetPos(37, 20);
	system("pause");//暂停
	system("cls");//清理屏幕

	SetPos(22, 12);
	wprintf(L"用↑.←.↓.→来控制蛇的移动方向,按F3加速,按F4减速\n");
	SetPos(35, 15);
	wprintf(L"加速可以得到更高的分数!\n");
	SetPos(37, 20);
	system("pause");
	system("cls");

}

这样就可以得到我们的游戏介绍
在这里插入图片描述
在这里插入图片描述

2、绘制地图

  我们假设实现⼀个棋盘27⾏,58列的棋盘(⾏和列可以根据⾃⼰的情况修改),再围绕地图画出墙,
如下:
在这里插入图片描述
打印墙,要先定位光标,在光标出打印‘□’就可以了。
注:X轴:一个方块占两个X坐标
  Y轴:一个方块占一个Y坐标

在这里插入图片描述
这里我们在头文件中定义一个墙,以方便我们以后想要把墙换成其他的图案

#define WALL L'□'
  • 上面一行,光标定位在(0.0),打印29个‘□’。
  • 下面一行,光标定位在(0.26),打印29个‘□’。
  • 左边一列,(0.0)处已有‘□’,所以从Y=1处开始打印。以此向下打印26个‘□’,所以光标定位在(0.i)处。
  • 右边一列,同左边一样,光标定位在(56.i)处。
//2,绘制地图
void CreateMap()
{
	int i = 0;
	//上
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
	
}

这样就得到了墙体。

3、创建蛇

  初始时,我们让蛇身有五个节点,我们可以用for循环来申请五个节点的空间,要求五个节点的坐标是挨着的,我们使用头插法将五个节点连接。
  节点的Y值一定是相等的,所以我们只需要考虑X坐标,X轴上是一个‘□’占两个坐标,所以每个节点的X坐标值差2。
  先给第一个节点一个初始值,先定为(16,5),所以五个节点的坐标为:X:16+2*i; Y:5;  这里也可以将第一个节点的坐标和蛇身图案在Snake.h文件中定义一下,方便以后的修改

#define pos_x 16
#define pos_y 5
#define BODY L'●'

有了上述分析,所以我们就可以用for循环和头插法将初始蛇身打印出来。

void InitSnake(PSnake sk)
{
	PSnakeNode cur = NULL;
	//循环五次,创建五个节点
	for (int i = 0; i < 5; i++)
	{
		cur = (PSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake()::malloc");
			return;
		}
		cur->next = NULL;
		//坐标
		cur->x = pos_x + 2 * i;
		cur->y = pos_y;

		//头插法插入链表
		if (sk->pSnake == NULL) //空链表
		{
			sk->pSnake = cur;
		}
		else //非空
		{
			cur->next = sk->pSnake;
			sk->pSnake = cur;
		}
	}
	//打印蛇身
	cur = sk->pSnake;
	while (cur)//遍历所有节点
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
}

在这里插入图片描述
这里我们也要将蛇身的一些属性在InitSnake()函数中设置出来

//设置贪吃蛇的属性
	sk->dir = right;//蛇开始时向右走
	sk->score = 0;//总成绩开始时为0
	sk->food_weight = 10;//一个食物得分为10
	sk->status = ok;//游戏起始状态为OK
	sk->sleep_time = 200;//单位为毫秒

4、创建食物

  食物的坐标要求:x坐标值必需是2的倍数、食物坐标不能和蛇的身体坐标以及墙的坐标冲突、每次打开游戏都要随机生成食物。
  首先,根据墙的坐标,我们可以确定食物X坐标值的范围为2 ~ 54,Y坐标值范围为1~25。
  生成随机值,我们要用到rand函数,使用此函数要在main函数中包含

srand((unsigned int)time(NULL));

生成随机坐标,并且X 值为2的倍数,可以用do while循环来实现。

again:
	do
		{
			x = rand() % 53 + 2;//用rand生成随机数
			y = rand() % 25 + 1;
		} while (x % 2 != 0);

然后,遍历已有的蛇身和食物坐标比较,是否重合,如果重合就重新生成随机值,所以需要再do while循环前加again:保证再一次进入循环生成新的坐标。

  	PSnakeNode cur = sk->pSnake;
	while (cur)//遍历所有的节点坐标
	{
		//如果食物和蛇身体冲突,就重新生成随机值
		if (x == cur->x && y == cur->y)
			goto again;
		cur = cur->next;
	}

接下来创造食物节点并打印食物
在头文件中定义一个食物,反比以后需要改变食物图案

#define FOOD L'★'
//创建食物节点
	PSnakeNode Food = (PSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL)
	{
		perror("CreateFood()::malloc");
		return;
	}

	Food->x = x;
	Food->y = y;
	Food->next = NULL;

	//打印食物
	SetPos(x, y);//定位光标
	wprintf(L"%lc", FOOD);

做完这些,不用忘记将创建好的食物放到结构体中的食物中

sk->pFood = Food;//将创建好的食物放到结构体的食物节点中

在这里插入图片描述

综上所述,创建食物的完整代码为:

void CreateFood(PSnake sk)
{
	int x = 0;//食物的坐标
	int y = 0;
	//食物的x坐标值必需是2的倍数
	//x: 2~54;   y:1~25
again:
	do
	{
		x = rand() % 53 + 2;//用rand生成随机数
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	//食物坐标不能和蛇的身体坐标冲突
	PSnakeNode cur = sk->pSnake;
	while (cur)//遍历所有的节点坐标
	{
		//如果食物和蛇身体冲突,就重新生成随机值
		if (x == cur->x && y == cur->y)
			goto again;
		cur = cur->next;
	}
	//创建食物节点
	PSnakeNode Food = (PSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL)
	{
		perror("CreateFood()::malloc");
		return;
	}

	Food->x = x;
	Food->y = y;
	Food->next = NULL;

	//打印食物
	SetPos(x, y);//定位光标
	wprintf(L"%lc", FOOD);
	
	sk->pFood = Food;//将创建好的食物放到结构体的食物节点中
}

三、运行游戏

在这里插入图片描述

1、打印帮助信息

我们在地图的右侧打印出游戏的帮助信息

//打印帮助信息
void PrintfHelpInfo()
{
	SetPos(64, 14);
	wprintf(L"%ls", L"不能穿墙,不能撞到自己");
	SetPos(64, 16);
	wprintf(L"%ls", L"用↑.←.↓.→.来控制蛇的方向");
	SetPos(64, 18);
	wprintf(L"%ls", L"按Ctrl加速,按Alt减速");
	SetPos(64, 20);
	wprintf(L"%ls", L"按ESC结束游戏,按空格键暂停游戏");
	
}

在这里插入图片描述

接下来用一个do while循环,在游戏状态为OK的时候运行游戏
先在循环中打印出食物成绩和总成绩

do
{
	//打印总分数和食物分数
	SetPos(64, 8);
	printf("总分数:%d", sk->score);
	SetPos(64, 10);
	printf("食物分数:%2d", sk->food_weight );
}while (sk->status == ok);

在这里插入图片描述

2、键盘上的按键情况

  判断按键情况要用到GetAsyncKeyState函数,在上一篇博客 link中有解释,所以只需要在Snake.c中定义一下就可以

#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)

  游戏中的按键无非就是上、下、左、右、暂停、结束、加速、减速。上下左右走的时候注意不可以向反方向行走,比如蛇正在向下走,此时只可以让它继续向下、左右走,而不可以让他向上走。
  所以根据这个规律来判断按键情况

//判断按键情况
		//上
		if (KEY_PRESS(VK_UP) == 1 && sk->dir != down)
		{
			sk->dir = up;
		}
		//下
		else if (KEY_PRESS(VK_DOWN) == 1 && sk->dir != up)
		{
			sk->dir = down;
		}
		//左
		else if (KEY_PRESS(VK_LEFT) == 1 && sk->dir != right)
		{
			sk->dir = left;
		}
		//右
		else if (KEY_PRESS(VK_RIGHT) == 1 && sk->dir != left)
		{
			sk->dir = right;
		}
		//ESC键  正常退出游戏
		else if (KEY_PRESS(VK_ESCAPE) == 1)
		{
			sk->status = END_NORMAL;
		}
		//空格   暂停游戏
		else if (KEY_PRESS(VK_SPACE) == 1)
		{
			Pause();
		}

  除了上面代码中的按键还有加减速按键(所有按键不是唯一,均可以自己喜好调整按键),休息时间越短,速度越快,时间越长,速度越慢
  这里的加减速我们给他一个小规则,就是不可以一直加速或减速,加速一次,一个食物的分数会有所增加,相反减速会减少,但是我们需要给加减速一个限制,不可以让分数过大,也不可以让分数减为负数。
  调整蛇的速度快慢,只需要调整蛇每走一步的休眠时间就可以了,休眠的初始时间为200毫秒,所以加速时,如果休眠时间小于等于了80毫秒,就不可以在加速了(最快速度为80毫秒),每次加速时间减30毫秒,食物分数加2分;
减速的时候,我们可以用食物分数来判断更方便一些,一个食物分数不能小于等于2分,每次减速时间加30毫秒,食物分数减2分。

代码实现:

//可根据个人喜好调整按键
//Ctrl  加速
	else if (KEY_PRESS(0x11) == 1)
	{
		//规定只能加速四次,加速一次加两分
		if (sk->sleep_time > 80)
		{
			sk->sleep_time -= 30;
			sk->food_weight += 2;
		}
	}
	//Alt 减速
	else if (KEY_PRESS(0x12) == 1)
	{
		//只能减速四次,减速一次减二分
		if (sk->food_weight > 2)
		{
			sk->sleep_time += 30;
			sk->food_weight -= 2;
		}
	}

3、蛇每走一步的状态

蛇的行走状态只有上下左右走,以及判断下一个坐标是不是食物。
首先,创建一个新节点作为蛇下一步的节点。

PSnakeNode nextnode = (PSnakeNode)malloc(sizeof(SnakeNode));
if (nextnode == NULL)
{
	perror("SnakeMove()::malloc");
	return;
}

(1)、上下左右走

对于蛇的行走,只需要改变相应的X轴和Y轴坐标值就可以了,这里我们使用switch函数来实现。

//先让蛇上下左右走
switch(sk->dir )
{
case up:
	nextnode->x = sk->pSnake->x;
	nextnode->y = sk->pSnake->y - 1;
	break;
case down:
	nextnode->x = sk->pSnake->x;
	nextnode->y = sk->pSnake->y + 1;
	break;
case right:
	nextnode->x = sk->pSnake->x+2;//两个X坐标为一个‘□’,所以改变X值要加减2
	nextnode->y = sk->pSnake->y;
	break;
case left:
	nextnode->x = sk->pSnake->x-2;//两个X坐标为一个‘□’,所以改变X值要加减2
	nextnode->y = sk->pSnake->y ;
	break;
}

(2)、判断下一个坐标是不是食物

判断下一个坐标是不是食物,需要行我们前面新创建的节点坐标与实物坐标比较,重合为是食物,不重合就不是食物,创建函数FindIsFood()来判断

//判断下一个坐标是不是食物
int FindIsFood(PSnakeNode pn, PSnake sk)
{
	if (sk->pFood->x == pn->x && sk->pFood->y == pn->y)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

返回1是食物, 返回不是1不是食物。

//判断下一个坐标是不是食物
	if (FindIsFood(nextnode, sk))
	{
		//下一个节点是食物
		EatFood(nextnode, sk);
	}
	else
	{
		//下一个节点不是食物
		NoFood(nextnode, sk);
	}

(3)、下一个节点是食物

如果下一个节点是食物,那么用头插法将食物与蛇身连接起来,还要注意一定要释放掉原来新创建的节点。然后打印新的蛇身,创建新的食物

//下一个节点是食物
void EatFood(PSnakeNode nextnode, PSnake sk)
{
	//头插法
	sk->pFood->next = sk->pSnake;
	sk->pSnake = sk->pFood;

	//新节点和食物重合,蛇与实物连接起来,要释放原来的新节点
	free(nextnode);
	nextnode = NULL;

	//打印蛇
	PSnakeNode cur = sk->pSnake;
	while (cur)//遍历蛇身
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}

	//加分
	sk->score += sk->food_weight;

	//创建食物
	CreateFood(sk);//直接调用前面创建食物的函数
}

(4)、下一个节点不是食物

如果下一个节点不是食物,就将新创建的节点和蛇身用头插法连接起来,那么我们要注意蛇每向前走一步都要在蛇尾消掉一个节点,并且在蛇尾打印一个空格。

//下一个节点不是食物
void NoFood(PSnakeNode nextnode, PSnake sk)
{
	//头插法
	nextnode->next = sk->pSnake;
	sk->pSnake = nextnode;

	PSnakeNode cur = sk->pSnake;
	while (cur->next->next != NULL)//找到最后一个节点
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}

	//把最后一个结点打印成空格
	SetPos(cur->next->x, cur->next->y);
	printf("  ");

	//释放最后一个结点
	free(cur->next);

	//把倒数第二个节点的地址置为NULL
	cur->next = NULL;
}

这里如果没有将最后一个节点打印成空格,那么打印中就会将最后一个节点留在原地,如图所示:
在这里插入图片描述
此时的贪吃蛇已经可以正常运行起来,接下来就只剩下判断蛇有没有撞墙或者撞到自己,由两个函数来实现

//判断蛇有没有撞墙
KillByWall(sk);

//判断蛇是否撞到自己
KillBySelf(sk);

(5)、判断蛇有没有撞墙

比较蛇头和墙的坐标是否重合

void KillByWall(PSnake sk)
{
	if (sk->pSnake->x == 0 || sk->pSnake->x == 56
		|| sk->pSnake->y == 0 || sk->pSnake->y == 26)
	{
		sk->status = KILL_BY_WALL;
	}
}

(6)、判断蛇是否撞到自己

判断蛇头是否和蛇身所有节点坐标重合

//判断蛇是否撞到自己
void KillBySelf(PSnake sk)
{
	//遍历蛇身,是否与蛇头坐标重合,重合就是撞到了自己
	PSnakeNode cur = sk->pSnake->next;
	while (cur)
	{
		if (cur->x == sk->pSnake->x && cur->y == sk->pSnake->y)
		{
			sk->status = KILL_BY_SELF;
			break;
		}
		cur = cur->next;
	}
}

这里我们的贪吃蛇运行就已经完成了,但是要注意蛇正常走路时也要有休眠时间, 要在SnakeMove()函数下面加上睡眠时间的初始值

//蛇每走一步的状态
SnakeMove(sk);
Sleep(sk->sleep_time);

四、结束游戏——善后工作

游戏的结束原因有:自己退出游戏、撞墙、撞到自己;在结束游戏时打印结束原因

void GameEnd(PSnake sk)
{
	SetPos(20, 12);
	switch (sk->status)//游戏状态
	{
	case KILL_BY_WALL:
		printf("您撞到了墙!游戏结束\n");
		break;
	case KILL_BY_SELF:
		printf("您撞上了自己!游戏结束\n");
		break;
	case END_NORMAL:
		printf("您以结束游戏\n");
		break;
	}

}

对于这里的游戏善后,我们还可以增加一些其他东西来做修饰,例如:一局游戏结束后不需要退出直接进行下一场游戏······大家可以自由的发挥。

完整代码展示

  • Snake.h文件

在这里插入图片描述




五、结语


  十分感谢您观看我的原创文章。
  本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
  如需引用,注明地址。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值