C语言游戏之贪吃蛇

1. 游戏背景

贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。 在编程语⾔的教学中,我们以贪吃蛇为例,从设计到代码实现来提升学⽣的编程能⼒和逻辑能⼒。

2. 课程⽬标

使⽤C语⾔在Windows环境的控制台中模拟实现经典⼩游戏贪吃蛇 实现基本的功能: • 贪吃蛇地图绘制 • 蛇吃⻝物的功能 (上、下、左、右⽅向键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞⾃⾝死亡 • 计算得分 • 蛇⾝加速、减速 • 暂停游戏

3. 技术要点

C语⾔函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。

4. Win32 API介绍

本次实现贪吃蛇会使⽤到的⼀些Win32 API知识,但我在这里就不多叙述了,感兴趣的可以自学一下

5. 贪吃蛇游戏设计与分析

首先我们需要一个地图页面

然后我们还需要打印规则

然后进入游戏后还需要地图规则一起出现,一左一右

同时还需要维护我们的游戏

并且实现一些功能按键

5.1开始实现准备工作

还是先创建三个文件,两个源文件一个头文件

在头文件中要包含以下头文件

#include<locale.h>
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>
#include<stdbool.h>

接下来我们设置光标位置

void SetPos(int x, int y)
{
	//获得设备句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//根据句柄设置光标位置
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);


}

然后打印我们的欢迎界面

需要有规则以及功能以及欢迎信息

void WelcomeToGame()
{
	//定位光标坐标,打印欢迎信息
	SetPos(48, 15);
	printf("欢迎来到贪吃蛇小游戏\n");
	SetPos(48, 20);

	system("pause");
	system("cls");
	//打印功能介绍信息
	SetPos(40, 10);
	printf("用↑ ↓ ← →来控制蛇的移动方向,F3是加速,F4是减速\n");
	SetPos(40, 11);
	printf("加速能获得更高的分数");
	SetPos(48, 20);
	system("pause");
	system("cls");
}

之后我们也需要测试

所以源文件中


int main()
{
	//修改适配本地中文环境
	setlocale(LC_ALL, "");

	test();//贪吃蛇游戏的测试
	SetPos(0, 28);

	return 0;
}

 头文件中

//定位光标位置
void SetPos(int x, int y);

 5.2地图的实现

实现地图的话我们需要特殊字符,这样的话打印就需要wprintf函数并且括号里面的格式也需要改变一下

我们先再头文件中去定义我们的墙体符号

#define WALL L'□'

然后再去s源文件中去补充

地图的话我们需要设置一个正方形或者长方形地图

并且因为特殊字符需要两个正常字符的格

所以我们的x轴要更大一下,并且最好是偶数

因为需要一直打印,所以我们利用for循环去打印四周的墙体

void CreateMap()
{
	int i = 0;
	//上
	SetPos(0, 0);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 28);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 28; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 28; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

 这样就打印好了

5.3蛇的创建

因为我们蛇是一节一节的

所以我们利用链表去创建节点

然后将蛇的节点一个个的连接起来

同时我们还需要初始化一些蛇的状态以及游戏中相应的东西

比如食物的分数,累计分数,方向等等

头文件

//蛇的默认起始坐标
#define POS_X 24
#define POS_Y 5
//游戏的状态
enum GAME_STATUS
{
	OK = 1,
	ESC,
	KILL_BY_WALL,
	KILL_BY_SELF
};

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 pFood;//指向食物的指针
	int Score;//当前累计分数
	int FoodWeight;//一个食物的分数
	int SleeoTime;//舍得休眠时间,时间短则速度快
	enum GAME_STATUS status;//游戏当前的状态
	enum DIRECTION dir;//蛇当前走的方向

}Snake, * pSnake;

源文件

