引言:
记得小时候还没有现在超级高端的智能手机,当时的诺基亚类型的老人机是我的最爱,而里面的贪吃蛇小游戏我总是能玩很久,所以今天就用C语言简单实现一下贪吃蛇这一个小游戏吧。
一、 准备工作:
1、VS2019简单配置:
我感觉只要与小游戏相关的那些函数你多多少少都要用到easyx的所以不妨给你们弄一下怎么配置,不然很多小伙伴会问为啥我的编译器运行会有一堆报错!!!
如何配置:EasyX头文件的配置。
参考这篇博文,可以说简单易懂了!!!
二、实现逻辑:
1、贪吃蛇初始化为三个节点
2、吃一个食物贪吃蛇增加一个节点也就是size:
这里运用判断蛇头坐标与食物坐标是否在食物大小的半径范围内若是则吃若不是则不吃,当然肯有一些小伙伴会问为什么不直接判断坐标重合则吃掉食物呢?嘿嘿嘿,这里坐标就是一个点,你要让两个点在一块屏幕上重合的难易程度可想而知。
3、贪吃蛇不能吃自己的身体
贪吃蛇不能吃自己的身体,这里直接使用的snake_check函数中一个判断去判断蛇头的坐标是否与除了蛇头以外的蛇尾坐标是在蛇身的半径范围内与吃食物比较类似
4、贪吃蛇不能直接从上到小掉头而是需要拐一个弯
利用条件语句实现:
三、直接上代码吧,因为我都在代码里注释的都有:
#include
#include
#include
#include
#include
#include
/*
作者:有·意思
实现内容:贪吃蛇小demo
制作时间:2022/4/8
代码不足:没有实现图形化界面,仅仅实现了贪吃蛇的基本逻辑
*/
/*
*** 作:大写的WSAD分别对应上下左右
或者小写的wsad分别对应上下左右
*/
//窗口的大小
#define WID 480 //宽度
#define HIGHT 640 //高度
#define SNAKE_NUM 500 //蛇的最大程度
#define FOOD_NUM 1
//定义一个反向的枚举常量
enum FANG
{
UP,
DOWN,
LEFT,
RIGHT,
};
//蛇的属性(结构体)
struct Snake {
int size;//蛇的大小
int fang;// 蛇的放向
int speed;//蛇的移动速度
POINT location[SNAKE_NUM];//蛇的坐标POINT就是一个定义了xy的坐标结构体可以直接使用
}snake;
//食物的结构体
struct Food {
bool eat;//食物是否被贪吃蛇吃掉
POINT location[FOOD_NUM];
}food;
void initgame()//初始化函数
{
initgraph(HIGHT, WID);//初始化窗口
srand((unsigned)time(NULL));//产生随机数
//初始化贪吃蛇的:
snake.size = 3;
snake.speed = 10;
snake.fang=RIGHT;
for (int i = 0; i < snake.size; i++)
{
snake.location[i].x = 20*i+10;//初始化贪吃蛇每个节点的坐标二十是半径加二十是两个实心圆的距离
snake.location[i].y = 20;
}
//初始化食物
for (int i = 0; i < FOOD_NUM; i++)
{
food.location[i].x = rand() % HIGHT;
food.location[i].y = rand() % WID;
}
food.eat = true;
}
//绘制函数
void gamedraw()
{
BeginBatchDraw();//开始双缓冲绘制图
setbkcolor(BLACK);//背景颜色自己想怎么设置就怎么设置
cleardevice();
//画贪吃蛇
setfillcolor(WHITE);
for (int i = 0; i < snake.size; i++)
{
solidcircle(snake.location[i].x, snake.location[i].y, 5);//一个实心圆就是一开始的贪吃蛇,这个函数是画圆函数
}
//随机画五个食物
setfillcolor(RED);
for (int i = 0; i < FOOD_NUM; i++)
{
solidcircle(food.location[i].x, food.location[i].y, 5);
}
EndBatchDraw();//双缓冲绘图防止闪屏
}
//蛇移动函数
void snakemove()
{
for (int i = snake.size - 1; i >0; i--)
{
snake.location[i] = snake.location[i - 1];//利用循环更新蛇尾的坐标与上一个节点的坐标一样
}
switch(snake.fang)//判断键值传入的方向改变的是蛇头至于蛇尾上面的for循环已经实现了更新
{
case RIGHT:
snake.location[0].x+=snake.speed;
if (snake.location[0].x > HIGHT)
{
snake.location[0].x = HIGHT-HIGHT;
}
break;//蛇在x轴上移动
case UP:
snake.location[0].y-= snake.speed; //设置蛇头蛇尾同步进行移动
if (snake.location[0].y < WID-WID)
{
snake.location[0].y = WID;
}
break;
case DOWN:
snake.location[0].y+= snake.speed;
if (snake.location[0].y > WID)
{
snake.location[0].y = WID-WID;
}
break;
case LEFT:
snake.location[0].x-= snake.speed;
if (snake.location[0].x < HIGHT-HIGHT)
{
snake.location[0].x = HIGHT;
}
break;
}
}
//与用户有关更新//按键改变方向
void keycontrol()
{
//判断有无按键输入
if (_kbhit() == 1)//kbhit函数是检测是否有按键输入若有则返回真
{
switch (_getch())
{
case 'W':
case 'w':if (snake.fang != DOWN) { snake.fang = UP; } break;//设置条件防止舌头上下翻转或者左右翻转
case 's':
case 'S':if (snake.fang != UP) { snake.fang = DOWN; } break;
case 'A':
case 'a':if (snake.fang != RIGHT) { snake.fang = LEFT; }break;
case 'D':
case 'd':if (snake.fang != LEFT) { snake.fang = RIGHT; } break;
}
}
}
//判断是否被吃到函数
void is_eat()
{
if (food.eat &&((snake.location[0].x >= food.location[0].x-5)) && (snake.location[0].x <= food.location[0].x + 5)&&
(snake.location[0].y <= food.location[0].y + 5)&& (snake.location[0].y >= food.location[0].y - 5))
//判断条件当蛇头的坐标与食物的坐标距离小于食物或者蛇头的半径的距离时就代表食物被吃了
{
food.eat = false;
snake.size++;
}
//食物重置
if (!food.eat)
{
food.eat = true;
for (int i = 0; i < FOOD_NUM; i++)
{
food.location[i].x = rand() % HIGHT;
food.location[i].y = rand() % WID;
}
}
}
//检查贪吃蛇是否失败
void snake_check()
{
for (int i = 1; i < snake.size; i++)
{
if ((snake.location[0].x == snake.location[i].x) && (snake.location[0].y == snake.location[i].y))
{
printf("the snake is knock itsself,so lose!");
exit(0);
}
}
}
int main()
{
initgame();
while (1)
{
gamedraw();
snakemove();
keycontrol();
is_eat();
snake_check();
Sleep(90);
}
return 0;
}
四、结语:
在配置好easyx之后,代码可以直接复制粘贴运行。 但是还是希望读者,理解大致思路参照代码格式编写属于自己的代码。 这样进步一定是显而易见的!!!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)