贪吃蛇小游戏(纯c实现)

331 阅读3分钟

「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

对于初学c语言的同学来说,贪吃蛇绝对是假期练手的好项目之一。用代码写出贪吃蛇并不难,其基本思路可以分为初始化蛇、食物;打印蛇、食物;让蛇吃食物;最后判断蛇死亡。

程序主要用到结构体、esayx图像库和一些基本的c语言语法。

在正式写主要程序前,我们先完成一些准备工作——设置结构体。

贪吃蛇其本身可以看成基于数组的填充方块, (用fillrectangle()函数实现填充)。其结构体主要有带有坐标的数组、方向、总长属性构成。 食物具象话来说也只是一节填充方块,其结构体有标记、分数以及坐标属性构成。

typedef struct coord {
	int x;//基本坐标
	int y;
}MYCOORD;

struct snake {
	MYCOORD xy[100];//蛇身
	int sum;//总长
	int direction;//方向
};

enum direction{right,up,left,down};

struct food {
	MYCOORD xy;//坐标
	int sign;//标志
	int score;//分数

}food;

现在开始正式写

初始化

贪吃蛇:在游戏一开始具有一个初始位置、初始长度以及初始的方向。 坐标上默认为原点,长度为3,方向为右。


void init_snake()
{
	//坐标,方向,长度
	
	snake.xy[2].x = 0;
	snake.xy[2].y = 0;
	snake.xy[1].x = 10;
	snake.xy[1].y = 0;
	snake.xy[0].x = 20;
	snake.xy[0].y = 0;

	snake.direction = right;
	snake.sum = 3;
}

食物:初始化它的坐标、标记、分数

void init_food()
{
	
	food.sign = 1;
	food.xy.x = rand() % 80 * 10;
	food.xy.y = rand() % 60 * 10;
	for (int i = 0; i < snake.sum ; i++)
	{
		//当食物与身体任意一节重合就重进行初始化
		if (food.xy.x == snake.xy[i].x && food.xy.y == snake.xy[i].y)
		{
			food.xy.x = rand() % 80 * 10;
			food.xy.y = rand() % 60 * 10;
		}
	}
}

这里采用随机种子来初始化种子的位置,使其在构造的界面内出现且不与蛇身重合。

开始绘制

:主要借助fillrectangle()函数实现。 画贪吃蛇:

void draw_snake()//画蛇
{
	srand((unsigned int)time(NULL));
	for (int i = 0; i < snake.sum; i++)
	{
		setlinecolor(BLACK);//设置边框颜色
		setfillcolor(RGB(rand() % 255,rand() % 255, rand() % 255));//设置填充方块颜色,采用随机

		fillrectangle(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10);//后面两个参数只要加上一节蛇身的大小即可

	}
}

画食物:与画贪吃蛇有异曲同工之妙

void draw_food()
{
	
	
		setlinecolor(BLACK);//设置边框颜色
		setfillcolor(RGB(rand() % 250, rand() % 250, rand() % 250));//设置填充方块颜色,采用随机

		fillrectangle(food.xy.x,food.xy.y,food.xy.x+10,food.xy.y+10);

	
}

让贪吃蛇动起来。

动起来的本质是:坐标之间的移动,蛇头带着蛇身去移动,前一节带着后一节。 翻译成代码就是:前一节的坐标给后一节,然后调用画贪吃蛇函数,再清屏(使之前的消失)即可。注意:蛇头的移动是玩家决定的——根据方向进行坐标的操作。蛇头移动跟蛇身要分开写

void move_sanck()
{
	//移动:坐标转换达成蛇身移动
	for (int i = snake.sum - 1; i > 0; i--)
	{
		snake.xy[i].x = snake.xy[i - 1].x;
		snake.xy[i].y = snake.xy[i - 1].y;
	}
	//蛇头移动
	switch (snake.direction)
	{
	case up:snake.xy[0].y -= 10; break;
	case down:snake.xy[0].y += 10; break;
	case right:snake.xy[0].x += 10; break;
	case left:snake.xy[0].x -= 10; break;

	}
}

在这里插入图片描述

这时贪吃蛇还是处于不可控状态,我们必须要让玩家可以去操作贪吃蛇,这就需要我们从键盘上读取玩家的操作指令,并更改贪吃蛇的方向。

void keyoperate()
{
	char keyread = _getch();
	switch (keyread)//判断玩家指令
	{
	case 'w':
	case'W':if (snake.direction != down)
		snake.direction = up;
		break;
	case 's':
	case 'S':if (snake.direction != up)
		snake.direction = down;
		break;
	case 'a':
	case 'A':if (snake.direction != right)
		snake.direction = left;
		break;
	case 'd':
	case 'D':if (snake.direction != left)
		snake.direction = right;
		break;
	}

}

注意:贪吃蛇是不能倒着走的,开弓没有回头箭。举例:当贪吃蛇正在往右行驶,玩家就不能直接让他往左走。

然后我们再编写代码判断贪吃蛇是否吃到食物。 先来分析:当贪吃蛇吃到后(蛇头坐标等于食物坐标),自身长度+1、食物标记变为0、得分+10

void eatfood()
{
	//当蛇头碰到食物时,标志变0,长度+1;分数+10
	if (food.xy.x == snake.xy[0].x && food.xy.y == snake.xy[0].y)
	{
		food.sign = 0;
		snake.sum++;
		food.score += 10;
	}
}

显示分数:

void showgrade()
{
	char grade[20] = "";
	sprintf_s(grade,"grade:%d",food.score);
	settextcolor(LIGHTBLUE);
	settextstyle(25,0,"楷体");
	outtextxy(650, 50, grade);


}

最后一步:判断贪吃蛇死亡

分析:贪吃蛇在碰到自身身体,或者碰到墙壁时就会死亡,游戏结束关闭音乐并退出。

void gameover()
{
	if (snake.xy[0].x < 0 || snake.xy[0].y < 0 || snake.xy[0].x>800 || snake.xy[0].y>600)
	{
		mciSendString("close 1.mp3", 0, 0, 0);
		exit(0);
	}
	for (int i = 1; i < snake.sum; i++)
	{
		if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y)
		{
			mciSendString("close 1.mp3", 0, 0, 0);
			exit(0);
		}
	}
}

最后源代码放在网盘上,需要的朋友自取

链接:pan.baidu.com/s/1aDjN6YXV… 提取码:y719