void InitSnake(pSnake ps)
{
	  //创建五个蛇身节点
	int i = 0;
	pSnakeNode cur = NULL;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake(:malloc()");
			return;
		}
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		cur->next = NULL;

		//头插
		if (ps->pSnake == NULL)
		{
			ps->pSnake = cur;
		}
		else
		{
			cur->next = ps->pSnake;
			ps->pSnake = cur;

		}
	}

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

	//贪吃蛇的其他信息初始化
	ps->dir = RIGHT;
	ps->FoodWeight = 10;
	ps->pFood = NULL;
	ps->Score = 0;
	ps->SleeoTime = 200;
	ps->status = OK;

}

 食物的创建

创建食物需要让食物随机出现

并且还要确定是否和蛇身重叠

并且让食物开辟属于自己的空间

void CreateFood(pSnake ps)
{
	int x = 0;
	int y = 0;
	again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);
	//坐标要和蛇的节点坐标错开,比较
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}

	//创建食物
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreateFood():malloc()");
		return;
	}
	pFood->x = x;
	pFood->y = y;
	ps->pFood = pFood;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);

}

 这样的话我们的前期准备工作算是彻底实现了

所以将这一个函数分装起来

然后整理到一块

并定义为游戏的开始

void GameStar(pSnake ps)
{
	//设置控制台的信息,窗口大小,窗口名
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");


	//隐藏光标
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo);

	//打印欢迎信息
	WelcomeToGame();
	//绘制地图
	CreateMap();
	//初始化蛇
	InitSnake(ps);
	//创建食物
	CreateFood(ps);

}

 5.4打印帮助信息

也就是说我们需要将所有的帮助信息在游戏开始时也打印

void PrintHelpInfo()
{
	SetPos(65, 15);
	printf("1.不能穿墙,不能咬到自己");
	SetPos(65, 16);
	printf("用 ↑ ↓ ← →来控制蛇的移动");
	SetPos(65, 17);
	printf("F3加速,F4减速");



}

void pause()
{
	while (1)
	{
		Sleep(100);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	
	}
}

 5.5判断是否是吃的食物

这里我们需要检测是否是吃的食物

如果吃了那么需要创建新的事物并且释放旧食物的空间

如果没有,那么移动,头插接下来释放尾结点

并将尾结点变成空白格


void EatFood(pSnake ps, pSnakeNode pn)
{
	pn->next = ps->pSnake;
	ps->pSnake = pn;

	//打印蛇身
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf("L%lc", BODY);
		cur = cur->next;
	}
	ps->Score += ps->FoodWeight;
	//释放旧食物,新建新食物
	free(ps->pFood);
	CreateFood(ps);
}

void NotEatFood(pSnake ps, pSnakeNode pn)
{
	//头插
	pn->next = ps->pSnake;
	ps->pSnake = pn;

	//释放尾节点
	pSnakeNode cur = ps->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);
	cur->next = NULL;
	
}

 5.6蛇的移动并检测撞墙

检测撞墙那么就需要当蛇身走到相应的墙体位置时

那么久结束游戏

检测撞到自己

则是创建一个空指针

然后让它指向蛇的next

然后检测如果新节点的x和y都是和蛇的重叠

那么就是撞到自己

然后蛇的移动则是创建一个节点

然后设置为空

并且判断是往哪个方向移动

利用switch语句

上下左右判断一下

//检测撞墙
void 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;
	}
}

//撞到自己
void KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->pSnake->next;
	while (cur)
	{
		if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
		{
			ps->status = KILL_BY_SELF;
			return;
		}
		cur = cur->next;
	}
}

