学习编程也有两三年时间了,中间也玩(学校安排学习)过很多东西 ,从汇编到C到Java和python。用Java和Python也就图一快,真要体会编程乐趣还得看我C语言(开玩笑 )
为什么要用C语言写一个贪吃蛇游戏呢,其实这是我大一时候万姐布置的一个课设,当时就是这个课设,逼着我一个星期“学会了”C语言,但是这段回忆是非常充实有趣的,现在我掌握了新的语言,新的编程思想,回过头来重新做一遍这个课设,感受编程带给我的最初的快乐。
贪吃蛇游戏我相信大家都玩过,具体规则也不用我多说,那么直接开始吧!
那么如何用C语言表示一条蛇呢?倘若使用Java或者Python这种面向对象语言,我们肯定会为蛇创建一个对象,再添加相应的属性和方法来表示蛇的特征,在C语言中,可以使用结构体来实现相似的功能。
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;
定义了蛇的表示,那么蛇有哪些行为需要我们实现呢?
毫无疑问,在游戏中,我们要在地图上生成一条蛇,那么一个生成蛇的方法肯定少不了,于是有了
Snake *new_born_snake(int pos_x, int pos_y);
参数pos_x
,pox_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, int pos_x, int pos_y);
void eat(Snake* snake, Direction dir, int pos_x, int pos_y);
蛇吃到食物需要生长,我们就假设食物的位置变为一节蛇身(蛇头),尾巴不去掉,那么用上面add_head_node
方法同样可以实现。
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;
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, int pos_x, int pos_y) {
Sleep(700 - snake->speed * 300);
snake->head->dir = dir;
add_head_node(snake, pos_x , pos_y);
remove_tail_node(snake);
}
void eat(Snake* snake, Direction dir, int pos_x, int pos_y) {
Sleep(700 - snake->speed * 300);
snake->head->dir = dir;
add_head_node(snake, pos_x, pos_y);
}