贪吃蛇设计详解

news2024/11/17 15:43:08

在去年12月中,初次接触c语言,我靠着为数不多的知识,使用数组仿照写了一份贪吃蛇,现在时隔5个月,我已经有能力独立写出真正的贪吃蛇而不是简单的仿照(虽然写的是挺简单的)。

那么我们现在就正式开始今天的主题,贪吃蛇设计:

前置知识:

这一次的知识跨度有点大,介绍了不少新的内容才能完成贪吃蛇的设计,让我们先来看看前置知识:

控制台程序:

我们需要包含头文件<windows.h>

首先就来讲讲控制台的指令

cmd指令:

平常我们运⾏起来的⿊框程序其实就是控制台程序
我们可以使⽤cmd命令来设置控制台窗⼝的⻓宽:设置控制台窗⼝的大小。
cmd指令写法为:
system(" mode con cols= 100 lines= 30 ")
cols为列,lines为行,即将窗口的大小设置为30行100列。

title指令:

使用title指令修改窗口名字
写法为:
system("title 贪吃蛇")
将窗口名字修改为贪吃蛇。

cls指令:

写法为:
system("cls")
用处为:清屏
pause指令
写法为:
system("pause");
用处为:按下任意键才能指向下一步操作

句柄:

句柄可以理解为一个可以操作其他设备的东西。

GetStdHandle函数:

GetStdHandle是⼀个Windows API函数。
它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标
准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
写法为:
HANDLE GetStdHandle (DWORD nStdHandle);
其中HANDLE为句柄的类型名, DWORD为需要获取的设备
例如:
HANDLE hOutput = NULL ;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
STD_OUTPUT_HANDLE即为输出设备,可以理解为窗口。

GetConsoleCursorInfo函数:

该函数的用处为检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息。

该函数的形式为:

