【C语言项目】贪吃蛇(上)

在这里插入图片描述

个人主页 ~

gitee仓库~


欢迎大家来到C语言系列的最后一个篇章–贪吃蛇游戏的实现,当我们实现了贪吃蛇之后,我们的C语言就算是登堂入室了,基本会使用了,当然,想要更加熟练地使用还需要多多练习

贪吃蛇

  • 一、目标
  • 二、需要的知识
    • 1、Win32 API概念
    • 2、控制台程序
      • (1)mode命令
      • (2)COORD坐标
      • (3)隐藏光标的操作
        • ①GetStdHandle
        • ②GetConsoleCursorlnfo
        • ③CONSOLE_CURSOR_INFO
        • ④SetConsoleCursorInfo
        • ⑤SetConsoleCursorPosition
        • 封装一个函数命名为SetPos,专门用来设置光标位置
      • (4)GetAsyncKeyState
  • 三、游戏设计与分析
    • 1、地图
      • (1)本地化
      • (2)类项
      • (3)setlocale
      • (4)宽字符的打印
      • (5)地图坐标
    • 2、蛇身和食物
    • 3、数据结构设计
    • 4、设计游戏流程

一、目标

使用C语言在Windows环境的控制台中模拟实现贪吃蛇游戏
功能:
①贪吃蛇地图
②蛇的移动
③蛇吃食物
④蛇撞墙或者撞到自己死亡
⑤计算得分
⑥暂停游戏
⑦加速蛇身
⑧计算得分

二、需要的知识

函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API
其中只有Win32 API我们在之前的博文中没有提到过,这里我们一起着重学习一下

1、Win32 API概念

Application Programming Interface(应用程序编程接口),简称API函数。
Windows是一个多作业系统,它除了协调应用程序的执行、分配内存、管理资源之外,也是一个很大的服务中心,调用这个服务中心的各种服务,其中每一种服务就是一个函数,可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的,这些函数服务的对象就是应用程序Application
Win32 API就是Windows32位平台的应用程序编程接口

2、控制台程序

在控制台能够执行的命令在编译器中也可以使用system函数来执行

(1)mode命令

mode con cols=100 lines=30;
#include <stdio.h>
int main()
{//设置控制台的大小为三十行一百列system("mode con cols=100 lines=30");//设置cmd窗⼝名称system("title 贪吃蛇"); return 0;
}

(2)COORD坐标

COORD是Windows API中的一个结构体,表示一个字符在控制台屏幕上的坐标,左上角的坐标为(0,0)
在这里插入图片描述
COORD中有两个short值,一个为x,一个为y

typedef struct _COORD
{SHORT X;SHORT Y;
}COORD,*PCOORD;
COORD p = {10,20};//给坐标赋值

(3)隐藏光标的操作

在游戏的过程中,我们需要打印蛇身,墙壁,食物等,当我们在进行游戏时,是看不到光标闪烁的,但光标是存在的,所以我们要将它们隐藏

①GetStdHandle

GetStdHandle也是一个Windows API函数,它用于从一个特定的设备(标准输入、标准输出、标准错误)中获得一个句柄,使用这个句柄可以操作设备

HANDLE GetStdHandle(DWORD nStdHandle);
②GetConsoleCursorlnfo

检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息

BOOL WINAPI GetConsoleCursorInfo
(HANDLE hConsoleoutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
//PCONSOLE_CURSOR_INFO是指向CONSOLE_CURSOR_INFO结构的指针

使用:

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

包含有关控制台光标的信息,是个结构体

typedef struct _CONSOLE_CURSOR_INFO 
{DWORD dwSize;//光标填充单元格的百分比,此值介于1-100,光标外观会发生变化BOOL bVisible;//游标的可见性,如果游标可见,其为TRUE,不可见为FALSE
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
④SetConsoleCursorInfo

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

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);//设置控制台光标状态
⑤SetConsoleCursorPosition

设置指定控制台屏幕缓冲区中的光标位置

BOOL WINAPI SetConsoleCursorPosition
(HANDLE hConsoleoutput,COORD pos
);

我们将想要设置的坐标信息放在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);//设置标准输出上光标的位置为posSetConsoleCursorPosition(houtput, pos);
}

