当前位置: 首页 > news >正文

实战项目:贪吃蛇游戏的实现(上)

前言

Hello, 今天我们来一起完成一个实战项目:贪吃蛇

相信大家都不会对这个游戏感到陌生,贪吃蛇游戏是久负盛名的游戏,他和俄罗斯方块,扫雷游戏等游戏位列世界经典游戏之列。这次我们旨在通过实战项目贪吃蛇的实现,从设计到代码的实现来提升我们的编程能力和逻辑运算能力!

游戏效果展示:

贪吃蛇游戏效果演示

1.项目目标:

  • 使用C语言在 Windows环境下的控制台模拟实现经典小游戏贪吃蛇
  • 实现的基本功能:
  • 贪吃蛇地图的绘制
  • 蛇吃食物的功能(上、下、左、右方向的控制键来控制蛇的动作)
  • 蛇撞到墙后立即死亡
  • 蛇撞到自身立即死亡
  • 计算得分
  • 蛇身发的加速和减速
  • 暂停游戏

2.技术要点

C语言函数、枚举、动态内存管理、预处理指令、初步解接触数据结构中的链表。

3.Windows系统工具函数

 3.1Win32API介绍

本次实现贪吃蛇会使用一些Win32API的知识,我们想要顺利的完成任务就要去认真掌握其中的一些函数。

Windows这个多作业系统除了协调应用程序的执行、分配管理、资源管理之外,他还是一个好大吃的服务中心,调用这个服务中心的服务(每一种服务就是一种函数)。可以帮助我们达到开启视窗、描绘图像、使用周边设备等目的,由于这些函数的服务对象是一些应用程序(Application),所以百年称之为Applicatino Programming Interface,简称API函数。WIN32API也是Microsoft Windows32w位平台的应用程序编程接口。

3.2控制台程序

平常我们运行起来的黑框程序其实就是控制台程序。

我们可以使用cmd命令来设置控制台窗口的长和宽:设置控制台窗口的大小,30行,100列

mode con cols=100 lines=30

也可以通过命令设置窗口的名字:

title 贪吃蛇

 

这些能在控制台窗口执行的命令,也可以调用C语言函数system来执行。例如:

#include<stdio.h>
int main()
{//设置控制台窗⼝的⻓宽:设置控制台窗⼝的⼤⼩,30⾏,100列system("mode con cols=100 lines=30");//设置cmd窗⼝名称system("title 贪吃蛇");getchar();return 0;
}

 3.3控制平台上的坐标COORD

COORD是WindowsAPI上定义的一个结构体·,表示一个字符在控制台屏幕上的坐标 

typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;

給坐标赋值:

COORD pos = { 10, 15 };

3.4GetStdHandle

GetStdHandle是一个WindowsAPI函数。它用于从一个特定的标准设备(标准输入、标准输出或者是标准错误)中取得一个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。

HANDLE GetStdHandle(DWORD nStdHandle);

实例:
 

HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

3.5GetConsoleCursorInfo

 检索有关指定的控制台的屏幕缓冲区堆的光标大小和课件行的信息

BOOL WINAPI GetConsoleCursorInfo(
HANDLE hConsoleOutput,
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
)

实例:

HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

3.5.1 CONSOLE_CURSOR_INFO

这个结构体,包含控制台光标信息

typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
  •  deSize,有光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会随着变化,范围从完全填充单元格到单元底部的水平线条。
  • bVisible,游标的可见性。如果光标可见则此成员为TRUE。
CursorInfo.bVisible = false; //隐藏控制台光标

 3.6SetConsoleCursorInfo

设置指定的控制台屏幕缓冲区光标的大小和可见性。

BOOL WINAPI SetConsoleCursorInfo(
HANDLE hConsoleOutput,
const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);

实例:

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

3.7 SetConsoleCursorPosition

设置制定控制台屏幕缓冲区中光标位置,我们将想要的设置的光标坐标信息放在COOR来行的pos中,调用SetConsoleCursorPosition的函数将光标的位置设定到指定的位置。

BOOL WINAPI SetConsoleCursorPosition(
HANDLE hConsoleOutput,
COORD pos
)

实例:

COORD pos = { 10, 5};
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);

SetPos:封装一个光标位置的函数

