c语言实现greedy snake(贪吃蛇)

##第一个小项目  大一学生寒假项目

c语言实现greedy snake(贪吃蛇)_第1张图片最终实现效果如图

一.以C语言实现个人小项目

在我们快速学完了一个高级编程语言,就应该写一个小项目来加以巩固自己的学习成果。

所以今天,我们来尝试写一写greedy snake,对于大学生来说也是可以加强能力的存在。事不宜迟,我们开始吧。(Tips:我会加入一些外部链接,这些于编写遇到的问题有关,可以帮助你更好的解决)

外部文件的引入以及一些定义

#include 
#include  //与绘图文件有关
#include     //两个都需要
#include 
#define SNAKE_NUM 500 //宏定义 规定好蛇的最大节数,以防溢出
enum DIR //枚举初始化方向
{
    UP,
    DOWN,
    LEFT,
    RIGHT,
};

解释:

我们在第四行引入的头文件是为了产生一个生成随机数的种子(所以我们引入了该头文件)

5函数名称: rand

函数原型: int rand(void);

函数功能: 产生0到32767间的随机整数(0到0x7fff之间)

函数返回: 随机整数

对于第二,第三行的头文件引入。

我在这里放好了它的下载官网,官网有下载说明,不复杂的

easyx文档 点击此处

二.蛇和食物的结构体定义

struct Snake
{
    int size; //蛇的长度
    int dir; //蛇的方向
    int speed; //蛇的速度
    POINT coor[SNAKE_NUM]; //坐标
}snake;

struct food
{
    int x;
    int y;
    int r; //食物大小
    bool flag; //为后面判断食物是否被吃做准备
    DWORO color;  //规定食物的颜色
}food;

在这里,我们注意一下 POINT coor[] 是我们引入了相应的头文件,以有表示二维坐标的

函数。 后续创建实体的写法是---> snake[i].x = 坐标点 其中i是它的大小。

并且,这里的坐标轴与数学中的有些不同,y轴的正方向是朝下的,所以我们想让蛇向上移动最好是snake[i].y -= speed .这样蛇就是上移。

对于food(食物处),我们定义的x,y是为后续的随机坐标做好准备的。

三.数据的初始化

void GameInit()
{
    //init;初始化 graph 图形窗口
    initgraph(640,480);
    //设置随机数种子 GetTickCount 获取系统开机到当前运行所经过的时间
    srand(GetTickCount());
    //初始化蛇 一开始就有n节 n随你定义 这里我是3
    snake.size = 3;
    snake.speed = 5;
    snake.dir = RIGHT;
    //循环 这里是初始化蛇的位置 
    for (int i = 0; i < snake.size; i++) {
        snake.coor[i].x = 40 - 10*i
        snake.coor[i].y = 10;
    }

    //初始化食物,rand()是随机函数 来自头文件
    //一般把时间作为种子,时间在变化
    food.x = rand() % 640; // % n ---> 可以得到 0-(n-1)的数
    food.y = rand() % 480;
    food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
    food.r = rand() % 10 + 5; //随机这个食物的半径 最小半径为5
    food.flag = true;
}

初始化的循环是为了 让蛇排列成行。 下标为0 是蛇头

四.图的绘制

void GameDraw()
{
    //双缓冲绘图 ---> 原因是会卡频
    //设置背景颜色
    setbkcolor(RGB(28,115,119)); //颜色可以按自己喜好的来
    cleardevice(); //清空绘图设备
    //绘制蛇
    setfillcolor(GREEN);
    for (int i = 0; i < snake.size; i++) {
        solidcircle(snake.coor[i].x,snake.coor[i].y, 5); //半径为5
    }
    //绘制食物
    if (food.flag)
    {
        solidcircle(food.x, food.y, food.r);
    }
    EndBatchDraw();
}

1.头文件graphics.h包含cleardevice()函数,该函数在图形模式下清除屏幕并将当前位置设置为(0,0)。清除屏幕包括用当前背景色填充屏幕。

2.if条件判断是为了判断食物是否被吃 后刷新食物。

3.EndBatchDraw();---相关官方文档在这easyx文档

五.蛇的移动