BOOL WINAPI GetConsoleCursorInfo (
HANDLE hConsoleOutput,
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
第一个参数为句柄,第二个参数为指向 CONSOLE_CURSOR_INFO 类型变量的指针

CONSOLE_CURSOR_INFO为存放光标数据的结构体

形式为:
typedef struct _ CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
dwSize,由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完
全填充单元格到单元底部的⽔平线条。
bVisible,游标的可见性。 如果光标可见,则此成员为 TRUE。
由此,我们便可以写出:
HANDLE hOutput = NULL ;
// 获取标准输出的句柄 ( ⽤来标识不同设备的数值 )
hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo (hOutput, &CursorInfo); // 获取控制台光标信息
而将数据传递给光标,我们传递的也是句柄和结构体。
句柄用于找到设备,结构体用于传递信息。
我们需要用到下面一个函数:

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函数

用于改变光标位置

COORD
COORD 是Windows API中定义的⼀个结构体,表⽰⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系 (0,0) 的原点位于缓冲区的顶部左侧单元格。
左侧参数为x坐标,右侧参数为y坐标。
从左上角开始,从左向右x坐标逐渐增大
从上到下y坐标逐渐增大
形式:
typedef struct _ COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;
set函数形式:
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函数(自己创建)

为了方便修改光标位置,我们可以自己写一个名为setpos的函数。
该函数的参数为改后光标的x,y轴坐标。
步骤可分为:
1.获取句柄
2.创建COORD变量赋值为{x,y}
3.将句柄和创建好的COORD变量一起传递给 SetConsoleCursorPosition函数 进行修改即可。
示例:
void SetPos ( short x, short y)
{
COORD pos = { x, y };
HANDLE hOutput = NULL ;
// 获取标准输出的句柄 ( ⽤来标识不同设备的数值 )
hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
// 设置标准输出上光标的位置为 pos
SetConsoleCursorPosition (hOutput, pos);
}

按键判断函数GetAsyncKeyState

在贪吃蛇中最重要的内容就是按键判断,通过按键来执行操作。

GetAsyncKeyState原型如下:
SHORT GetAsyncKeyState (
int vKey
);
这个函数我们尽管调用就好了,因为他的作用为:
将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果
返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬 起;如果最低位被置为1则说明,该按键被按过,否则为0。
换句话说,我们只需要检测 GetAsyncKeyState函数 的的最高位或最低位即可。
我们可以进行宏定义检测函数返回值的最低值即可:
# define pdVK(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
将返回值与1进行与操作,其他位置都改为0,如果最低位为1则为真,为0则为假。
其实我们不需要使用双目操作符进行后面的判断,因为他的值只有1和0两种
写成#define pdVK(VK) ((GetAsyncKeyState(VK)&1))
同样可以完成目的。

宽字符:

在游戏地图上,我们打印墙体使⽤宽字符:□,打印蛇使⽤宽字符●,打印⻝物使⽤宽字符★
普通的字符是占⼀个字节的,这类宽字符是占⽤2个字节。
同时使用这类宽字符还有一定要求

<locale.h>本地化

<locale.h>提供的函数⽤于控制C标准库中对于不同的地区会产⽣不⼀样⾏为的部分。
在标准中,依赖地区的部分有以下⼏项:
数字量的格式
货币量的格式
字符集
⽇期和时间的表⽰形式
我们使用的这些字符同样包括在内,所以需要对C标准库进行一点修改。
我们这里不做过多解释,直接说主要内容:

setlocale函数

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

setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。
setlocale 的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参 数是LC_ALL,就会影响所有的类项。
C标准给第⼆个参数仅定义了2种可能取值: "C" (正常模式)和 "" (本地模式)。
切记,本地模式的""内部是空的,没有任何字符。
通过 setlocale (LC_ALL, "" );
我们就可以实现使用汉字和打印某些特殊字符的操作。

宽字符的打印:

宽字符的字⾯量必须加上前缀“L”,否则 C 语⾔会把字⾯量当作窄字符类型处理。前缀“L”在单引
号前⾯,表⽰宽字符,对应 wprintf() 的占位符为 %lc ;在双引号前⾯,表⽰宽字符串,对应
wprintf() 的占位符为 %ls
例如:
setlocale (LC_ALL, "" );
wchar_t ch1 = L' ';
wprintf ( L"%lc\n" , ch1);

程序撰写:


OK,前置知识学习完之后我们就可以进行贪吃蛇的撰写了。

首先我们先理清楚思路

游戏进行过程如下:

1.跳出两张图片提示游戏开始和按键操作

2.第三张图分为框内框外,框的外侧印着分数。

3.框内侧为小蛇和食物

4.小蛇可以通过各种按键进行操控

5.小蛇吃掉食物后会长一节,食物会再次刷新。

大致内容分为以上五部分

我们先来看下函数的头文件

头文件:

col为列数,line为行数

我们将wall,snakebody定义为墙和蛇身,方便后面的书写。

sit为situation的缩写,意味小蛇此时的状态

dir为direction的缩写,意味小蛇此时的方向

我们在定义一个结构体类型snakenode意味蛇节点。

每个节点都有他的左边和下一个节点,蛇身采用的是链表的形式。

使用typedef将蛇节点结构体改名为snakenode,该结构提的指针为psnakenode。

然后我们再写一个蛇结构体,里面存放蛇的各种数据,包括蛇的状态,头结点,单个食物的分值,当前食物的位置,小蛇的方向,总分数和休眠时间(即蛇的速度),同样进行改名操作。

然后下面的函数简单进行声明,我们后面进行介绍。

主函数:

就只有两个内容,一个为切换到本地模式,一个为游戏开始。

函数编写:

首先对随机数进行修改,保证每次游戏都是不同的情况。

然后我们打印菜单栏(即两张图)

菜单:

前面提到过的将光标状态切换为不可见

将窗口大小设置为40行100列

然后找到位置打印文字“欢迎来到贪吃蛇小游戏”

将光标切换到下一行防止接到原文字之后。

文字显示完,按下任意键之后,清屏。

重复同样的操作打印游戏按键即可。

打印墙:

传入两个参数对应行和列

将上下左右四个方向分别打印上墙即可

注意:一个宽字符对应两个普通字符,所以打印最右侧时,需要将x坐标设置为2*(列数-1)

初始化蛇:

我们现将蛇变量创建出来,然后在编写函数用来初始化蛇

传递的为蛇指针

将各项值设置好即可。

需要注意的是我们要给食物指针专门开辟一块空间用来存放食物的,与蛇节点使同一个结构体

创建蛇:

使用链表的方式将蛇节点一个一个穿上即可

创建一个新的节点指针cur。

我们给蛇身创建5个长度即可。

每一个节点都单独开辟一块空间将指针传递给cur,cur的下一个节点指向头指针,将头指针指向cur即可实现增加一个节点,即从0开始的头插。至于设置位置这项操作在头插前还是后进行都没关系。只需要注意宽字符占2个普通字符宽度即可。

最后在每次循环插完节点之后在窗口上打印蛇身即可。

创建食物:

使用goto语句,随机到的节点如果在墙上或者在奇数位置的x上就重新随机,随机完之后再和蛇身的每一个节点进行比较,如果该点在蛇身上那么就重新上面的操作。

取到的位置合适就将蛇结构体中食物位置这一项修改为对应位置即可,在窗口上打印食物。

按键判断:

进入循环,循环退出条件为蛇不再正常。

在墙之外打印上我们的分数以及当前单个食物的分数

休眠时间也是存在蛇结构体中的。时间越长,蛇的速度越快。

在前面我们已经介绍过可以使用

#define pdVK(VK) ((GetAsyncKeyState(VK)&1))

来快速判断按键是否被按下,可以节省打字时间。

方向

如果按键方向不为蛇运动的反方向

则将蛇结构体的方向进行修改

加减速与暂停

加减速不能无上限的加速减速,我们给他设定一个范围,

在这个范围内每次加速可以增加2点食物分值,减速则减少两点,将休眠时间进行相应的增加与减少即可

如果我们按下空格(SPACE),那么就要进行暂停

stop函数很简单,死循环的进行判断即可,如果空格(SPACE)被再次按下即退出循环。

蛇的移动:

最后的最后就是我们的重中之重,蛇的运动了

经过前面的积累,蛇的移动已经显而易见了

创建下一个节点作为新的头结点

新节点为蛇头当前位置加上运动的方向。

修改完新节点后,我们还要进行判断(没错,还有)

如果新节点为食物,就进行吃食物操作

如果不是食物,就进行非食物操作

吃食物与不吃食物

传递新节点与蛇指针。

如果吃食物

那么就将新节点修改为新的头,在新节点的位置打印上蛇身,加个分,然后再创建一个新的食物即可。

如果不吃食物

新节点同样改为头结点,找到倒数第二个节点,通过倒数第二个节点先将最后一个节点的位置修改为'  '(宽字符,两个' '),释放掉最后一个节点的内存,将倒数第二个节点的下一个节点置为空,那么原倒数第二个节点就成为了现在的最后一个节点。

到这里为止,大部分内容都已完成,只剩下小蛇吃到自己与撞墙死的判断了。

在小蛇移动后进行判断

撞墙死

很简单,判断蛇头是否在墙的位置,是的话将小蛇状态改为撞墙死,退出循环,否则继续寻找下一个节点,直到全部节点都遍历过。

吃到自己

从蛇头的下一个节点开始比较,如果某个节点和蛇头位置撞了则将蛇的状态修改为吃到自己,退出循环。

游戏结束

小蛇撞到墙或者吃到自己则会导致游戏结束

将光标移动到中间某个位置,打印最终的分数

打印完之后将光标移动到下方避免程序结束出现的文字截断掉贪吃蛇的画面即可

到这里,游戏已经设计完成了,让我们看下最后的效果

效果展示:

ok,文章到这里就结束了,看在博主辛辛苦苦码了这么多字的情况下点个免费的赞吧,球球了(噗通一声倒地不起)

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

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

相关文章

在ComfyUI中使用Deforum简单步骤, 以及报错处理

⛳背景 deforum这个插件其实去年就在webui流行的时候火过一阵子&#xff0c;效果的话&#xff0c;因为并没有引入太多“时间”的概念&#xff0c;所以画面基本上每一帧都不一样&#xff0c;但也恰恰因为这个&#xff0c;所以可以产生很多宛若吃了毒蘑菇的视频&#xff0c;后来…

Rokid AR Lite空间计算套装发布,软硬件全面升级推动居家、出行、户外场景大规模应用

4月20日&#xff0c;以“好玩、好看、好上头”为主题的Rokid Open Day 2024发布会在杭州举行&#xff0c;Rokid对外正式发布新一代AR Lite空间计算套装&#xff0c;分享了近期Rokid在AR开发者生态和数字文化领域的进展和成果&#xff0c;并宣布了多项跨行业重磅合作。作为中国代…

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

OerOerlikonTCO1200欧瑞康LPCVD system操作使用说明

javaWeb项目-智能仓储系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JSP技术 JSP(Jav…

MySQL 列数据跨表拷贝,一句SQL快速将表A每条记录的某些字段拷贝到表B每条记录的某些字段(A、B表通过ID等字段对应)

文章目录 MySQL 列数据跨表拷贝&#xff0c;一句SQL快速将表A每条记录的某些字段拷贝到表B每条记录的某些字段&#xff08;A、B表通过ID等字段对应&#xff09;背景定义表填充测试数据跨表一 一对应拷贝列数据SQL参考资料 MySQL 列数据跨表拷贝&#xff0c;一句SQL快速将表A每条…

OSPF动态路由实验(思科)

华为设备参考&#xff1a;OSPF动态路由实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 OSPF&#xff08;Open Shortest Path First&#xff09;是一种内部网关协议&#xff0c;主要用于在单一自治系统内决策路由。它是一种基于链路状态的路由协议&#xff0c;通过…

漆包线行业你了解多少?专业漆包线行业MES生产管理系统

今天就说说漆包线行业&#xff0c;漆包线是工业电机&#xff08;包括电动机和发电机&#xff09;、变压器、电工仪表、电力及电子元器件、电动工具、家用电器、汽车电器等用来绕制电磁线圈的主要材料。 漆包线上游是铜杆行业&#xff0c;下游是各种消费终端&#xff0c;主要是电…

详解数据在内存中的存储

系列文章目录 第一章 C语言基础知识 第二章 C语言控制语句 第三章 C语言函数详解 第四章 C语言数组详解 第五章 C语言操作符详解 第六章 C语言指针详解 第七章 C语言结构体详解 文章目录 1. 数据类型 1.1 基本数据类型 1.2 派生数据类型 2. 整形在内存中的存储 2.1 …

力扣练习题(2024/4/18)

1不相交的线 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足&#xff1a; nums1[i] nums2[j]且绘制的直线不与任何其他连线&#xff08;非水平线…

kaggle 房价预测 得分0.53492

流程 导入需要的包引入文件,查看内容数据处理调用模型准备训练输出结果 导入需要的包 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.linear_model i…

Pandas介绍与Series创建

1.Pandas介绍 Pandas 是基于 NumPy 的一种工具&#xff0c;该工具是为解决数据分析任务而创建的&#xff0c;Pandas 提供了大量能使我们快速便捷地处理数据的功能 Pandas 与出色的 Jupyter 工具包和其他库相结合&#xff0c;Python 中用于进行数据分析的环境在性能、生产率和协…

【介绍下WebStorm开发插件】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

稀碎从零算法笔记Day53-LeetCode:不同路径 II

稀碎系列有点更不动(更多是自己懈怠了) 题型&#xff1a;矩阵、模拟 链接&#xff1a;63. 不同路径 II - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &…

Emerald AI 2024

使用易于使用的编辑器和大量内置功能,快速创建高质量的人工智能。 Emerald AI 2024是一个完全重写和重新设计的通用人工智能框架,适用于各种人工智能和游戏类型。它的多组件设计使开发人员能够灵活地只使用他们需要的功能,并允许有组织和可管理的工作流程。Emerald AI经过了…

【介绍下LeetCode的使用方法】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

OpenHarmony其他工具类—libharu [GN编译]

简介 libharu主要用于生成 PDF格式文件。 下载安装 直接在OpenHarmony-SIG仓中搜索libharu并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 库代码存放路径&#xff1a;./third_party/libharu 修改添加依赖的编译脚本&#xff0c;路径&#xff1a;/developtools…

OpenHarmony南向开发案例:【智能中控屏】

样例简介 本Demo是基于Hi3516开发板&#xff0c;使用开源OpenHarmony开发的应用。通过控制面板可以控制同一局域网内的空调&#xff0c;窗帘&#xff0c;灯等智能家居设备。 当前支持的配套L0设备只有[智能灯]&#xff0c;如需添加新的设备。 应用运行效果图&#xff1a; 样…

nginx--Nginx转发真实的IP

Nginx转发真实的IP 前言给nginx.conf 设置proxy_set_headerjava 程序里获取 前言 在使用nginx的时候可能会遇到判断是不是本机在做操作&#xff0c;这样的话web端我们是可以通过ip和端口进行远程连接的这样的话我们就需要从后端获取到真实ip来判断是不是指定的机器了&#xff…

PS-ZB转座子分析流程2-重新分析并总结

数据处理 数据质控 随机挑出九个序列进行比对&#xff0c;结果如下&#xff1a; 所有序列前面的部分序列均完全相同&#xff0c;怀疑是插入的转座子序列&#xff0c;再随机挑选9个序列进行比对&#xff0c;结果如下&#xff1a; 结果相同&#xff0c;使用cutadapt将该段序列修…

【C语言】贪吃蛇项目(2)- 实现代码详解

文章目录 前言一、游戏开始界面设计首先 - 打印环境界面其次 - 游戏地图、蛇身及食物的设计1、地图2、蛇身设置及打印3、食物 二、游戏运行环节蛇的上下左右移动等功能蛇的移动 三、结束游戏代码 前言 在笔者的前一篇博客中详细记载了贪吃蛇项目所需的一些必备知识以及我们进行…