c语言实现greedy snake(贪吃蛇)

2024-03-25 08:10

本文主要是介绍c语言实现greedy snake(贪吃蛇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

##第一个小项目  大一学生寒假项目

最终实现效果如图

一.以C语言实现个人小项目

在我们快速学完了一个高级编程语言,就应该写一个小项目来加以巩固自己的学习成果。

所以今天,我们来尝试写一写greedy snake,对于大学生来说也是可以加强能力的存在。事不宜迟,我们开始吧。(Tips:我会加入一些外部链接,这些于编写遇到的问题有关,可以帮助你更好的解决)

外部文件的引入以及一些定义

#include <stdio.h>
#include <graphics.h> //与绘图文件有关
#include <conio.h>    //两个都需要
#include <stdlib.h>
#define SNAKE_NUM 500 //宏定义 规定好蛇的最大节数,以防溢出
enum DIR //枚举初始化方向
{UP,DOWN,LEFT,RIGHT,
};

解释:

我们在第四行引入的头文件是为了产生一个生成随机数的种子(所以我们引入了该头文件)

5函数名称: rand

函数原型: int rand(void);

函数功能: 产生0到32767间的随机整数(0到0x7fff之间)

函数返回: 随机整数

对于第二,第三行的头文件引入。

我在这里放好了它的下载官网,官网有下载说明,不复杂的

easyx文档 点击此处

二.蛇和食物的结构体定义

struct Snake
{int size; //蛇的长度int dir; //蛇的方向int speed; //蛇的速度POINT coor[SNAKE_NUM]; //坐标
}snake;struct food
{int x;int y;int r; //食物大小bool flag; //为后面判断食物是否被吃做准备DWORO color;  //规定食物的颜色
}food;

在这里,我们注意一下 POINT coor[] 是我们引入了相应的头文件,以有表示二维坐标的

函数。 后续创建实体的写法是---> snake[i].x = 坐标点 其中i是它的大小。

并且,这里的坐标轴与数学中的有些不同,y轴的正方向是朝下的,所以我们想让蛇向上移动最好是snake[i].y -= speed .这样蛇就是上移。

对于food(食物处),我们定义的x,y是为后续的随机坐标做好准备的。

三.数据的初始化

void GameInit()
{//init;初始化 graph 图形窗口initgraph(640,480);//设置随机数种子 GetTickCount 获取系统开机到当前运行所经过的时间srand(GetTickCount());//初始化蛇 一开始就有n节 n随你定义 这里我是3snake.size = 3;snake.speed = 5;snake.dir = RIGHT;//循环 这里是初始化蛇的位置 for (int i = 0; i < snake.size; i++) {snake.coor[i].x = 40 - 10*isnake.coor[i].y = 10;}//初始化食物,rand()是随机函数 来自头文件<stdlib.h>//一般把时间作为种子,时间在变化food.x = rand() % 640; // % n ---> 可以得到 0-(n-1)的数food.y = rand() % 480;food.color = RGB(rand() % 256, rand() % 256, rand() % 256);food.r = rand() % 10 + 5; //随机这个食物的半径 最小半径为5food.flag = true;
}

初始化的循环是为了 让蛇排列成行。 下标为0 是蛇头

四.图的绘制

void GameDraw()
{//双缓冲绘图 ---> 原因是会卡频//设置背景颜色setbkcolor(RGB(28,115,119)); //颜色可以按自己喜好的来cleardevice(); //清空绘图设备//绘制蛇setfillcolor(GREEN);for (int i = 0; i < snake.size; i++) {solidcircle(snake.coor[i].x,snake.coor[i].y, 5); //半径为5}//绘制食物if (food.flag){solidcircle(food.x, food.y, food.r);}EndBatchDraw();
}

1.头文件graphics.h包含cleardevice()函数,该函数在图形模式下清除屏幕并将当前位置设置为(0,0)。清除屏幕包括用当前背景色填充屏幕。

2.if条件判断是为了判断食物是否被吃 后刷新食物。

3.EndBatchDraw();---相关官方文档在这easyx文档

五.蛇的移动

//移动蛇
void snakemove()
{//移动是什么发生改变;坐标改变for (int i = snake.size; 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 = 640;}//超出了上面的边界break;}switch (snake.dir){case DOWN:snake.coor[0].y+=snake.speed;if (snake.coor[0].y - 10 >= 640) {snake.coor[0].y = 0;}break;}switch (snake.dir){case LEFT:snake.coor[0].x-=snake.speed;if (snake.coor[0].x + 10 <= 0) {snake.coor[0].x = 640;}break;}switch (snake.dir){case RIGHT:snake.coor[0].x+=snake.speed;if (snake.coor[0].x - 10 >= 640) {snake.coor[0].x = 0;}break;}}

六.keyborad (键盘控制)

//通过按键操作
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;}}
}

对于_kbhit() --->判断是否keyboard被按动 并返回bool值

_getch() ---> 获取按键信息

七.吃食物

void EatFood()
{if (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;}/*可以加一个分数,吃一个食物,加n分*/
}

TIPS:

这里的两个if判断语句

对于第一个if,是判定什么时候什么范围,蛇将这个食物给吃了  可以同过点到圆心的距离

即 d <= r(该圆半径)  (d为距离---为两个圆心的距离) 此时,两个圆相交便为吃了,否则,玩家的操作系数上升,不适宜游玩。

对于第二个if,是为了刷新被吃掉的食物。

八.游戏暂停

void stop()
{//判断是否键盘按动 和 是否为空格键if (_kbhit() && _getch() == ' '){while(1){if (_getch() == ' '){break;}}}
}

原理是:我们写一个死循环 while(1)---来占用进程,以达到暂停效果。 里面还有一个if判断是为了用户在按下一次的空格键下,打破循环,继续游戏。

二.主函数实现最终效果

int main()
{//在主函数调用,出现初始化结果GameInit();//防止闪退while(1) {GameDraw();snakemove();stop();keyControl();EatFood();Sleep(30); //防止太快移动,延迟}return 0;
}

注意,这里的stop()---游戏暂停函数一定要放到前面,否则会达不到暂停的效果。

在我们完成这些代码,F5调试时,可能有些人的蛇无法移动。

解决方案是:在shell(控制面板)来操控蛇的移动。就是那个黑框框。

也有不用在这个shell里面操作的方案,但是操作起来有些麻烦,所以还是用这个简单些的方案好一些。

最后我将这个project的源码放入,感兴趣的同学也可以通过这以上的代码自行输入,会有很多感悟。

谢谢。

这篇关于c语言实现greedy snake(贪吃蛇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/844365

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

MySQL 横向衍生表(Lateral Derived Tables)的实现

《MySQL横向衍生表(LateralDerivedTables)的实现》横向衍生表适用于在需要通过子查询获取中间结果集的场景,相对于普通衍生表,横向衍生表可以引用在其之前出现过的表名,本文就来... 目录一、横向衍生表用法示例1.1 用法示例1.2 使用建议前面我们介绍过mysql中的衍生表(From子句