再来一次的C语言贪吃蛇小游戏(一)

0. 写在开头

学习编程也有两三年时间了,中间也玩(学校安排学习)过很多东西 ,从汇编到C到Java和python。用Java和Python也就图一快,真要体会编程乐趣还得看我C语言(开玩笑 )

为什么要用C语言写一个贪吃蛇游戏呢,其实这是我大一时候万姐布置的一个课设,当时就是这个课设,逼着我一个星期“学会了”C语言,但是这段回忆是非常充实有趣的,现在我掌握了新的语言,新的编程思想,回过头来重新做一遍这个课设,感受编程带给我的最初的快乐。

贪吃蛇游戏我相信大家都玩过,具体规则也不用我多说,那么直接开始吧!

1. 如何表示一条蛇

那么如何用C语言表示一条蛇呢?倘若使用Java或者Python这种面向对象语言,我们肯定会为蛇创建一个对象,再添加相应的属性和方法来表示蛇的特征,在C语言中,可以使用结构体来实现相似的功能。

  • 蛇由多节蛇身组成,包括蛇头也算是蛇身,每个蛇身都是一个结构体,我采用双向环形链表来表示一条蛇,之所以使用双向循环链表,是为了每一节蛇身可以指向它的下一节蛇身,也可以指向它的上一节蛇身,同时头的上一节是尾巴,尾巴的下一节是头,便于我们遍历操作。类似于:(随意配图,无视苯环)
  • 每一节蛇身有自己的坐标,也有自己运动方向,还有两个分别指向前一节和后一节的指针
  • 蛇的运动方向,我们假设蛇只能向上下左右四个方向运动。
  • 蛇的运动速度,我们假设蛇可以慢速,正常速,快速三种速度 爪巴
  • 蛇的长度,我们记录在蛇的结构体内

2. 具体实现

snake.h头文件中部分内容:

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

typedef enum speed {
	slow,
	normal,
	fast,
}Speed;

//环状双向链表
typedef struct snake_body_node 
{
	int pos_x;
	int pos_y;
	Direction dir;
	struct snake_body_node *previous_node;
	struct snake_body_node *next_node;
}Snake_Body_Node;

typedef struct snake
{
	int length;
	Speed speed;
	Snake_Body_Node *head;
}Snake;

3. 蛇的行为

定义了蛇的表示,那么蛇有哪些行为需要我们实现呢?

毫无疑问,在游戏中,我们要在地图上生成一条蛇,那么一个生成蛇的方法肯定少不了,于是有了

Snake *new_born_snake(int pos_x, int pos_y);

参数pos_xpox_y分别表示最初蛇的位置,这里我将蛇最初的长度设为1,相当于就一脑袋

蛇肯定要移动,蛇在移动的时候,直观上蛇身的全部节点都要移动,但实际则不然,只有两节蛇身是需要变化的,一节是脑袋,一节是蛇尾,其余的蛇身移动的位置其实都是其上一个蛇身移动前的位置,那么我们可以不管这些节点,我们需要做的就是新建一个蛇头,去掉蛇尾。

void add_head_node(Snake* snake, int pos_x, int pos_y);
void remove_tail_node(Snake* snake);
void move(Snake* snake, Direction dir);

蛇吃到食物需要生长,我们就假设食物的位置变为一节蛇身(蛇头),尾巴不去掉,那么用上面add_head_node方法同样可以实现。

4. 具体实现

snake.c

#include "snake.h"

struct  snake * new_born_snake(int pos_x, int pos_y) 
{
	Snake* new_snake = (Snake*)malloc(sizeof(Snake));
	Snake_Body_Node *head = mknode();
	new_snake->length = 1;
	new_snake->speed = normal;
	head->dir = up;
	head->pos_x = pos_x;
	head->pos_y = pos_y;
	new_snake->head = head;
	head->next_node = head;
	head->previous_node = head;
	return new_snake;
}

void add_head_node(Snake* snake, int pos_x, int pos_y) 
{
	Snake_Body_Node *head = snake->head;
	Snake_Body_Node *body = mknode();
	body->pos_x = pos_x;
	body->pos_y = pos_y;
	body->dir = head->dir;
	if (head->next_node == head)
	{
		body->previous_node = head;
		head->next_node = body;
	}
	else
	{
		body->previous_node = head->previous_node;
		head->previous_node->next_node = body;

	}
	head->previous_node = body;
	body->next_node = head;
	snake->head = body;
	snake->length++;
}

void remove_tail_node(Snake* snake)
{
	Snake_Body_Node *head = snake->head;
	Snake_Body_Node *tail = head->previous_node;
	head->previous_node = tail->previous_node;
	tail->previous_node->next_node = head;
	free(tail);
	snake->length--;
}

void destroy_snake(Snake* snake)
{
	Snake_Body_Node* head = snake->head;
	while (head != head->next_node) {
		free(head);
		head = head->next_node;
	}
	free(head);
	free(snake);
}

Snake_Body_Node* mknode()
{
	Snake_Body_Node* node = (Snake_Body_Node*)malloc(sizeof(Snake_Body_Node));
	if (node == NULL)
	{
		printf("out of memory");
		exit(1);
	}
	return node;
}

void move(Snake* snake,  Direction dir) {
	Snake_Body_Node * head = snake->head;
	int pos_x = head->pos_x;
	int pos_y = head->pos_y;
	Sleep(700 - snake->speed * 200);
	switch (dir)
	{
	case up:
		snake->head->dir = up;
		add_head_node(snake, pos_x, pos_y - 1);
		remove_tail_node(snake);
		break;
	case right:
		snake->head->dir = right;
		add_head_node(snake, pos_x + 1, pos_y);
		remove_tail_node(snake);
		break;
	case down:
		snake->head->dir = down;
		add_head_node(snake, pos_x, pos_y + 1);
		remove_tail_node(snake);
		break;
	case left:
		snake->head->dir = left;
		add_head_node(snake, pos_x - 1, pos_y);
		remove_tail_node(snake);
		break;
	default:
		break;
	}
}

5. 在游戏中控制蛇,下篇揭晓。。。。。

发布了43 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/include_IT_dog/article/details/103924061
今日推荐