c语言利用控制台实现贪吃蛇

使用控制台实现贪吃蛇需要的技能加点:

控制台设置(包含于stdlib.h):

定义命令行窗口高/宽:
system("mode con cols=100 lines=30");

        system() 函数是一个C标准库函数,它允许程序执行操作系统命令。
        mode 是命令的关键字,代表“模式”,用于改变系统设备的配置。
        con 是“console”的缩写,指代命令行界面或控制台窗口。
        cols=100 设置了窗口的列数(宽度)为100个字符。
        lines=30 设置了窗口的行数(高度)为30行。
        长宽(二倍关系);
        合起来为改变控制台(命令行)窗口的配置:高30 宽100.

设置标题:
system("title 贪吃蛇");

        在程序运行结束前设定标题为贪吃蛇;
        在程序结束后标题恢复为默认状态。

控制台窗口坐标:

                                                  坐标图(x轴俩个单位长度等于y轴一个单位)

使用windows.h头文件可以使用该结构体,该结构体有俩个成员:

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

    通过X,Y可以确定一个控制台上的一个位置,后面会用它来调整光标位置。


    光标

获取/使用句柄(控制台句柄):

        获取句柄

        句柄可以理解为一个中介,通过中介可以操纵使用中介手里的资源。例如你需要找个兼职,但是不知道怎么做才能兼职,于是你找了一个地区的兼职中介,你将需求告诉了中介,最后中介帮你搞定了找兼职的事,这个中介只管他所在地区的资源。
        在这里你需要隐藏掉控制台的光标,毕竟我们不需要在贪吃蛇显示光标。

//获取当前控制台界面的句柄
HANDLE houtput = NULL;
//定义结构体用来接收存放句柄;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);

        GetStdHandle()是Windows API 提供的函数,参数为标准设备(标准输入、标准输出、标准错误),返回值为对应句柄
        STD_OUTPUT_HANDLE 表示标准输出设备(当前控制台)。

        使用句柄

        我们可以通过这个句柄对当前的控制台进行一些操作,这里我们先来一个获取光标信息的操作:

//首先定义一个光标信息的结构体
CONSOLE_CURSOR_INFO cursor_info = {0};

        该结构体是Windows API中用于描述控制台光标属性的数据结构,它包含以下两个成员:

typedef struct {DWORD dwSize;BOOL  bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

关键词解释:

        dwSize:这是一个DWORD类型的变量,表示光标的大小。这里的“大小”并不是指光标的物理尺寸,而是指光标所覆盖的字符单元的百分比。例如,如果设置为50,则光标将占据半个字符单元的高度。此值必须在1到100之间;
        DWORD类型是Windows API中定义的一种数据类型,全称为Double Word,表示一个32位的无符号整数。

        bVisible:这是一个BOOL类型的变量,指示光标是否可见。如果bVisible为TRUE,则光标可见;如果为FALSE,则光标不可见。


下面演示一下获取句柄->通过该句柄得到光标数据->打印出光标数据

        //获得标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定义一个光标信息的结构体CONSOLE_CURSOR_INFO cursor_info = {0};//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中GetConsoleCursorInfo(houtput, &cursor_info);//打印当前控制台的光标大小,光标隐藏情况printf("%u, %d", cursor_info.dwSize, cursor_info.bVisible);

        除了得到句柄,我们也可以定义一个光标属性的结构体,设定好里面的参数,然后将他交给句柄来改变光标属性:
        

        //定义一个光标信息的结构体CONSOLE_CURSOR_INFO cursor_info = {0};//设定光标显示:否cursor_info.bVisible = false;//像前面一样,获得当前标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//设置控制台上的光标信息(通过刚刚获得的句柄,SetConsoleCursorInfo通过句柄可以知道更改的是哪个窗口SetConsoleCursorInfo(houtput, &cursor_info);//暂停程序以便观察system("pause");观察发现光标不见了(不显示)

    改变光标位置(实现在控制台不同位置打印文本,而不是默认的从左到右、从上到下):

        获得当前标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);定义并初始化一个窗口坐标结构体,参数为横纵坐标:COORD pos = { 10, 20 };使用光标位置调整函数(参数为句柄和窗口坐标结构体)SetConsoleCursorPosition(houtput, pos);测试光标位置printf("10,20位置的光标在这里");