//设置光标的坐标
void SetPos(short x, short y)
{
COORD pos = { x, y };
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
}

3.8GetAsyncKeyState

获取按键情况,这个函数的原型如下:

 

SHORT GetAsyncKeyState(
int vKey
);

将键盘上的每个按键的虚拟键值传递给函数,函数通过返回值来分辨案件的状态。

GetAsyncKeyState的返回值是short类型的,在上一次调用GetAsyncKeyState函数后,如果返回的是16位的short数据,最高位是1,说明按键的状态是按下,如果最高位是0,则按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。

如果我们要判断一个案件是否被按过,可以检测GetAsyncKeyState返回值的最低位是否为1.

#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

4.贪吃蛇游戏的设计与分析

4.1地图 

 我们最终想要的贪吃蛇大纲可能就是这个样子,按我们要如何进行的图的布置呢?

 

这里我们不得不在讲一下控制窗台的知识了,如果想要在控制台的窗口指定位置输出信息,我们得知道该位置的坐标,所以首先介绍一下控制窗口的坐标知识。

控制窗口的坐标只是如下所示,横向的是x轴,从左向右依次增长,纵向是Y轴,从上到下一次增长。

 

在游戏地图上,我们打印墙体使用宽字符:□ ;打印蛇身我们使用:●;打印食物‘使用宽字符:★’,普通的字符只占一个字节,这类宽字符是占用2个字节。

这里简单的讲一下C语言国际化特性相关的知识,过去C语言并不适合非英语的国家(地区)使用。

C语言最初假定假定字符都是自己的。但是这些假定并不是在世界所有的地方都适用。

后来C鱼啊一年适应到了国际化,C语言标准中不断加入国际化的支持,比如:加入和宽字符的类型wchar_t和宽字符的输入和输出函数,加入<locale.h>头文件,其中提供了允许程序员针对特定地区(通常是国家或者说特定语言的地理地区)调整程序行为的函数。

4.1.1<locale.h>本地化

<locale.h>提供的函数用于控制C语言标准库中对于不同地区会产生的不一样行为的部分·。
在标准可以中,依赖地区的部分有以下几项:

  • 数字量的格式
  • 货币量的格式
  • 字符集
  • 日期和时间的表示形式

 4.1.2类项

通过修改地区,程序可以改变它的行为来适应世界的不同区域。单区域的改变可能影响库的许多部分其中一部分可能使我们不希望改变的。所以C语言针对不同的类项进行修改,下面的一个宏,指定一个类项:

• LC_COLLATE

• LC_CTYPE

• LC_MONETARY

setlocale(LC_ALL, "C");

• LC_NUMERIC

• LC_TIME

• LC_ALL - 针对所有类项修改

4.1.3 setlocale函数

char* setlocale (int category, const char* locale);

setlocale函数用于修改当前的地区,可以针对一个类想项修改,也可以针对所有的类项修改。

setlocale的·第一个参数可以是前面说明的类项中的一个,那么每次只会影响一个类项,如果第一个·参数是LC_ALL,就会影响所有的类项。

C标准给定的第二个参数仅定义了两种可能得取值:“c” 和“ ”。

在任意程序运行是,都会隐藏式执行调用:

setlocale(LC_ALL, "C");

当地区设置为"c"时,库函数按正常的方式执行,小数点是一个点。

的那个吃呢工序运行起来之后想要改变地区,就只能显示调用setlocale函数。用“”作为第二个参数,调用setlocale函数就可以切回到本地模式,这中模式下程序 会适应本地环境。比如:切换到我们本地模式后就支持宽字符(汉字的输出)等。

setlocale(LC_ALL, " ");//切换到本地环境

4.1.4宽字符的打印

那如果想在屏幕上打印宽字符,怎么打印呢?

 