(4)GetAsyncKeyState

原型:

SHORT GetAsyncKeyState
(int vKey
);

这个函数可以通过检测游戏进行时的按键来传递相应的返回值,可以实时监测此时按键的状态,调用后,如果该键按下返回的short值的最高位为1,否则为0,所以我们定义一个宏,来判断该键是否被按下

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

括号里是虚拟键代码,填入相应的虚拟键代码可以检测键是否被按下

三、游戏设计与分析

1、地图

在这里插入图片描述

在游戏中墙体、蛇体以及食物的打印用的是宽字符,占用两个字符,因为一个字符的话游戏会相当不美观,因为x轴的1和y轴的1的长度不同,y轴的1的长度约等于x轴的1的两倍

x=y=1时:
在这里插入图片描述

x=2,y=1时:
在这里插入图片描述
我们可以明显看出格子的区别
在宽字符打印之前我们要进行本地化

(1)本地化

包含头文件<local.h>

(2)类项

①LC_COLLATE:影响字符串比较函数strcoll和strxfrm
②LC_CTYPE:影响字符处理函数的行为
③LC_MONETARY:影响货币格式
④LC_NUMERIC:影响printf的数字格式
⑤LC_TIME:影响时间格式strftime和wcsftime
⑥LC_ALL:以上所有类别全部修改

(3)setlocale

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

该函数用来修改当前地区
第一个
第二个参数仅定义了两种可能的取值:
“C”正常模式
“ ”本地模式
切换到本地模式就可以支持宽字符的打印

setlocale(LC_ALL, "C");//正常模式
setlocale(LC_ALL, " ");//本地模式

(4)宽字符的打印

可以把宽字符看做是长的字符

#include <stdio.h>
#include <locale.h>
int main()
{
setlocale(LC_ALL, "");
wchar_t c = L's';
wchar_t s = L"little_monster";
wprintf(L"%lc",c);
wprintf(L"%ls",s);
}

(5)地图坐标

这里我们实现的地图是27*58的,围绕边缘打印一周墙体

2、蛇身和食物

开始时,假设蛇长度为5,蛇身的每个节点用◆符号,在一个固定的连续5个坐标放蛇身
蛇的每个节点的x坐标都是2的倍数(宽字符),否则会出现一半节点在里边一半节点在墙里
食物节点的x坐标也是2的倍数,并且坐标不能与蛇身重合

3、数据结构设计

游戏运行过程中,蛇每吃掉一个食物蛇体就增加一个节点,每个节点就存储当前的坐标以及下一个节点的坐标

typedef struct SnakeNode
{int x;int y;struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

现在我们有了节点的定义,我们再来用一个结构体维护整条贪吃蛇以及食物

typedef struct Snake
{pSnakeNode _pSnake;//维护整条蛇的指针pSnakeNode _pFood;//维护⻝物的指针enum DIRECTION _Dir;//蛇头的⽅向,默认是向右enum GAME_STATUS _Status;//游戏状态int _Socre;//游戏当前获得分数int _foodWeight;//默认每个⻝物10分int _SleepTime;//每⾛⼀步休眠时间
}Snake, * pSnake;

蛇的方向我们用枚举,因为蛇的行进方向只能有一个,使用枚举可以减小内存的占用

enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
};

游戏状态我们也用枚举,理由同上,状态只能有一个

enum GAME_STATUS
{OK,//正常运⾏KILL_BY_WALL,//撞墙KILL_BY_SELF,//咬到⾃⼰END_NOMAL//正常结束
};

4、设计游戏流程