检测按键:

        在游戏中,我们需要通过上下左右控制蛇的方向,所以我们还需要一个检测按键的方法:

        以下举例为检测数字5是否被按过:

short ret = GetAsyncKeyState(0x35);
if ((ret & 1) == 1)//这里使用了位与运算符&来检查ret的最低位(第0位)是否为1printf("5被按过\n");elseprintf("没有被按过\n");

        这里用到了GetAsyncKeyState函数:这是Windows API中的一个函数,用于检查指定虚拟键的当前状态。它接收一个虚拟键码作为参数,返回一个短整型(short)值,该值反映了按键的"状态"包括"是否被按下"。虚拟键码0x35对应于键盘上的数字键"5"。        

        这段代码调用了GetAsyncKeyState函数,传入数字键"5"的虚拟键码,获取其状态并存储在变量ret中

        由于我们此次项目只检测按键是否被按过这一状态,不在乎按键的其他状态(如是否为持续按住),所以我们只会用到ret的最后一位数字,该数字为1表示按过,为0表示没按过。     
        我们可以用做一个宏用来检测某键是否被按过

 #define KEY_PRESS(vk)  ((GetAsyncKeyState(vk)&1)?1:0)

        参数为虚拟键码vk。
        虚拟键码表可以自行网上搜索

本地化:

        有一些特殊的字符需要俩个字节的编码来表示,而使用这些字符需要设置一个本地化:由于世界不同地区的文字差异,时间格式差异,符号差异,货币单位差异...,不同地区有不同的双字节编码方式(同样的编码可能表示不同的字符)。

        以下为查询当前程序的本地化设置。

#include <locale.h>//我们要用的setlocale函数在这个头文件        char* ret = setlocale(LC_ALL, NULL);printf("%s\n", ret);//打印出当前的本地化设置名称。

        调用setlocale函数,参数LC_ALL是一个宏,代表所有类别,用它的意思是对所有的地区性的东西动手。第二个参数为NULL时,NULL表示不修改地区性的东西。setlocale会返回修改后的本地化设置名称(返回的设置名称被存储在ret指向的字符数组中,随后通过printf打印出来。)

        以下为改变当前程序的本地化设置

    ret = setlocale(LC_ALL, "");printf("%s\n", ret);//再次打印出本地化设置名称。

        调用setlocale函数,这次第二个参数是空字符串""。当使用空字符串作为参数时,setlocale会尝试根据环境变量(如LC_ALL, LANG, LC_CTYPE等)来设置本地化信息,通常会选择用户或系统的默认本地化设置。

        再次打印出本地化设置名称,这次是在尝试应用用户默认设置后得到的结果。如果用户的默认设置与之前的查询结果不同,这里应该能看到变化。

        我们先尝试一下本地化后的汉字打印,以及本地的特殊符号打印:

//设置本地化setlocale(LC_ALL, "");//定义一个字符变量 ,由于该变量占俩个字节,所以叫做宽字符,宽字符的变量类型为wchar_t,赋值的变量前面加上L来说明该字符为宽字符,防止程序将其误会为普通的char类型字符wchar_t a = L'本';wchar_t b = L'地';wprintf(L"%lc\n", wc1);wprintf(L"%lc\n", wc2);wprintf(L"%lc\n", L'●');wprintf(L"%lc\n", L'★');

        打印可以看到宽字符的宽度是普通字符的俩倍。

单链表和结构体知识:

        蛇的身体我们通过单链表来维护。

贪吃蛇游戏实现:

适配本地环境,设定随机数"起点"  

//设置适配本地环境setlocale(LC_ALL, "");srand((unsigned int)time(NULL));

        我们生成食物需要用到随机数。

初始化游戏:

    1. 打印开始界面(欢迎界面,下一步后记得清屏)

        通过控制控制台坐标来调整光标位置,再打印文字来实现欢迎界面打印

