贪吃蛇
贪吃蛇对于大家来说肯定不陌生,那么今天我们将用C语言来实现贪吃蛇的功能,自己动手做一款属于自己的小游戏。
首先先看几个我做的贪吃蛇游戏截图:
在编写程序之前,我们先来简单分析一下,我们最终要实现成什么样子呢,要有哪些功能,要将这些功能分为哪些方面,分别要进行几步实现,对于自己设计就有了自己的玩法,界面和规则,所以一定要有独特看法,一定要考虑到游戏各个方面的问题。
首先我们要确定大体框架,因为我最近在学习数据结构,因此我会采用链表的形式来实现基本操作,大家可以有自己想法。
上面是我们做这个小项目的一些简单说明,接下来正式进入贪吃蛇的设计。
先来说明我的设计思路,我将整个项目分为以下几个方面 :
- 屏幕坐标的获取与设置
- 地图的设计
- 节点的设计
- Snake蛇的设计
- 食物的设计
- 蛇的移动方式
- 控制蛇的方式
- 游戏输赢的判断方式
- 游戏界面的设计
- 屏幕坐标的获取与设置
void SetPos(int x,int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得句柄
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);//设置光标位置
}
SetPos()
函数有两个参数 x,y
,作为屏幕的横坐标和纵坐标输入。函数里面,handle
为一个句柄,GetStdHandle(STD_OUTPUT_HANDLE)
获得标准输出句柄给handle
。
COORD pos
定义一个COORD类型的数据pos,用来保存坐标值。
关于COORD,有如下介绍
The COORD structure defines the coordinates of a character cell in a console screen buffer. The origin of the coordinate system (0,0) is at the top, left cell of the buffer.
COORD原型:
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD;
SetConsoleCursorPosition(handle, pos)
该函数的作用是移动屏幕光标到指定位置
函数原型:
BOOL SetConsoleCursorPosition(
HANDLE hConsoleOutput, // handle to screen buffer
COORD dwCursorPosition // new cursor coordinates);
以上是关于坐标的设置,这也是我们这个小项目中最重要的一步,因为不管是整个画面的打印,还是蛇的控制与移动都离不开坐标,是我们完成项目的基础。
- 地图的设计
void CreateMap()
{
int i;
for ( i = 0; i <= 56; i+=2)
{
SetPos(i, 0);
printf(WALL);
SetPos(i, 26);
printf(WALL);
}
for (i = 1; i <= 25; i++)
{
SetPos(0, i);
printf(WALL);
SetPos(56, i);
printf(WALL);
}
}
打印一个27*25大小的地图,WALL是一个宏定义表示“■”。
地图打印的样子是:
- 节点的设计
//节点
typedef struct Node
{
struct Node *next;//下一个节点
int x;//该节点x坐标
int y;//该节点y坐标
}SnakeNode,*pSnakeNode;
使用结构体作为节点,里面封装一个横坐标x,纵坐标y,和一个指向下一节点的指针。
- Snake蛇的设计
//蛇结构体
typedef struct Snake
{
pSnakeNode _pSnake;//指向蛇
pSnakeNode _pFood;//食物
enum status _status;//蛇的状态
enum Dir _Dir;//蛇的行走方向
int SleepTime;//蛇的停留时长
}Snake ,*pSnake;
用一个结构体表示蛇的属性,在结构体中包含:指针_pSnake
用来指向蛇的身体,指针_pFood
用来指向食物,枚举类型的 _status
用来表示当前蛇的状态,_Dir
用来表示当前蛇的行走方向,SleepTime
用来表示蛇的停留时间,也就是蛇行走的快慢
//3.初始化蛇
void InitSnake(pSnake pS)
{
pSnakeNode Cur = malloc(sizeof(SnakeNode));
Cur->x = INIT_X;
Cur->y = INIT_Y;
Cur->next = NULL;
//采用头插
for (size_t i = 1; i <= 4; i++)
{
//头插进一个新的节点
pS->_pSnake = malloc(sizeof(SnakeNode));
pS->_pSnake->next = Cur;//使新节点连接上之前的节点
pS->_pSnake->x = INIT_X + i * 2;//新节点赋值
pS->_pSnake->y = INIT_Y;
Cur = pS->_pSnake; //使Cur指向第一个节点
}
pS->_Dir = RIGHT;
pS->_status = OK;
}
首先有一个节点指针Cur,他的初始位置(INIT_X,INIT_Y), 然后采用头插的方法再次插入3个节点,以这4个节点作为蛇的初始身体。这里选择头插的方式,时间复杂度为O(1),较与尾插的方式,更加方便快捷。
最后再将这只蛇的状态和方向设定好。
- 食物的设计
void CreadeFood(pSnake pS)
{
pSnakeNode pFood = malloc(sizeof(SnakeNode));
pSnakeNode Cur = NULL;
assert(pS);
int flag = 1;//标记
while (flag)
{
GetRandFood(pFood);//随机生成食物坐标