void SnakeMove(pSnake ps)
{
	pSnakeNode pn = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pn == NULL)
	{
		perror("snakemove():mallco()");
		return;
	}
	pn->next = NULL;
	switch (ps->dir)
	{
	case UP:
		pn->x = ps->pSnake->x;
		pn->y = ps->pSnake->y - 1;

		break;
	case DOWN:
		pn->x = ps->pSnake->x;
		pn->y = ps->pSnake->y + 1;

		break;
	case LEFT:
		pn->x = ps->pSnake->x - 2;
		pn->y = ps->pSnake->y;

		break;
	case RIGHT:
		pn->x = ps->pSnake->x + 2;
		pn->y = ps->pSnake->y;
		break;

	}
	//下一个坐标处是否是食物?
	if (NextIsFood(ps, pn))
	{
		//是食物就吃掉
		EatFood(ps, pn);
	}
	else
	{
		//不是就正常走
		NotEatFood(ps, pn);
	}
	//检测撞到自己或者墙
	KillByWall(ps);
	KillBySelf(ps);
}

5.7 游戏跑起来

将之前的函数整合一下

就可以让游戏跑起来了

void GameRun(pSnake ps)
{
	//打印帮助信息
	PrintHelpInfo();

	do
	{
		//当前的分数情况
		SetPos(65, 10);
		printf("当前的总分:%5d\n", ps->Score);
		SetPos(65, 11);
		printf("食物的分值:%02d\n", ps->FoodWeight);
		//检测按键
		//上下左右,ESC ,空格 ,F3, F4
		if (KEY_PRESS(VK_UP)&&ps->dir!=DOWN)
		{
			ps->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
		{
			ps->dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
		{
			ps->dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
		{
			ps->dir = RIGHT;
		}
		else if (KEY_PRESS((VK_ESCAPE)))
		{
			ps->status = ESC;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			//游戏暂停
			pause();//实现暂停和继续
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (ps->SleeoTime <= 80)
			{
				ps->SleeoTime -= 30;
				ps->FoodWeight += 2;
		    }

		}
		else if (KEY_PRESS(VK_F4))
		{
			if (ps->FoodWeight >= 2)
			{
				ps->SleeoTime += 30;
				ps->FoodWeight -= 2;
			}
		}

		//睡眠
		Sleep(ps->SleeoTime);
		//走一步
		SnakeMove(ps);//移动函数
	} while (ps->status==OK);
}

5.8游戏的维护结尾 

当游戏结束后,我们需要根据死亡的情况告知玩家如何死亡的

并在结束后我们需要释放空间资源

释放蛇和食物的空间

void GameEnd(pSnake ps)
{
	SetPos(30, 12);
	switch (ps->status)
	{
	case ESC:
		printf("正常退出\n");
		break;
	case KILL_BY_WALL:
		printf("很遗憾撞墙,游戏结束");
		break;
	case KILL_BY_SELF:
		printf("很遗憾,撞到自己,游戏结束");
		break;
	}
	//释放资源
	pSnakeNode cur = ps->pSnake;
	pSnakeNode del = NULL;
	while (cur)
	{
		del = cur;
		cur = cur->next;
		free(del);

	}
	free(ps->pFood);
	ps->pFood = NULL;
	ps = NULL;
}

6.游戏的代码合集 

test源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"

void test()
{
	//创建贪吃蛇
	int ch = 0;
	do
	{
		Snake snake = { 0 };
		GameStar(&snake);//游戏开始前的初始化
		GameRun(&snake);//游戏过程
		GameEnd(&snake);//善后工作
		SetPos(20, 15);
		printf("再来一局吗?(Y/N):");
		ch = getchar();
		getchar();//清理\n
	} while (ch=='Y'||ch=='y');
}


int main()
{
	//修改适配本地中文环境
	setlocale(LC_ALL, "");

	test();//贪吃蛇游戏的测试
	SetPos(0, 28);

	return 0;
}

snake源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"

void SetPos(int x, int y)
{
	//获得设备句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//根据句柄设置光标位置
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);


}

void WelcomeToGame()
{
	//定位光标坐标,打印欢迎信息
	SetPos(48, 15);
	printf("欢迎来到贪吃蛇小游戏\n");
	SetPos(48, 20);

	system("pause");
	system("cls");
	//打印功能介绍信息
	SetPos(40, 10);
	printf("用↑ ↓ ← →来控制蛇的移动方向,F3是加速,F4是减速\n");
	SetPos(40, 11);
	printf("加速能获得更高的分数");
	SetPos(48, 20);
	system("pause");
	system("cls");
}
void CreateMap()
{
	int i = 0;
	//上
	SetPos(0, 0);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 28);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 28; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 28; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}



void InitSnake(pSnake ps)
{
	  //创建五个蛇身节点
	int i = 0;
	pSnakeNode cur = NULL;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake(:malloc()");
			return;
		}
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		cur->next = NULL;

		//头插
		if (ps->pSnake == NULL)
		{
			ps->pSnake = cur;
		}
		else
		{
			cur->next = ps->pSnake;
			ps->pSnake = cur;

		}
	}

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

	//贪吃蛇的其他信息初始化
	ps->dir = RIGHT;
	ps->FoodWeight = 10;
	ps->pFood = NULL;
	ps->Score = 0;
	ps->SleeoTime = 200;
	ps->status = OK;

}