system("cls")//下一步进入操作介绍前记得清屏


    2. 功能介绍

            介绍游戏的操作方式,如何控制移动方向,设置速度,实现方式和上一步同理
    3. 绘制地图

            打印一个墙体,墙用方格子表示,方格子是宽字符,需设置本地化
    4. 创建蛇

            本质是创建一个链表,然后打印出来
    5. 创建食物

            在随机的坐标生成食物,本质为创建一个不和蛇相交的结点并打印

            注意食物的坐标横坐标应该为偶数
    6. 设置游戏的相关信息(开局蛇的方向,分数,食物分数,蛇速,蛇状态为存活)

            创建一个结构体来维护这些信息

运行游戏:

    1.显示打印当前分数和食物的分值
    2.用if else检测刚刚的按键情况并执行相应任务,改变方向、退出、加速、减速、暂停
    3.结算蛇走一步
        根据结算决定是否进行下一个循环:
        啥事没有->继续:蛇身链表头增,尾删实现蛇移动一格
        撞自己->结束 :蛇头遍历蛇身体存在相同坐标,此时代表撞了自己,设置蛇状态为撞自己并结束游戏。
        撞墙->结束:蛇头遍历墙体坐标存在相同坐标,此时代表撞了墙,设置蛇状态为撞墙并结束游戏。
        吃了食物->继续:蛇头坐标与食物坐标相同,蛇身链表不尾删,只头增,同时创建一个新食物,同初始化游戏第五条。
    4.程序休息一点点时间(模拟蛇的速度)

Sleep(time);

结束游戏:

    1.打印结束原因(你撞墙了,你撞自己了...)
    2.释放蛇链表内存
    3.询问是否再来一盘

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

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

相关文章

(九) 盘古UI,日期和时间选择控件,自定义多种场景!

(九) 盘古UI,日期和时间选择控件,自定义多种场景! 盘古UI,较为全面的自定义UI框架,帮助你绝对的快速开发!(长期维护中) 控件位置: 主要控件: com.smart.pangu_ui_lib.widget.PanguSelectDateView 内部使用的时间弹窗:pop: com.smart.pangu_ui_lib.pop.PopSelectDate demo地址…

nginx反向代理.NetCore开发的基于WebApi创建的gRPC服务

一、本文中使用的工具: Vs2022使用.NET 8.0开发基于ASP.NET Core WebApi的gRPC服务; Nginx:1.25.5,下载地址:http://nginx.org/en/download.html 二、gRPC介绍: 由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。在vs2022中可以直接创建gRP…

设计模式之模板方法模式详解(下)

3&#xff09;钩子方法的使用 1.概述 钩子方法的引入使得子类可以控制父类的行为。 2.结构图 3.代码实现 将公共方法和框架代码放在抽象父类中 abstract class DataViewer {//抽象方法&#xff1a;获取数据public abstract void GetData();//具体方法&#xff1a;转换数据…

【JAVA面试题】探索多线程同步:ReentrantLock与synchronized的对比解析

程序员如何搞副业&#xff1f; 文章目录 程序员如何搞副业&#xff1f;强烈推荐引言&#xff1a;ReentrantLock介绍可重入性&#xff08;Reentrancy&#xff09;&#xff1a;公平性&#xff08;Fairness&#xff09;&#xff1a;条件变量&#xff08;Condition&#xff09;&…

C语言基础(入门综合案例)

学生信息管理系统 学员管理系统可以实现对学员的添加、全部显示、查询、修改、删除功能 数据存储格式说明 // 宏定义的常量&#xff0c;代表学生的最大个数 #define NUM 100// 结构体类型 struct stu 别名为 STU typedef struct stu {char name[30]; // 姓名int age; …

海外代理IP|Facebook对IP都有哪些要求?要选哪种?

众所周知&#xff0c;Facebook封号大多数情况都是因为IP的原因。Facebook对于用户账号有严格的IP要求和限制&#xff0c;以维护平台的稳定性和安全性。在这种背景下&#xff0c;海外IP代理成为了一种有效的解决方案&#xff0c;帮助用户避免检测&#xff0c;更加快捷安全地进行…

影响钕铁硼磁钢性能的因素及方法

钕铁硼永磁材料自问世以来&#xff0c;就以其优越的磁性能而备受关注&#xff0c;被称为“磁王“&#xff0c;在市场需求的不断地增长下&#xff0c;钕铁硼生产工艺及磁体性能也不断发展和提升。我们一般用剩磁、矫顽力和最大磁能积这几个指标来衡量磁性材料的磁性能。 剩磁 B…

