使用C语言实现经典贪吃蛇游戏

一、项目概述

我们的目标是创建一个基本的贪吃蛇游戏,它具有以下功能:

蛇能够根据玩家的键盘输入改变方向。

当蛇吃到食物时,蛇的长度增加,同时分数增加。

蛇可以在窗口边缘"穿墙"移动。

游戏界面包括一个蛇和一个随机出现的食物。

支持游戏暂停功能。

二、环境配置

为了实现这个项目,我们需要准备以下开发工具:

  1. Visual Studio Code 或其他任何C/C++ IDE。

  2. Turbo C++ 或者安装了相应库的现代IDE,因为代码中使用了graphics.h,该头文件通常与Turbo C++一起使用。

  3. MinGW 或者其他编译器,用来编译C代码。

注意:graphics.h库不是标准C库的一部分,在某些现代环境中可能不可用。如果不能使用graphics.h,可以考虑使用如SDL、OpenGL等其他图形库来替代。

三、代码详解

1. 数据结构定义

首先,定义了两个结构体:snakeFood。其中snake包含蛇的位置信息和方向等属性;Food则表示食物的位置和颜色等信息。

struct snake {
	int size;
	int dir;
	int speed;
	POINT coor[SNAKE_NUM];
};

struct Food {
	int score;
	int x;
	int y;
	int r;
	bool flag;
	DWORD color;
};

2. 初始化游戏

初始化函数GameInit()负责设置游戏的基本参数,如图形窗口的大小、蛇的初始位置和速度等。

void GameInit() {
	initgraph(640, 480, SHOWCONSOLE);
	srand(GetTickCount());
	snake.size = 3;
	snake.speed = 10;
	snake.dir = RIGHT;
	...
}

3. 绘制游戏画面

GameDraw()函数负责绘制当前的游戏状态,包括背景色、蛇和食物的位置。

void GameDraw() {
	BeginBatchDraw();
	setbkcolor(RGB(28, 115, 119));
	cleardevice();
	// 绘制蛇和食物
	...
	EndBatchDraw();
}

4. 控制蛇的移动

snakeMove()函数根据当前的方向更新蛇的位置,并实现了蛇穿过屏幕边缘的功能。

void snakeMove() {
	for (int i = snake.size - 1; i > 0; i--) {
		snake.coor[i] = snake.coor[i - 1];
	}
	switch (snake.dir) {
		case UP: ...
		case DOWN: ...
		case LEFT: ...
		case RIGHT: ...
	}
}

5. 用户输入处理

keyControl()函数监听键盘输入并改变蛇的方向。

void keyControl() {
	if (_kbhit()) {
		switch (_getch()) {
			case 'w': ...
			case 's': ...
			case 'a': ...
			case 'd': ...
			case ' ': // 暂停游戏
				while (1) {
					if (_getch() == ' ') return;
				}
		}
	}
}

6. 吃食物逻辑

Eatfood()函数检查蛇是否吃到了食物,如果是,则增加蛇的长度和玩家的分数。

void Eatfood() {
	if (food.flag && ... && ...) {
		food.flag = false;
		snake.size++;
	}
	if (!food.flag) {
		food.x = rand() % 640;
		...
		food.flag = true;
	}
	if (!food.flag) {
		food.score++;
		printf("得分: %d", food.score);
	}
}

四、主循环

最后,在main()函数中创建了一个无限循环,用于不断更新游戏状态和渲染画面。

int main() {
	GameInit();
	GameDraw();

	while (1) {
		GameDraw();
		snakeMove();
		keyControl();
		Eatfood();
		Sleep(100);
	}

	return 0;
}

完整代码:

