c语言实现贪吃蛇游戏,包含对代码的注解
时间: 2024-03-22 10:41:19 浏览: 65
C语言实现贪吃蛇游戏代码
5星 · 资源好评率100%
好的,以下是一个简单的 C 语言实现贪吃蛇游戏的代码,附有注释解释。
```c
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#define WIDTH 30 // 地图宽度
#define HEIGHT 20 // 地图高度
#define INITIAL_LENGTH 4 // 初始蛇身长度
#define INTERVAL 150 // 刷新间隔时间,单位毫秒
// 定义地图、蛇、食物的符号表示
#define MAP_SYMBOL ' '
#define SNAKE_SYMBOL 'O'
#define FOOD_SYMBOL '*'
// 定义蛇的结构体
typedef struct _snake_node {
int x;
int y;
struct _snake_node *next;
} SnakeNode, *Snake;
// 定义游戏状态
typedef enum _game_state {
STATE_NORMAL, // 正常游戏状态
STATE_OVER // 游戏结束状态
} GameState;
// 全局变量
Snake snake; // 蛇的链表
int food_x, food_y; // 食物的坐标
int score; // 得分
GameState state; // 游戏状态
// 函数声明
void InitGame(); // 初始化游戏
void DrawMap(); // 绘制地图
void InitSnake(); // 初始化蛇
void CreateFood(); // 随机生成食物
void MoveSnake(int dx, int dy); // 移动蛇
void UpdateGameState(); // 更新游戏状态
void GameOver(); // 游戏结束
void PrintScore(); // 输出得分
int main()
{
InitGame(); // 初始化游戏
while (1)
{
if (_kbhit()) // 如果有按键按下
{
int ch = _getch(); // 获取按下的键值
switch (ch)
{
case 'a':
MoveSnake(-1, 0); // 左
break;
case 'd':
MoveSnake(1, 0); // 右
break;
case 'w':
MoveSnake(0, -1); // 上
break;
case 's':
MoveSnake(0, 1); // 下
break;
default:
break;
}
}
// 更新游戏状态
UpdateGameState();
// 如果游戏结束,退出循环
if (state == STATE_OVER)
break;
Sleep(INTERVAL); // 等待一段时间,控制游戏速度
}
GameOver(); // 游戏结束
return 0;
}
// 初始化游戏
void InitGame()
{
srand((unsigned int)time(NULL)); // 设置随机数种子
// 绘制地图
DrawMap();
InitSnake(); // 初始化蛇
CreateFood(); // 随机生成食物
score = 0; // 得分清零
state = STATE_NORMAL; // 进入正常游戏状态
}
// 绘制地图
void DrawMap()
{
system("cls"); // 清屏
int i, j;
for (i = 0; i <= HEIGHT + 1; i++)
{
for (j = 0; j <= WIDTH + 1; j++)
{
if (i == 0 || i == HEIGHT + 1 || j == 0 || j == WIDTH + 1)
printf("#"); // 边框
else
printf("%c", MAP_SYMBOL); // 地图
}
printf("\n");
}
}
// 初始化蛇
void InitSnake()
{
int i;
SnakeNode *node;
// 创建初始蛇身
for (i = 0; i < INITIAL_LENGTH; i++)
{
// 分配结点内存
node = (SnakeNode*)malloc(sizeof(SnakeNode));
node->x = WIDTH / 2 + i;
node->y = HEIGHT / 2;
node->next = snake;
snake = node; // 添加到链表头部
}
// 绘制蛇
node = snake;
while (node != NULL)
{
printf("\033[%d;%dH%c", node->y + 1, node->x + 1, SNAKE_SYMBOL);
node = node->next;
}
}
// 随机生成食物
void CreateFood()
{
// 食物不能在蛇身上
do
{
food_x = rand() % WIDTH + 1;
food_y = rand() % HEIGHT + 1;
} while (IsSnakeNode(food_x, food_y));
// 绘制食物
printf("\033[%d;%dH%c", food_y + 1, food_x + 1, FOOD_SYMBOL);
}
// 移动蛇
void MoveSnake(int dx, int dy)
{
// 计算蛇头新位置
int new_x = snake->x + dx;
int new_y = snake->y + dy;
// 判断是否吃到食物
if (new_x == food_x && new_y == food_y)
{
// 创建新的蛇头结点
SnakeNode *node = (SnakeNode*)malloc(sizeof(SnakeNode));
node->x = new_x;
node->y = new_y;
node->next = snake;
snake = node; // 添加到链表头部
CreateFood(); // 生成新的食物
score++; // 得分加一
}
else
{
// 创建新的蛇头结点
SnakeNode *node = (SnakeNode*)malloc(sizeof(SnakeNode));
node->x = new_x;
node->y = new_y;
node->next = snake;
snake = node; // 添加到链表头部
// 删除蛇尾结点
SnakeNode *tail = snake;
while (tail->next->next != NULL)
tail = tail->next;
printf("\033[%d;%dH%c", tail->next->y + 1, tail->next->x + 1, MAP_SYMBOL); // 清除蛇尾结点
free(tail->next); // 释放蛇尾结点内存
tail->next = NULL; // 将尾结点指针置为空
}
// 绘制新的蛇头
printf("\033[%d;%dH%c", new_y + 1, new_x + 1, SNAKE_SYMBOL);
}
// 更新游戏状态
void UpdateGameState()
{
// 判断是否撞墙
if (snake->x <= 0 || snake->x >= WIDTH + 1 || snake->y <= 0 || snake->y >= HEIGHT + 1)
{
state = STATE_OVER; // 进入游戏结束状态
return;
}
// 判断是否撞到自己
if (IsSnakeNode(snake->x, snake->y) > 1)
{
state = STATE_OVER; // 进入游戏结束状态
return;
}
}
// 判断坐标是否在蛇身上,返回在蛇身上的结点个数
int IsSnakeNode(int x, int y)
{
int count = 0;
SnakeNode *node = snake;
while (node != NULL)
{
if (node->x == x && node->y == y)
count++;
node = node->next;
}
return count;
}
// 游戏结束
void GameOver()
{
printf("\033[%d;%dHGame Over!", HEIGHT / 2 + 1, (WIDTH - 9) / 2 + 1); // 输出游戏结束信息
PrintScore(); // 输出得分
}
// 输出得分
void PrintScore()
{
printf("\033[%d;%dHYour score: %d", HEIGHT / 2 + 2, (WIDTH - 12) / 2 + 1, score);
}
```
注释解释:
- 定义了一些常量,如地图的宽度、高度、初始蛇身长度、刷新间隔时间等。
- 定义了地图、蛇、食物的符号表示,用于绘制游戏界面。
- 定义了蛇的结构体,包括 x 坐标、y 坐标和下一个结点的指针。
- 定义了游戏状态,包括正常游戏状态和游戏结束状态。
- 定义了全局变量,包括蛇的链表、食物的坐标、得分和游戏状态。
- 定义了一些函数,包括初始化游戏、绘制地图、初始化蛇、随机生成食物、移动蛇、更新游戏状态、游戏结束和输出得分。
- 在 main 函数中,首先调用 InitGame 函数初始化游戏,然后进入循环,不断监听键盘输入,根据不同的按键调用 MoveSnake 函数移动蛇,然后更新游戏状态,直到游戏结束。
- InitGame 函数中,首先设置随机数种子,然后调用 DrawMap 函数绘制地图,接着调用 InitSnake 函数初始化蛇,随机生成食物,得分清零,进入正常游戏状态。
- DrawMap 函数中,先调用 system 函数清屏,然后用两重循环绘制地图和边框。
- InitSnake 函数中,先创建初始蛇身,然后遍历蛇的链表,绘制蛇。
- CreateFood 函数中,先随机生成食物坐标,然后检查食物是否在蛇身上,如果是就重新生成,最后绘制食物。
- MoveSnake 函数中,先计算蛇头新位置,然后判断是否吃到食物,如果是就创建新的蛇头结点,添加到链表头部,并生成新的食物,得分加一;如果不是就创建新的蛇头结点,添加到链表头部,删除蛇尾结点,得分不变。最后绘制新的蛇头。
- UpdateGameState 函数中,先判断是否撞墙,如果是就进入游戏结束状态;然后判断是否撞到自己,如果是就进入游戏结束状态。
- IsSnakeNode 函数中,遍历蛇的链表,判断坐标是否在蛇身上,返回在蛇身上的结点个数。
- GameOver 函数中,输出游戏结束信息,然后调用 PrintScore 函数输出得分。
- PrintScore 函数中,输出得分信息。
阅读全文