C语言数据结构之链表

目录 前言 \color{maroon}{前言} 前言1.链表的概念及结构2.链表的分类3.无头单向非循环链表的实现4.带头双向循环链表的实现5.顺序表和链表的对比 前言 \color{maroon}{前言} 前言 在上一篇博客中我们提到&#xff0c;线性表包括顺序表和链表&#xff0c;顺序表在上篇博客中已…

力扣HOT100 - 25. K 个一组翻转链表

解题思路&#xff1a; class Solution {public ListNode reverseKGroup(ListNode head, int k) {ListNode dum new ListNode(0, head);ListNode pre dum;ListNode end dum;while (end.next ! null) {for (int i 0; i < k && end ! null; i) {end end.next;}if …

学习笔记-数据结构-线性表(2024-04-17)

设计一个算法实现在单链表中删除值相同的多余节点的算法。 设计思想&#xff1a;双指针 变量说明&#xff1a; head - 参数变量&#xff0c;代表链表的头节点。在调用DelSameNum函数时&#xff0c;需要传递链表的头节点的地址给这个参数&#xff0c;从而允许函数对链表进行操作…

类和对象(中)(构造函数、析构函数和拷贝构造函数)

1.类的六个默认成员函数 任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 //空类 class Date{}; 默认成员函数&#xff1a;用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数 2.构造函数 构造函数 是一个 特殊的成员函数&a…

docker容器技术篇:centos7搭建docker swarm集群

centos7搭建docker swarm集群 一 docker swarm 概述 1.1 swarm简介 Docker Swarm是 Docker 的集群管理工具&#xff0c;Swarm 在 Docker 1.12 版本之前属于一个独立的项目&#xff1b;其主要作用是把Docker集群抽象为一个整体&#xff0c;并且通过一个统一管理这些 Docker 主…

密码学 | 数字证书:应用

&#x1f951;原文&#xff1a;数字签名和数字证书的原理解读 - 知乎 &#x1f951;前文&#xff1a;密码学 | 数字签名 数字证书 - CSDN &#x1f951;提示&#xff1a;把客户端想成 Alice&#xff0c;服务器端想成 Bob 即可。客户端实际上指的是客户端浏览器。 下面&#…

前端入门:HTML(CSS边框综合案例)

案例&#xff1a; 源代码&#xff1a; css-borders.html: <body> <div id"square"> </div> <br> <div id"triangle"> </div> <br> <div id"trapezium"> </div> <br> <div id…

【C语言】指针篇-深入探索数组名和指针数组(2/5)- 必读指南

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章目录 认识指针与数组之间的关系(涉及二级指针)**数组名****指针访问…

面试后,公司如何决定你的去留

在现代职场中&#xff0c;求职者在经历了一系列严格的面试流程后&#xff0c;往往会进入一段等待期。在这段时间里&#xff0c;他们满怀希望地等待企业的最终反馈。但有一个现象普遍存在&#xff1a;无论面试过程如何&#xff0c;最终决定权总是掌握在公司手中&#xff0c;由公…

企业常用Linux三剑客awk及案例/awk底层剖析/淘宝网cdn缓存对象分级存储策略案例/磁盘知识/awk统计与计算-7055字

高薪思维&#xff1a; 不愿意做的事情:加班&#xff0c;先例自己在利他 生活中先利他人在利自己 感恩&#xff0c;假设别人帮助过你&#xff0c;先帮助别人&#xff0c;感恩境界 awk三剑客老大 find其实也算是一种新的第四剑客 find 查找文件 查找文件&#xff0c;与其他命令…

推荐实用网站——算法可视化

网站链接 https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

variant

class RTTR_API variant 对github项目rttr&#xff08;C反射库&#xff09;解析&#xff0c;链接&#xff1a;https://github.com/rttrorg/rttr namespace rttr { class variant_associative_view; class variant_sequential_view; class type; class variant; class argumen…

真实世界的密码学(四)

原文&#xff1a;annas-archive.org/md5/655c944001312f47533514408a1a919a 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十六章&#xff1a;加密何时何地失败 本章涵盖 使用加密时可能遇到的一般问题 遵循烘烤良好的加密的要点 加密从业者的危险和责任 问候…