
★hello,大家好,我是程序员黎明 ,写一个贪吃蛇游戏其实挺有意思的,用C语言可以实现一个简单版本,下面我就从第一视角带你了解一下怎么一步步写出来。
1. 确定思路
首先,我得弄清楚贪吃蛇的基本玩法:蛇在一个网格里移动,每次吃到食物就会变长,不能撞墙也不能撞自己。如果撞墙或者撞自己,那游戏就结束。
大体思路是这样:
-
蛇的身体可以用一个链表来表示,每个节点代表身体的一部分。 -
网格用二维数组来表示,0代表空地,1代表蛇,2代表食物。 -
蛇的头部会根据用户按的方向键来移动,每移动一步检查是否吃到食物或者撞到自己/墙。
2. 准备工作
我需要用到一些库函数:
#include <stdio.h> // 输入输出
#include <stdlib.h> // 动态内存分配
#include <conio.h> // 用于检测键盘输入
#include <windows.h> // 实现延时和光标移动
3. 定义数据结构
先把蛇和地图的数据结构搞定:
#define WIDTH 20 // 地图的宽度
#define HEIGHT 20 // 地图的高度
typedef struct Node { // 蛇的每一节
int x, y; // 位置
struct Node* next; // 指向下一个节点
} SnakeNode;
typedef struct {
SnakeNode* head; // 蛇头
SnakeNode* tail; // 蛇尾
int length; // 蛇的长度
} Snake;
int map[HEIGHT][WIDTH]; // 地图数组
int foodX, foodY; // 食物的坐标
蛇用链表来表示,蛇头和蛇尾分别有指针,这样方便控制蛇的增长和移动。
4. 初始化
我要让游戏有个初始状态,比如蛇和食物的位置。
void initGame(Snake* snake) {
// 初始化蛇,默认在地图中央
snake->head = (SnakeNode*)malloc(sizeof(SnakeNode));
snake->head->x = WIDTH / 2;
snake->head->y = HEIGHT / 2;
snake->head->next = NULL;
snake->tail = snake->head;
snake->length = 1;
// 清空地图
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
map[i][j] = 0;
}
}
// 设置食物位置
foodX = rand() % WIDTH;
foodY = rand() % HEIGHT;
map[foodY][foodX] = 2;
}
5. 游戏循环
游戏的主要逻辑需要不断重复,所以我需要一个循环来控制蛇的移动、吃食物、碰撞检测等。
5.1 方向控制
先处理方向控制,用户按方向键来控制蛇的移动方向:
char getInput() {
if (_kbhit()) { // 检查是否有按键输入
return _getch(); // 获取用户按下的键
}
return '\0'; // 没有输入时返回空字符
}
5.2 移动蛇
根据方向移动蛇的头部,然后更新身体位置:
void moveSnake(Snake* snake, char direction) {
int newX = snake->head->x;
int newY = snake->head->y;
// 根据方向调整新坐标
if (direction == 'w') newY--; // 上
else if (direction == 's') newY++; // 下
else if (direction == 'a') newX--; // 左
else if (direction == 'd') newX++; // 右
// 创建新节点并移动蛇头
SnakeNode* newHead = (SnakeNode*)malloc(sizeof(SnakeNode));
newHead->x = newX;
newHead->y = newY;
newHead->next = snake->head;
snake->head = newHead;
// 检查是否吃到食物
if (newX == foodX && newY == foodY) {
snake->length++;
// 随机生成新食物
foodX = rand() % WIDTH;
foodY = rand() % HEIGHT;
map[foodY][foodX] = 2;
} else {
// 蛇尾跟随移动,释放旧蛇尾节点
SnakeNode* temp = snake->tail;
snake->tail = snake->tail->next;
free(temp);
}
}
5.3 碰撞检测
每次移动蛇后,我还得检查有没有撞墙或者撞自己。
int checkCollision(Snake* snake) {
int headX = snake->head->x;
int headY = snake->head->y;
// 撞墙
if (headX < 0 || headX >= WIDTH || headY < 0 || headY >= HEIGHT) {
return 1;
}
// 撞自己
SnakeNode* current = snake->head->next;
while (current != NULL) {
if (current->x == headX && current->y == headY) {
return 1;
}
current = current->next;
}
return 0;
}
5.4 游戏展示
要让玩家看到蛇和食物,我需要实时刷新屏幕,把当前的状态打印出来。
void drawGame(Snake* snake) {
system("cls"); // 清屏
// 绘制地图
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++) {
if (i == snake->head->y && j == snake->head->x) {
printf("O"); // 蛇头
} else if (i == foodY && j == foodX) {
printf("F"); // 食物
} else {
printf(" "); // 空地
}
}
printf("\n");
}
}
6. 游戏结束
一旦蛇撞墙或者撞自己,游戏就结束,跳出循环:
int main() {
Snake snake;
initGame(&snake);
char direction = 'd'; // 初始方向向右
while (1) {
char input = getInput();
if (input) {
direction = input;
}
moveSnake(&snake, direction);
if (checkCollision(&snake)) {
printf("Game Over!\n");
break;
}
drawGame(&snake);
Sleep(200); // 控制移动速度
}
return 0;
}
7. 总结
这就是一个简单版的贪吃蛇游戏,用C语言实现的。我主要用了链表来存储蛇的身体,每次蛇移动的时候,蛇头会变成新位置,蛇尾则跟着移动。如果你想要加更多功能,比如加速、关卡等,可以在这个基础上继续扩展哦。
这样写出来的贪吃蛇虽然很基础,但完全可以作为学习C语言编程的一个好项目。好了,本期我们就学到这里啦,我们下期不见不散!


