用链表写一个简单的贪吃蛇游戏

1、首先兴建一个坐标系,蛇生成和移动与食物的生成均在此坐标系上移动,使用两个一维数组分别表示X轴和Y轴。以圆形作为蛇头和蛇身,每一次蛇移动的圆形都要在坐标上。此处生成一个640 x 480的窗口大小

	int x_coor[64], y_coor[48];
	for (int i = 0; i < 64; i++)
		x_coor[i] = RADIUS + 2 * i * RADIUS;
	for (int i = 0; i < 48; i++)
		y_coor[i] = RADIUS + 2 * i * RADIUS;

2、链表表示蛇头和蛇身。蛇的链表结构表示为:

struct Snake {
	int x;
	int y;
	int Length;
	Snake* next;
};

初始化一个蛇头,坐标在坐标系中随机选择一个

	Snake* snake = NULL;
	int direction = RIGHT;
	snake = (Snake*)malloc(sizeof(Snake));
	int x = rand() % 64;
	int y = rand() % 48;
	if (!snake) exit(OVERFLOW);
	snake->x = x_coor[x];
	snake->y = y_coor[y];
	snake->next = NULL;

初始化蛇的身体,蛇的身体,初始化蛇身体函数传入蛇头,初始🐍方向向右。🐍身体坐标可根据🐍头坐标依次获得。

void initSnake(Snake* snake) {
	int i = 0;
	Snake* q = snake;
	while (i < O_LENGTH)
	{
		Snake* p = NULL;
		p = (Snake*)malloc(sizeof(Snake));
		if (!p)
			exit(OVERFLOW);
		p->x = (snake->x - (i + 1) * 2 * RADIUS);
		p->y = snake->y;
		p->next = NULL;
		q->next = p;
		q = p;
		i++;
	}
	q->next = NULL;
	snake = q;
	snake->Length = i;
}

画出🐍的头和身体

void drawSnake(Snake* snake)
{
	Snake* p = NULL;
	p = (Snake*)malloc(sizeof(Snake*));
	if (!p)
		exit(OVERFLOW);
	p = snake;
	Color color{};
	color.r = rand() % 255;
	color.g = rand() % 255;
	color.b = rand() % 255;
	while (p)
	{
		setfillcolor(RGB(color.r, color.g, color.b));
		solidcircle(p->x, p->y, RADIUS);
		p = p->next;
	}
	free(p);
}

3、初始化食物并且画出食物。食物只包含坐标,X坐标和Y坐标,以及食物坐标的改变。参考🐍头的生成生成食物

struct Food {
	int x;
	int y;
};

Food* initFood(int x_coor[], int y_coor[])
{
	Food* food = NULL;
	food = (Food*)malloc(sizeof(Food*));
	if (!food)
		exit(OVERFLOW);
	Color color{};
	color.r = rand() % 128 + 128;
	color.g = rand() % 128 + 128;
	color.b = rand() % 128 + 128;
	int x = rand() % 64;
	int y = rand() % 48;
	food->x = x_coor[x];
	food->y = y_coor[y];
	setfillcolor(RGB(color.r, color.g, color.b));
	solidcircle(food->x, food->y, RADIUS);
	return food;

}

void changeFoodxy(Food* food, int x_coor[], int y_coor[])
{
	//food = NULL;
	if (!food)
		exit(OVERFLOW);
	Color color{};
	color.r = rand() % 128 + 128;
	color.g = rand() % 128 + 128;
	color.b = rand() % 128 + 128;
	int x = rand() % 64;
	int y = rand() % 48;
	food->x = x_coor[x];
	food->y = y_coor[y];
	setfillcolor(RGB(color.r, color.g, color.b));
	solidcircle(food->x, food->y, RADIUS);
}

4、考虑🐍的移动,🐍移动只需要考虑蛇头的移动,🐍头移动之后,🐍的身体一次跟随头移动,第二节身体坐标即头改变前的坐标,第三节身体移动后坐标即第二节身体移动前坐标,后面一次替换即可。移动完成之后需要对🐍最后一节擦除,即颜色与背景颜色一致即可,并且重新画🐍