void CreateFood(pSnake ps)
{
	int x = 0;
	int y = 0;
	again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 24 + 1;
	} while (x % 2 != 0);
	//坐标要和蛇的节点坐标错开,比较
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		if (x == cur->x && y == cur->y)
		{
			goto again;
		}
		cur = cur->next;
	}

	//创建食物
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreateFood():malloc()");
		return;
	}
	pFood->x = x;
	pFood->y = y;
	ps->pFood = pFood;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);

}

void GameStar(pSnake ps)
{
	//设置控制台的信息,窗口大小,窗口名
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");


	//隐藏光标
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo);

	//打印欢迎信息
	WelcomeToGame();
	//绘制地图
	CreateMap();
	//初始化蛇
	InitSnake(ps);
	//创建食物
	CreateFood(ps);

}

void PrintHelpInfo()
{
	SetPos(65, 15);
	printf("1.不能穿墙,不能咬到自己");
	SetPos(65, 16);
	printf("用 ↑ ↓ ← →来控制蛇的移动");
	SetPos(65, 17);
	printf("F3加速,F4减速");



}

void pause()
{
	while (1)
	{
		Sleep(100);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	
	}
}

int NextIsFood(pSnake ps, pSnakeNode pn)
{
	if (ps->pFood->x == pn->x && ps->pFood->y == pn->y)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}



void EatFood(pSnake ps, pSnakeNode pn)
{
	pn->next = ps->pSnake;
	ps->pSnake = pn;

	//打印蛇身
	pSnakeNode cur = ps->pSnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf("L%lc", BODY);
		cur = cur->next;
	}
	ps->Score += ps->FoodWeight;
	//释放旧食物,新建新食物
	free(ps->pFood);
	CreateFood(ps);
}

void NotEatFood(pSnake ps, pSnakeNode pn)
{
	//头插
	pn->next = ps->pSnake;
	ps->pSnake = pn;

	//释放尾节点
	pSnakeNode cur = ps->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);
	cur->next = NULL;
	
}
//检测撞墙
void 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;
	}
}

//撞到自己
void KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->pSnake->next;
	while (cur)
	{
		if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
		{
			ps->status = KILL_BY_SELF;
			return;
		}
		cur = cur->next;
	}
}

void SnakeMove(pSnake ps)
{
	pSnakeNode pn = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pn == NULL)
	{
		perror("snakemove():mallco()");
		return;
	}
	pn->next = NULL;
	switch (ps->dir)
	{
	case UP:
		pn->x = ps->pSnake->x;
		pn->y = ps->pSnake->y - 1;

		break;
	case DOWN:
		pn->x = ps->pSnake->x;
		pn->y = ps->pSnake->y + 1;

		break;
	case LEFT:
		pn->x = ps->pSnake->x - 2;
		pn->y = ps->pSnake->y;

		break;
	case RIGHT:
		pn->x = ps->pSnake->x + 2;
		pn->y = ps->pSnake->y;
		break;

	}
	//下一个坐标处是否是食物?
	if (NextIsFood(ps, pn))
	{
		//是食物就吃掉
		EatFood(ps, pn);
	}
	else
	{
		//不是就正常走
		NotEatFood(ps, pn);
	}
	//检测撞到自己或者墙
	KillByWall(ps);
	KillBySelf(ps);
}