在这里插入图片描述
当我们把整个框架定好,下一步就可以来实现游戏了


下一篇再见~

在这里插入图片描述

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

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

相关文章

(八)JSP教程——application对象

application对象是一个比较重要的对象&#xff0c;服务器在启动后就会产生这个application对象&#xff0c;所有连接到服务器的客户端application对象都是相同的&#xff0c;所有的客户端共享这个内置的application对象&#xff0c;直到服务器关闭为止。 可以使用application对…

MGRE 实验

需求&#xff1a;1、R2为ISP&#xff0c;其上只能配置IP地址。 2、R1-R2之间为HDLC封装 3、R2-R3之间为ppp封装&#xff0c;pap认证&#xff0c;R2为主认证方。 4、R2-R4之间为ppp封装&#xff0c;chap认证&#xff0c;R2为主认证方。 5、R1、R2、R3构建MGRE环境&#xff0…

sourceTree push失败

新电脑选择commit and push&#xff0c;报错了&#xff0c;不过commit成功&#xff0c;只不过push失败了。 原因是这个&#xff0c;PuTTYs cache and carry on connecting. 这里的ssh选择的是 PuTTY/Plink&#xff0c;本地没有这个ssh密钥&#xff0c;改换成openSSH&#xff…

DEV--C++小游戏(吃星星(0.1))

目录 吃星星&#xff08;0.1&#xff09; 简介 头文件 命名空间变量 副函数 清屏函数 打印地图函数 移动函数 主函数 0.1版完整代码 吃星星&#xff08;0.1&#xff09; 注&#xff1a;版本<1为未实现或只实现部分 简介 用wasd去吃‘*’ 头文件 #include<bi…

各种索引地址

直接索引&#xff0c;一级间接索引&#xff0c;二级间接索引 【软考】解析直接地址索引和间接地址索引_直接地址索引和一级地址索引-CSDN博客 系统架构设计师真题解析&#xff08;1&#xff09;—— 文件系统物理结构_文件系统采用索引节点管理-CSDN博客 磁盘块&#xff0c…

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解

Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解&#xff1a; HarmonyOS NEXT Preview系列教程基于Api11讲解-IT营大地老师 1 、电脑要求以及注意事项 操作系统 &#xff1a; Windows10 64 位、 Windows11 64 位 内存 &#xff1a; 8GB 及以上&#xff0c;推荐 16G…

AI中LangChain原理以及快速上手

AI中LangChain原理以及快速上手 什么是LangChain&#xff1f; LangChain是一种基于语言模型的自然语言处理技术&#xff0c;它可以将自然语言转换为向量表示&#xff0c;从而实现对自然语言的理解和处理。LangChain的核心思想是将自然语言中的每个单词或短语映射到一个高维向…

新火种AI|AI让大家都变“土”了!

作者&#xff1a;一号 编辑&#xff1a;美美 AI不仅要把人变“土”&#xff0c;还要把人变多样。 这个世界&#xff0c;终究是变“土”了。 今年五一假期&#xff0c;一个名为“Remini”的AI修图APP火遍了全网。注意&#xff0c;是Remini&#xff0c;而不是Redmi&#xff0…

Redis学习汇总

目录 1.Linux环境下安装redis 2.redis的数据结构及命令 3.redis.conf配置文件常用配置 3.redis的事务操作 4.redis实现乐观锁 5.通过jedis操作redis 6.Springboot集成redis 7.自定义一个RedisTemplate 8.持久化策略 RDB和AOF 9.redis集群环境搭建 10.哨兵模式 11.缓…

java集合中retainAll方法使用注意

java集合中retainAll方法使用注意 retainAll新的改变 retainAll retainAll()方法被用来找出两个集合的共同元素&#xff0c;并且只会在交集不为空的情况下返回true。通过比较操作前后集合的大小是否有变化&#xff0c;我们可以确定是否存在共同元素。 retainAl()方法会改变原集…

