「这是我参与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