//移动蛇
void snakemove()
{
	//移动是什么发生改变;坐标改变
	for (int i = snake.size; i > 0 ; i--)
	{
		snake.coor[i] = snake.coor[i - 1];
	}
	//移动是什么发生改变
	switch (snake.dir)
	{
	case UP:
		snake.coor[0].y-=snake.speed;
		if (snake.coor[0].y+10 <= 0) 
		{
			snake.coor[0].y = 640;
		}//超出了上面的边界
		break;
	}
	switch (snake.dir)
	{
	case DOWN:
		snake.coor[0].y+=snake.speed;
		if (snake.coor[0].y - 10 >= 640) {
			snake.coor[0].y = 0;
		}
		break;
	}
	switch (snake.dir)
	{
	case LEFT:
		snake.coor[0].x-=snake.speed;
		if (snake.coor[0].x + 10 <= 0) {
			snake.coor[0].x = 640;
 		}
		break;
	}
	switch (snake.dir)
	{
	case RIGHT:
		snake.coor[0].x+=snake.speed;
		if (snake.coor[0].x - 10 >= 640) {
			snake.coor[0].x = 0;
 		}
		break;
	}
	
}

六.keyborad (键盘控制)

//通过按键操作
void keyControl()
{
	//判断有无按键
	if (_kbhit()) //检测是否有按键
	{
		//72 80 75 77 上下左右键值
		switch (_getch())
		{
		case 'w':
		case 'W':
		case 72:
			//改变方向
			if (snake.dir != DOWN) {
				snake.dir = UP;
			}
			break;
		case 's':
		case 'S':
		case 80:
			if (snake.dir != UP) {
				snake.dir = DOWN;
			}
			break;
		case 'a':
		case 'A':
		case 75:
			if (snake.dir != RIGHT) {
				snake.dir = LEFT;
			}
			break;
		case 'd':
		case 'D':
		case 77:
			if (snake.dir != LEFT) {
				snake.dir = RIGHT;
			}
			break;
		}
	}
}

对于_kbhit() --->判断是否keyboard被按动 并返回bool值

_getch() ---> 获取按键信息

七.吃食物

void EatFood()
{
	if (snake.coor[0].x >= food.x - food.r && snake.coor[0].x <= food.x + food.r
		&& snake.coor[0].y >= food.y - food.r && snake.coor[0].y <= food.y + food.r)
	{
		food.flag = false;
		snake.size++;
	}
	if (!food.flag){
		food.x = rand() % 640;
		food.y = rand() % 480;
		food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
		food.r = rand() % 10 + 5;
		food.flag = true;
	}
	/*
	可以加一个分数,吃一个食物,加n分
	*/
}

TIPS:

这里的两个if判断语句

对于第一个if,是判定什么时候什么范围,蛇将这个食物给吃了  可以同过点到圆心的距离

即 d <= r(该圆半径)  (d为距离---为两个圆心的距离) 此时,两个圆相交便为吃了,否则,玩家的操作系数上升,不适宜游玩。

对于第二个if,是为了刷新被吃掉的食物。

八.游戏暂停

void stop()
{
    //判断是否键盘按动 和 是否为空格键
    if (_kbhit() && _getch() == ' ')
    {
        while(1)
        {
            if (_getch() == ' ')
            {
                break;
            }
        }
    }
}

原理是:我们写一个死循环 while(1)---来占用进程,以达到暂停效果。 里面还有一个if判断是为了用户在按下一次的空格键下,打破循环,继续游戏。

二.主函数实现最终效果

int main()
{
    //在主函数调用,出现初始化结果
    GameInit();
    
    //防止闪退
    while(1) {
        GameDraw();
        snakemove();
        stop();
        keyControl();
        EatFood();
        Sleep(30); //防止太快移动,延迟
    }
    return 0;
}

注意,这里的stop()---游戏暂停函数一定要放到前面,否则会达不到暂停的效果。

在我们完成这些代码,F5调试时,可能有些人的蛇无法移动。

解决方案是:在shell(控制面板)来操控蛇的移动。就是那个黑框框。

也有不用在这个shell里面操作的方案,但是操作起来有些麻烦,所以还是用这个简单些的方案好一些。

最后我将这个project的源码放入,感兴趣的同学也可以通过这以上的代码自行输入,会有很多感悟。

谢谢。

你可能感兴趣的:(个人小项目,c语言,算法,开发语言)