ES:基础查询语法(简单易懂)

一、基础查询语句的结构&#xff1a; GET http://ip:prot/textbook/_search GET { "query" : { ...query子句... }, "aggs" : { ..aggs子句.. }, "sort" : { ..sort子句.. } "from" : 0, // 返回搜索结果的开始位置 &…

解锁自动化办公新技能:Python实战应用-自动转发邮件到企业微信

&#x1f4e7; 【高效联络&#xff0c;信息不落空】 &#x1f4e7; 在这个信息爆炸的时代&#xff0c;作为企业的一员&#xff0c;我们如何从繁杂的邮件中迅速筛选出客户的心声、展会的新动向&#xff0c;同时又不遗漏每一份重要的咨询呢&#xff1f;秘诀就在我们的新策略里&a…

Springboot监听ConfigMap配置文件自动更新配置

背景&#xff1a; 最近调研使用k8s的ConfigMap来作为springboot项目的配置中心&#xff0c;需要实现热更新机制&#xff0c;避免pod重启影响业务。 ConfigMap作为挂载卷使用的时候可以更新pod中的配置内容&#xff0c;但是业务应用需要能监听并处理这些变更。我在测试的时候已…

Day3 | Java基础 | 4常见类

Day3 | Java基础 | 4 常见类 基础版Object类equalshashCode&#xff08;散列码&#xff09;hashCode和equals clone方法String类 问题回答版Object类Object类的常见方法有哪些&#xff1f;和equals()的区别是什么&#xff1f;为什么要有hashCode&#xff1f;hashCode和equals的…

FFmpeg常用命令详解与实战指南

下载地址&#xff1a;Releases BtbN/FFmpeg-Builds (github.com) 1. 获取视频信息 使用FFmpeg获取视频信息是最基本的操作之一。你可以使用-i选项指定输入文件&#xff0c;然后使用FFmpeg内置的分析器来获取视频的各种信息&#xff0c;包括视频编解码器、音频编解码器、分辨…

JAVA文件的简单操作

文件IO&#xff08;Input和Output&#xff09; 文件的输入和输出是人为规定的&#xff0c;那么什么是输入&#xff1f;什么是输出捏&#xff1f;在这里统一已CPU为基准 例如&#xff1a;将文件由内存写入硬盘就是输出&#xff0c;有硬盘写入内存就是输入。可以总结为&#xff…

OpenHarmony 3.2 Release版本实战开发——Codec HDI适配过程

简介 OpenHarmony Codec HDI&#xff08;Hardware Device Interface&#xff09;驱动框架基于 OpenMax 实现了视屏硬件编解码驱动&#xff0c;提供 Codec 基础能力接口供上层媒体服务调用&#xff0c;包括获取组件编解码能力、创建组件、参数设置、数据的轮转和控制、以及销毁…

C++反汇编,指针和内存分配细节,面试题05

文章目录 20. 指针 vs 引用21. new vs malloc 20. 指针 vs 引用 指针是实体&#xff0c;占用内存空间&#xff0c;逻辑上独立&#xff1b;引用是别名&#xff0c;与变量共享内存空间&#xff0c;逻辑上不独立。指针定义时可以不初始化&#xff1b;引用定义时必须初始化。指针的…

Cmake编译源代码生成库文件以及使用

在项目实战中&#xff0c;通过模块化设计能够使整个工程更加简洁明了。简单的示例如下&#xff1a; 1、项目结构 project_folder/├── CMakeLists.txt├── src/│ ├── my_library.cpp│ └── my_library.h└── app/└── main.cpp2、CMakeList文件 # CMake …

刷题记录2

文章目录 刷题记录21047.删除字符串中的所有相邻重复项150.逆波兰表达式求值239.滑动窗口最大值347.前k个高频元素144.二叉树前序遍历(145、94后序、中序)102.二叉树的层序遍历226.翻转二叉树101.对称二叉树104.二叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数 …