cpp 复制代码
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<stdlib.h>
#define SNAKE_NUM 500 //蛇的最大节数
enum DIR //蛇的方向
{
	UP,
	DOWN,
	LEFT,
	RIGHT,
};
//蛇的结构
struct snake
{
	int size;//蛇的节数
	int dir;//蛇的方向
	int speed;//蛇的速度
	POINT coor[SNAKE_NUM];//坐标
}snake;
//食物结构
struct Food
{
	int score;
	int x;
	int y;
	int r; //食物大小
	bool flag;//食物是否被吃
	DWORD color;

}food;
//数据初始化
void GameInit()
{						//显示控制台
	initgraph(640, 480,SHOWCONSOLE);//图形窗口
	//设置随机数种子
	srand(GetTickCount());
	//初始化蛇 一开始有三节
	snake.size = 3;
	snake.speed = 10;
	snake.dir = RIGHT;
	for (int i = 0; i < snake.size ; i++)
	{
		snake.coor[i].x = 40-10*i;
		snake.coor[i].y = 10;
	}
	//初始化食物 rand()随机生产一个整数
	//随机数种子需要头文件stdlib.h
		food.x = rand() % 640;
		food.y = rand() % 480;
		food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
		food.r = rand() % 10 + 5;
		food.flag = true;

}
void GameDraw()
{
	//双缓冲绘图
	BeginBatchDraw();
	setbkcolor(RGB(28, 115, 119));//设置背景颜色
	cleardevice();
	//绘制蛇
	setfillcolor(YELLOW);
	for (int i = 0; i < snake.size; i++)
	{
		solidcircle(snake.coor[i].x, snake.coor[i].y, 5);
	}
	//绘制食物
	if (food.flag)
	{
		solidcircle(food.x, food.y, food.r);
	}
	EndBatchDraw();
}
//移动蛇
void snakeMove()
{
	//移动即蛇头改变
	//让身体跟随蛇头移动
	for (int i = snake.size-1; i > 0; i--)
	{
		snake.coor[i] = snake.coor[i - 1];
	}
		switch (snake.dir)
		{
		case UP:
			snake.coor[0].y-=snake.speed;
			if (snake.coor[0].y + 10 <= 0)//超出上面的边界
			{
				snake.coor[0].y = 480;
			}
			break;
		case DOWN:
			snake.coor[0].y+=snake.speed;
			if (snake.coor[0].y - 10 >= 480)
			{
				snake.coor[0].y = 0;
			}
			break;
		case LEFT:
			snake.coor[0].x-=snake.speed;
			if (snake.coor[0].x + 10 <= 0)
			{
				snake.coor[0].x = 640;
			}
			break;
		case RIGHT:
				snake.coor[0].x+=snake.speed;
				if (snake.coor[0].x - 10 >= 640)
				{
					snake.coor[0].x = 0;
				}
				break;
		}
	
}
//通过按键改变蛇的方向
void keyControl()
{
	//判断有没有按键,如果有按键就返回真
	if (_kbhit())
	{
		//72 80 75 77上下左右键值
		switch (_getch())
		{
		case 'w':
		case 'W': 
		case 72:
			//改变方向
			if (snake.dir != DOWN)
			{
				snake.dir = UP;
			}
			break;
		case 's':
		case 'S':
		case 80:
			if (snake.dir != UP)
			{
				snake.dir = DOWN;
			}
			break;
		case 'a':
		case 'A':
		case 75:
			if (snake.dir !=RIGHT)
			{
				snake.dir = LEFT;
			}
			break;
		case 'd':
		case 'D':
		case 77:
			if (snake.dir != LEFT)
			{
				snake.dir = RIGHT;
			}
			break;
		case' '://游戏暂停逻辑
			while (1)
			{
				if (_getch() == ' ')
					return;
			}
			break;
	    }
	}
}
void Eatfood()
{		//判断食物是否存在
	if (food.flag && snake.coor[0].x >=food.x-food.r && snake.coor[0].x<= food.x+food.r&&
		snake.coor[0].y>=food.y-food.r && snake.coor[0].y<=food.y+food.r)
	{
		food.flag = false;
		snake.size++;
	}//若食物消失,则重新生成
	if (!food.flag)
	{
		food.x = rand() % 640;
		food.y = rand() % 480;
		food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
		food.r = rand() % 10 + 5;
		food.flag = true;
	}
	//吃食物加分
	if (!food.flag)
	{
		food.score++;
		printf("得分:", food.score);
	}
}
int main()
{
	GameInit();
	GameDraw();

	while (1)
	{
		GameDraw();
		snakeMove();
		keyControl();
		Eatfood();
		Sleep(100);
	}

	return 0;
}
相关推荐
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
搬砖的小码农_Sky6 小时前
C语言:数组
c语言·数据结构
为什么每天的风都这么大7 小时前
Vscode/Code-server无网环境安装通义灵码
ide·vscode·阿里云·编辑器·ai编程·code-server
ahadee10 小时前
蓝桥杯每日真题 - 第19天
c语言·vscode·算法·蓝桥杯
Theliars10 小时前
C语言之字符串
c语言·开发语言
Reese_Cool10 小时前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法
搬砖的小码农_Sky11 小时前
C语言:结构体
c语言·数据结构
写点什么啦12 小时前
[debug]不同的window连接ubuntu的vscode后无法正常加载kernel
linux·vscode·ubuntu·debug
平头哥在等你13 小时前
求一个3*3矩阵对角线元素之和
c语言·算法·矩阵