#include <stdio.h>
#include<locale.h>
int main() {
setlocale(LC_ALL, ""
wchar_t ch1 = L'●';
wchar_t ch2 = L'⽐';
wchar_t ch3 = L'特';
wchar_t ch4 = L'★';
printf("%c%c\n", 'a', 'b');
wprintf(L"%c\n", ch1);
wprintf(L"%c\n", ch2);
wprintf(L"%c\n", ch3);
wprintf(L"%c\n", ch4);
return 0;
}

从输出来看,我们发现一个普通的字符占一个字符的位置但是打印一个汉字字符,占用2个字符的位置,那么我们如果在贪吃蛇中使用宽字符,就得憨憨处理地图上的坐标计算。

1个坐标1个正常字符

2个坐标可以存放一个宽字符 

 4.1.5地图坐标

我们假设实现一个棋盘27行,58列的棋盘(行和列可以根据自己的爱好设计修改),再围绕地图画出墙如下:
 

4.2蛇身和食物

初始化状态,假设蛇的长度为5,蛇身上的·节点是●,在固定的一个坐标处,比如(24,5)处开始出现蛇,连续5个节点。注意:蛇的每个节点的x坐标必须是2的倍数,否则可能出现蛇的一个节点有一半出现在墙体中。另外一半在墙体外的现象,坐标不好对齐。

关于食物,就是在墙体内随机生成一个坐标(X坐标必须是2的倍数),坐标不能和蛇的身体重合,让后打印★ 

 

相关文章:

实战项目:贪吃蛇游戏的实现(上)

前言 Hello, 今天我们来一起完成一个实战项目&#xff1a;贪吃蛇。 相信大家都不会对这个游戏感到陌生&#xff0c;贪吃蛇游戏是久负盛名的游戏&#xff0c;他和俄罗斯方块&#xff0c;扫雷游戏等游戏位列世界经典游戏之列。这次我们旨在通过实战项目贪吃蛇的实现&#xff0c…...

SHT30温湿度传感器全解析——概况,性能,MCU连接,样例代码

常见温湿度传感器测量范围&#xff1a;(价格仅供参考&#xff0c;具体性能要看折线图) 型号DHT11DHT20AHT10AHT20AHT30SHT20价格&#xffe5; 2.49&#xffe5;3.04&#xffe5; 1.9&#xffe5;1.4&#xffe5; 1.3&#xffe5;5.5温度测量范围20—90%RH0—100%RH0—100%RH0—…...

SQL server 同环比计算模板

1、计算 月 年 季度的环比和同比 计算公式如下&#xff1a; 环比增长率 &#xff08;本期数 - 上期数&#xff09; / |上期数| 100% 同比增长率 &#xff08;本期数 - 同期数&#xff09; / |同期数| * 100% --- dbo.ads_erp_finance_gross_profit_actual_invoice_yoy_m…...

python发送外部请求

在Python中&#xff0c;服务器发送外部请求是一个常见的操作&#xff0c;尤其是在需要集成不同服务或API时。有多种库可以帮助你完成这项任务&#xff0c;但最流行和广泛使用的库之一是requests。以下是如何使用requests库在Python服务器中发送外部请求的基本步骤&#xff1a; …...

c++并发编程面试题

1. C中lock_guard和unique_lock的区别&#xff1f; 在C中&#xff0c;lock_guard和unique_lock都是用于管理互斥锁的类&#xff0c;它们提供了一种 RAII&#xff08;Resource Acquisition Is Initialization&#xff09;机制来确保锁在作用域结束时自动释放。尽管它们的目的相…...

K8S上安装LongHorn(分布式块存储) --use

要在 Kubernetes上安装 LongHorn&#xff0c;您可以按照以下步骤进行操作&#xff1a; 准备工作 参考 官网教程将LongHorn只部署在k8s-worker5节点上。https://github.com/longhorn/longhorn 安装要求 Each node in the Kubernetes cluster where Longhorn is installed must f…...

2024年前端技术发展趋势分析

2024年的前端技术发展趋势继续受到快速变化的技术环境和不断增长的用户期望的影响。以下是2024年前端技术发展的几个关键趋势&#xff1a; 1. Web 组件和自定义元素 Web 组件技术&#xff08;包括 Shadow DOM、HTML Templates 和 Custom Elements&#xff09;正在成为构建可重…...

spring boot 笔记大杂烩

一&#xff0c;springboot项目创建 springboot创建时idea会打开start.spring.io失败报错 可以手动打开这个页面&#xff0c;然后选择maven项目&#xff0c;然后修改group和name名然后添加依赖web&#xff0c;然后生成项目包&#xff0c;解压缩后用idea打开就能用了 运行后报错…...

如何在香港云服务器上优化网站性能?

在香港云服务器上优化网站性能可以通过以下几种方式进行&#xff0c;确保用户从全球各地访问时获得快速、稳定的体验&#xff1a; 1. 使用内容分发网络 (CDN) 优势&#xff1a;CDN可以将静态内容&#xff08;如图像、视频、CSS、JavaScript文件&#xff09;缓存到全球多个节点…...

STM32低功耗与备用备份区域

STM的备份备用区域其实就是两个区块&#xff1a;BKP和RTC。低功耗则其实是STM32四种模式中的三种耗能很低的模式。 目录 一&#xff1a;备用区域 1.BKP 2.RTC 二&#xff1a;低功耗模式 1.睡眠模式&#xff1a; 2.停机模式&#xff1a; 3.待机模式&#xff1a; 一&…...

武汉某汽配公司携手三品软件 共绘PLM项目新蓝图

近日&#xff0c;三品软件与武汉某汽配公司达成战略合作&#xff0c;双方将共同启动PLM项目&#xff0c;以助力该公司在汽车制造业的研发管理领域实现全面升级。 客户简介 该公司自2008年成立以来&#xff0c;一直专注于为汽车制造业提供自动化输送系统、车辆装配的合装技术和…...

uniapp多图上传uni.chooseImage上传照片uni.uploadFile,默认上传9张图

uniapp多图上传uni.chooseImage上传照片uni.uploadFile 代码示例&#xff1a; /**上传照片 多图*/getImage() {uni.chooseImage({count: 9, //默认9sizeType: [original, compressed], //可以指定是原图还是压缩图&#xff0c;默认二者都有sourceType: [album], //从相册选择/…...

MySQL——内置函数

时间函数 select * from msg where date_add(sendtime, interval 2 minute) > now(); 理解&#xff1a; ------------------------------|-----------|-------------|------------------ 初始时间 now() 初始时间2min 字符串 length函数返回字符串长度&#xff0c;以字节为…...

2024年最新版小程序云开发数据模型的开通步骤,支持可视化数据库管理,支持Mysql和NoSql数据库,可以在vue3前端web里调用操作

小程序官方又改版了&#xff0c;搞得石头哥不得不紧急的再新出一版&#xff0c;教大家开通最新版的数据模型。官方既然主推数据模型&#xff0c;那我们就先看看看新版的数据模型到底是什么。 一&#xff0c;什么是数据模型 数据模型是什么 数据模型是一个用于组织和管理数据的…...

智慧水库大坝安全监测预警系统解决方案

前言 水库大坝作为重要的水利设施&#xff0c;承载着防洪涝、灌溉、发电等功能&#xff0c;关系着无数人的生命财产安全&#xff0c;一旦发生意外事故&#xff0c;后果将不堪设想&#xff0c;因此需要建立一套水库大坝安全监测预警系统解决方案。 系统概述 水库大坝安全监测…...

基于SpringBoot+VUE的社区团购系统(源码+文档+部署)

主要内容&#xff1a;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能与大数据、单片机开发、物联网设计与开发设计、简历模板、学习资料、面试题库、技术互助、就业指导等 业务范围&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写…...

LeetCode 3151. 特殊数组 I【数组】简单【Py3,C++,Java,GO,Rust】

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

超级字符串技能:提升你的编码游戏

嘿嘿,uu们,今天咱们来详解字符函数与字符串函数,好啦,废话不多讲,开干&#xff01; 1.:字符分类函数 C语言中又一系列的函数是专门做字符分类的,也就是一个字符属于什么类型的字符的,这些函数的使用需要包含头文件ctype.h 这些函数的使用方法都十分类似,博主在这里就举两到三个…...

米联客-FPGA程序设计Verilog语法入门篇连载-16 Verilog语法_时钟分频设计

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本小节讲解Verilog语法的时钟…...

【Echarts】custom自定义图表实现甘特图

效果图 主要注意点&#xff1a; 1、右上角图例visualMap实现 2、visualMap增加formatter 3、series使用custom自定义图表&#xff0c;encode解析四维数组。核心是renderItem方法&#xff0c;必填项&#xff0c;且需要注意要全部定义在options里面&#xff01;&#xff01;&…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...