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

news2024/11/7 11:30:10

一、项目概述

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

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

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

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

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

支持游戏暂停功能。

二、环境配置

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

  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;
}

完整代码:

#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;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2228614.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot Configuration和AutoConfiguration加载逻辑和加载顺序调整

在spring中&#xff0c; AutoConfiguration也是一个种Configuration&#xff0c;只是AutoConfiguration是不能使用proxy的。 而且spring对于两者的加载顺序也不是一视同仁&#xff0c;是有顺序的。spring会先加载SpringBootApplication可达的且标注了Configuration的类&#x…

算法速刷(LeetCode)(160.相交链表)

个人思路&#xff1a; 笨蛋做法&#xff0c;但是好用 代码如下 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public class Solution …

面试记录(1)

java中的抽象类和接口的区别&#xff1a; 相同点 (1) 都可以被继承 (2) 都不能被实例化 (3) 都可以包含方法声明 (4) 派生类必须实现未实现的方法 不同点 1.关键字不同&#xff1a; ​ ① 继承抽象类的关键字是extends&#xff0c;而实现接口的关键字是implements&#xff1b;…

MATLAB下的四个模型的IMM例程(CV、CT左转、CT右转、CA四个模型),附源代码可复制

文章目录 基于IMM算法的目标跟踪概述源代码运行结果代码结构与功能1. 初始化2. 仿真参数设置3. 模型参数设置4. 生成量测数据5. IMM算法初始化6. IMM迭代7. 绘图8. 辅助函数总结基于IMM算法的目标跟踪 概述 该MATLAB代码实现了基于交互式多模型(IMM)算法的目标跟踪,旨在估…

Jmeter实际应用

环境准备 JDK1.8Jmeter 5.6.3 下载地址Jmeter 插件 下载地址 放到lib/ext下 常用命令 # 启动 sh jmeter# 集群模式下启动节点&#xff0c;不启动用不了集群 sh jmeter-server#生成ssl需要的证书, 这里会要求输入个密码&#xff0c;是要在jmeter中用的 keytool -import -ali…

使用 Flask 实现简单的登录注册功能

目录 1. 引言 2. 环境准备 3. 数据库设置 4. Flask 应用基本配置 5. 实现用户注册 6. 实现用户登录 7. 路由配置 8. 创建前端页面 9. 结论 1. 引言 在这篇文章中&#xff0c;我们将使用 Flask 框架创建一个简单的登录和注册系统。Flask 是一个轻量级的 Python Web 框架…

SystemC学习(3)— APB_SRAM的建模与测试

SystemC学习&#xff08;3&#xff09;— APB_SRAM的建模与测试 一、前言 二、APB_SRAM建模 编写APB_SRAM模型文件apb_sram.h文件如下所示&#xff1a; #ifndef __APB_SRAM_H #define __APB_SRAM_H#include "systemc.h"const int ADDR_SIZE 32; const int DATA_…

新兴斗篷cloak技术,你了解吗?

随着互联网技术的飞速发展&#xff0c;网络营销领域也经历了翻天覆地的变革。 从最早的网络横幅广告到如今主流的搜索引擎和社交媒体营销&#xff0c;广告形式变得越来越多样。 其中&#xff0c;搜索引擎广告一直以其精准投放而备受青睐&#xff0c;但近年来&#xff0c;一项名…

UG NX二次开发(C#)-计算圆柱面与其他平面的夹角

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、首先创建一个三维模型3、 源代码4、调用代码1、前言 在QQ群中,有群友提问了如何判断圆柱面与某一平面是否垂直,我这里以案例的形式计算圆柱面主轴矢量与平面法矢的夹角,如果夹角为0,…

基于卷积神经网络的棉花病虫害识别与防治系统,resnet50,mobilenet模型【pytorch框架+python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 棉花病害识别与防治系统&#xff0c;卷积神经网络&#xff0c;resnet50&#xff0c;mobilenet【pytorch框架&#xff0c;python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积…

成都世运会志愿者招募报名流程及证件照制作方法

成都世运会志愿者招募正在如火如荼地进行中&#xff0c;许多热心公益的青年们纷纷报名参与。本文将详细介绍如何通过官方渠道报名&#xff0c;并使用手机来自行制作符合要求的4:5比例的白底证件照。 一、志愿者报名流程概述首先&#xff0c;报名成都世运会志愿者需要通过官方指…

Java 输入/输出(I/O)操作(10/30)

目录 Java 输入/输出&#xff08;I/O&#xff09;操作 1. Java I/O 类体系结构 2. 文件读写操作 2.1 使用 FileInputStream 和 FileOutputStream 进行字节流读写 2.2 使用 FileReader 和 FileWriter 进行字符流读写 3. 缓冲流的使用 3.1 使用 BufferedReader 和 Buffere…

Unity XR Interaction Toolkit 开发教程(1):OpenXR 与 XRI 概述【3.0 以上版本】

文章目录 &#x1f4d5;Unity XR 开发架构&#x1f50d;底层插件&#xff08;对接硬件&#xff09;&#x1f50d;高层 SDK&#xff08;面向应用交互层&#xff09; &#x1f4d5;OpenXR&#x1f4d5;XR Interaction Toolkit&#x1f50d;特点&#x1f50d;XRI 能够实现的交互类…

Nginx防盗链配置

1. 什么是盗链? 盗链是指服务提供商自己不提供服务的内容&#xff0c;通过技术手段绕过其它有利益的最终用户界面&#xff08;如广告&#xff09;&#xff0c;直接在自己的网站上向最终用户提供其它服务提供商的服务内容&#xff0c;骗取最终用户的浏览和点击率。受益者不提供…

使用Scrapy框架爬取博客信息

随着网络的发展&#xff0c;越来越多有价值的信息存储在网络上。使用爬虫技术可以从这些信息源中提取出有用的数据。本文将介绍如何使用Python中的Scrapy框架来爬取博客站点上的文章标题、作者以及阅读数&#xff0c;并将其保存到JSON文件中。 一、项目背景 Scrapy是一个快速…

Vue2.0 通过vue-pdf-signature@4.2.7和pdfjs-dist@2.5.207实现PDF预览

1.安装依赖 npm install pdfjs-dist2.5.207 --savenpm install vue-pdf-signature4.2.7 --save2.在.vue文件中 script 部分引入 <script> import * as PDFJS from pdfjs-dist PDFJS.GlobalWorkerOptions.workerSrc require(pdfjs-dist/build/pdf.worker.js);//解决pdf…

A4-C四驱高防变电站巡检机器人

在电力行业数字化、智能化转型进程中&#xff0c;搭载多模态成像传感器的变电站巡检机器人、视频监控设备逐渐取代传统人工&#xff0c;成为变电设备状态监测的主要工具。变电站巡检机器人具有全天候、非接触式、多参量测量等特点&#xff0c;结合内置人工智能算法完成仪表识别…

““ 引用类型应用举例

#include <iostream> //使能cin(),cout(); #include <stdlib.h> //使能exit(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用se…

Git 本地操作(2)

会以下操作就可以完成本地的版本控制了&#xff0c;就不需要再复制文件每次改一个东西就复制整个工程保存下来啦&#xff01; 建议先看上一篇文章噢 &#xff01;&#xff01;&#xff01; 一、新建项目git本地操作 1、初始化仓库 创建一个 project 文件夹&#xff0c;将需…

室内障碍物射线追踪算法matlab模拟仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 增加发射点 加入室内墙壁&#xff1a; 同时增加发射点和室内墙壁&#xff1a; 2.算法运行软件版本 matlab2022a 3.部分…