void snakeMove_RIGHT(Snake* snake)
{
	Snake temp{};
	Snake temp2{};

	temp.x = snake->x;
	temp.y = snake->y;
	snake->x = snake->x + 2 * RADIUS;
	snake->y = snake->y;
	//蛇移动应该是上下左右四个方向,此处先做向右移动
	while (snake->next)
	{
		temp2.x = snake->next->x;
		temp2.y = snake->next->y;

		snake->next->x = temp.x;
		snake->next->y = temp.y;

		snake = snake->next;
		temp.x = temp2.x;
		temp.y = temp2.y;
	}
	setfillcolor(BLACK);
	solidcircle(temp2.x, temp2.y, RADIUS);

}

5、判断🐍吃掉食物。吃掉食物头部坐标与食物圆心坐标相重合

6、身体变长。吃掉食物后身体长度应该加1,用尾插法在尾部加一节。新增一节坐标要考虑四种情况,分别是从上下左右吃掉食物,吃掉食物后需要重新生成

void snakeGrow(Snake* snake, Food* food, int direction, 
	int x_coor[], int y_coor[])
{
	if (eatFood(snake, food))
	{
		setfillcolor(BLACK);
		solidcircle(food->x, food->y, RADIUS);
		Snake* q = snake;
		snake->Length++;
		Snake* p;
		p = (Snake*)malloc(sizeof(Snake*));
		if (!p)
			exit(OVERFLOW);
		int i = 0;
		while (q->next)
		{
			q = q->next;
			i++;
		}
		switch (direction)
		{
		case RIGHT:	
			p->x = snake->x - RADIUS * i;
			p->y = snake->y;
			q->next = p;
			q = p;
			break;
		case LEFT:
			p->x = snake->x + RADIUS * i;
			p->y = snake->y;
			p->next = NULL;
			q->next = p;
			q = p;
			break;
		case TOP:
			p->x = snake->x;
			p->y = snake->y - RADIUS * i;
			q->next = p;
			q = p;
			break;
		case BOTTOM:
			p->x = snake->x;
			p->y = snake->y + RADIUS * i;
			q->next = p;
			q = p;
			break;
		default:
			break;
		}
		snake = q;
		free(p);
		changeFoodxy(food, x_coor, y_coor);	//重新生成食物
		
	}

7、控制🐍移动。定义一个键盘输入的"D"表示向右移动

void snakeControl(Snake* snake, char &key, int &direction)
{
	if (_kbhit())
		key = _getch();
	
	switch (key)
	{
	case 'W':snakeMove_UP(snake);
		direction = TOP;
		break;
	case 'A':snakeMove_LEFT(snake);
		direction = LEFT;
		break;
	case 'S':snakeMove_DOWN(snake);
		direction = BOTTOM;
		break;
	case 'D':snakeMove_RIGHT(snake);
		direction = RIGHT;
	default:
		break;
	}
}

8、判定🐍死亡。撞墙或者触碰到身体即表示死亡。

bool snakeDeath(Snake* snake)
{
	Snake* p = NULL;
	p = (Snake*)malloc(sizeof(Snake*));
	if (!p)
		exit(OVERFLOW);
	Snake temp{};
	p = snake;
	temp.x = snake->x;
	temp.y = snake->y;
	p = p->next;
	while (p) 
	{
		if (p->x == temp.x && p->y == temp.y)
			return true;	//触碰自己死亡
		p = p->next;
	}

	free(p);
	if ((snake->x + RADIUS) > RIGHT_BOUNDARY || (snake->x - RADIUS) < LEFT_BOUNDARY
		|| (snake->y + RADIUS) > BOTTOM_BOUNDARY || (snake->y - RADIUS) < TOP_BOUNDARY)
		return true;	//撞到墙体死亡
	else
		return false;

}

总结:最后不断循环即可,读者可以自行完善。基本可以正常运行,但在测试中依然有一丢丢的bug,希望大家可以多多指正。谢谢!!!

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值