C语言循环链表实现贪吃蛇游戏
前置技能
在实现贪吃蛇游戏前,需要有以下基本知识:
- C语言开发基础,包括变量、指针、结构体等的基础使用;
- 循环链表的基本原理,包括循环链表的概念、实现等。
- 整个游戏的基本逻辑,包括贪吃蛇的移动和食物生成等。
游戏框架
本贪吃蛇游戏基于循环链表展开,游戏的实现需使用结构体和指针来实现单个节点及其相互关系的存储。
首先,我们需要定义一个结构体,用于存储每个节点的信息:
typedef struct SnakeNode {
int x; // 节点x坐标
int y; // 节点y坐标
struct SnakeNode *next; // 指向下一个节点的指针
} SnakeNode;
为了表示整个循环链表,我们还需要定义一个链表的头结点,代表着整个链表的第一个节点:
typedef struct Snake {
SnakeNode *head; // 链表头
int length; // 链表长度
int direction; // 贪吃蛇移动的方向
} Snake;
其中,length
表示链表中节点的数量,direction
表示当前贪吃蛇的移动方向,我们可以通过键盘事件来改变其方向。
节点的插入和删除
在初始化贪吃蛇之后,贪吃蛇的每次移动实际上是对链表进行了添加和删除操作。
对于贪吃蛇身体的每个节点,我们可以使用 malloc()
来为其动态分配内存。下面是一个示例代码,用于在链表头插入一个新的节点:
void add_node(Snake *snake, int x, int y) {
SnakeNode *node = (SnakeNode*)malloc(sizeof(SnakeNode));
node->x = x;
node->y = y;
node->next = snake->head;
snake->head = node;
snake->length++;
}
当贪吃蛇移动时,如果贪吃蛇没有吃到食物,那么需要从链表尾部删除一个节点,示例代码如下:
void remove_tail(Snake *snake) {
if(snake->length == 0) {
return;
}
SnakeNode *p = snake->head;
for(int i = 1; i < snake->length; i++) {
p = p->next;
}
SnakeNode *q = p->next;
p->next = q->next;
free(q);
snake->length--;
}
游戏的实现
一旦我们定义好了节点的插入和删除,我们就可以开始实现贪吃蛇游戏的主要逻辑了。
当用户输入一个移动方向的命令后,贪吃蛇需要朝着这个方向移动。这里可能需要使用到一些算法来判断贪吃蛇下一步是否会碰到边界或自己的身体。如果贪吃蛇吃到了食物,则需要将食物的坐标记录在链表中,并在屏幕上生成一个新的食物。
整个游戏的主循环代码如下:
int main() {
init(); //游戏初始化
while(1) {
if(kbhit()) {
char ch = getch();
switch(ch) {
case 'w': snake.direction = UP; break;
case 's': snake.direction = DOWN; break;
case 'a': snake.direction = LEFT; break;
case 'd': snake.direction = RIGHT; break;
}
}
move(); // 移动贪吃蛇
if(is_over()) {
gameover(); // 游戏结束
break;
}
draw(); // 绘制贪吃蛇
}
return 0;
}
在游戏结束后,需要清理所有节点占用的内存:
void clear() {
SnakeNode *p = snake.head;
while(p != NULL) {
SnakeNode *q = p->next;
free(p);
p = q;
}
}
示例说明
下面示例代码演示了贪吃蛇的初始化、插入、删除等节点操作以及游戏循环逻辑。在运行程序后,用户可以通过键盘输入控制贪吃蛇的方向,并通过绘制贪吃蛇身体和食物等元素获得视觉反馈。
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <graphics.h>
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
typedef struct SnakeNode {
int x;
int y;
struct SnakeNode *next;
} SnakeNode;
typedef struct Snake {
SnakeNode *head;
int length;
int direction;
} Snake;
typedef struct Food {
int x;
int y;
} Food;
Snake snake;
Food food;
int score = 0;
void init_snake() {
snake.head = NULL;
snake.length = 0;
snake.direction = RIGHT;
add_node(&snake, 5, 5);
add_node(&snake, 4, 5);
add_node(&snake, 3, 5);
}
void init_food() {
srand(time(NULL));
food.x = rand() % 600;
food.y = rand() % 400;
}
void draw_snake() {
SnakeNode *p = snake.head;
while(p != NULL) {
rectangle(p->x, p->y, p->x + 10, p->y + 10);
p = p->next;
}
}
void draw_food() {
setcolor(YELLOW);
rectangle(food.x, food.y, food.x + 10, food.y + 10);
}
void move() {
int old_x = snake.head->x;
int old_y = snake.head->y;
switch(snake.direction) {
case UP: snake.head->y -= 10; break;
case DOWN: snake.head->y += 10; break;
case LEFT: snake.head->x -= 10; break;
case RIGHT: snake.head->x += 10; break;
}
SnakeNode *p = snake.head->next;
while(p != NULL) {
int tmp_x = p->x;
int tmp_y = p->y;
p->x = old_x;
p->y = old_y;
old_x = tmp_x;
old_y = tmp_y;
p = p->next;
}
}
void add_node(Snake *snake, int x, int y) {
SnakeNode *node = (SnakeNode*)malloc(sizeof(SnakeNode));
node->x = x;
node->y = y;
node->next = snake->head;
snake->head = node;
snake->length++;
}
void remove_tail(Snake *snake) {
if(snake->length == 0) {
return;
}
SnakeNode *p = snake->head;
for(int i = 1; i < snake->length; i++) {
p = p->next;
}
SnakeNode *q = p->next;
p->next = q->next;
free(q);
snake->length--;
}
int is_eat() {
if(snake.head->x == food.x && snake.head->y == food.y) {
return 1;
}
return 0;
}
void eat() {
init_food();
add_node(&snake, food.x, food.y);
score++;
}
int is_over() {
SnakeNode *p = snake.head->next;
while(p != NULL) {
if(snake.head->x == p->x && snake.head->y == p->y) {
return 1;
}
p = p->next;
}
if(snake.head->x < 0 || snake.head->x > 600 ||
snake.head->y < 0 || snake.head->y > 400) {
return 1;
}
return 0;
}
void gameover() {
printf("Game Over\n");
printf("Score: %d\n", score);
}
void init() {
initwindow(640, 480, "Snake Game");
init_snake();
init_food();
}
void draw() {
setcolor(WHITE);
cleardevice();
draw_snake();
draw_food();
delay(100);
}
void clear() {
SnakeNode *p = snake.head;
while(p != NULL) {
SnakeNode *q = p->next;
free(p);
p = q;
}
}
int main() {
init();
while(1) {
if(kbhit()) {
char ch = getch();
switch(ch) {
case 'w': snake.direction = UP; break;
case 's': snake.direction = DOWN; break;
case 'a': snake.direction = LEFT; break;
case 'd': snake.direction = RIGHT; break;
}
}
move();
if(is_eat()) {
eat();
} else {
remove_tail(&snake);
}
if(is_over()) {
gameover();
break;
}
draw();
}
clear();
closegraph();
return 0;
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言循环链表实现贪吃蛇游戏 - Python技术站