void GameRun(pSnake ps)
{
	//打印帮助信息
	PrintHelpInfo();

	do
	{
		//当前的分数情况
		SetPos(65, 10);
		printf("当前的总分:%5d\n", ps->Score);
		SetPos(65, 11);
		printf("食物的分值:%02d\n", ps->FoodWeight);
		//检测按键
		//上下左右,ESC ,空格 ,F3, F4
		if (KEY_PRESS(VK_UP)&&ps->dir!=DOWN)
		{
			ps->dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
		{
			ps->dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
		{
			ps->dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
		{
			ps->dir = RIGHT;
		}
		else if (KEY_PRESS((VK_ESCAPE)))
		{
			ps->status = ESC;
			break;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			//游戏暂停
			pause();//实现暂停和继续
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (ps->SleeoTime <= 80)
			{
				ps->SleeoTime -= 30;
				ps->FoodWeight += 2;
		    }

		}
		else if (KEY_PRESS(VK_F4))
		{
			if (ps->FoodWeight >= 2)
			{
				ps->SleeoTime += 30;
				ps->FoodWeight -= 2;
			}
		}

		//睡眠
		Sleep(ps->SleeoTime);
		//走一步
		SnakeMove(ps);//移动函数
	} while (ps->status==OK);
}

void GameEnd(pSnake ps)
{
	SetPos(30, 12);
	switch (ps->status)
	{
	case ESC:
		printf("正常退出\n");
		break;
	case KILL_BY_WALL:
		printf("很遗憾撞墙,游戏结束");
		break;
	case KILL_BY_SELF:
		printf("很遗憾,撞到自己,游戏结束");
		break;
	}
	//释放资源
	pSnakeNode cur = ps->pSnake;
	pSnakeNode del = NULL;
	while (cur)
	{
		del = cur;
		cur = cur->next;
		free(del);

	}
	free(ps->pFood);
	ps->pFood = NULL;
	ps = NULL;
}

snake头文件

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

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


//蛇的默认起始坐标
#define POS_X 24
#define POS_Y 5

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

//定位光标位置
void SetPos(int x, int y);

//游戏的状态
enum GAME_STATUS
{
	OK = 1,
	ESC,
	KILL_BY_WALL,
	KILL_BY_SELF
};

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 pFood;//指向食物的指针
	int Score;//当前累计分数
	int FoodWeight;//一个食物的分数
	int SleeoTime;//舍得休眠时间,时间短则速度快
	enum GAME_STATUS status;//游戏当前的状态
	enum DIRECTION dir;//蛇当前走的方向

}Snake, * pSnake;

//游戏开始前的准备
void GameStar(pSnake ps);

//打印欢迎界面
void WelcomeToGame();


//绘制地图
void CreateMap();

//初始化贪吃蛇
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);

//游戏运行的整个逻辑
void GameRun(pSnake ps);

//打印帮助信息
void PrintHelpInfo();

//判断蛇头的下一步要走的位置节点处是否是食物
int NextIsFood(pSnake ps, pSnakeNode pn);


//下一步要走的位置处是食物
void EatFood(pSnake ps, pSnakeNode pn);

//不是食物,则需要出现食物
void NotEatFood(pSnake ps, pSnakeNode pn);

//检测撞墙
void KillByWall(pSnake ps);


//检测撞自己
void KillBySelf(pSnake ps);

//游戏结束的善后工作
void GameEnd(pSnake ps);
  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值