贪吃蛇项目实践!(上)

大家好,今天我带着大家从0构建起贪吃蛇项目的高楼大厦~

要实现这个游戏,我们需要实现哪些功能呢?

实现基本的功能:
• 贪吃蛇地图绘制
• 蛇吃⻝物的功能(上、下、左、右⽅向键控制蛇的动作)
• 蛇撞墙死亡
• 蛇撞⾃⾝死亡
• 计算得分
• 蛇⾝加速、减速
• 暂停游戏

Win32API

调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程序达到开启
视窗、描绘图形、使⽤周边设备等⽬的。

控制台程序

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

cmd命令来设置控制台窗⼝的⻓宽:例如设置控制台窗口的大小为30行,100列。

mode con cols=100 lines=30

也可以设置控制台窗口的名字:

title 贪吃蛇

这些能在控制台窗⼝执⾏的命令,也可以调⽤C语⾔函数system来执⾏。例如:

#include <stdio.h>
int main() 
{system("mode con cols=100 lines=30");//设置cmd窗⼝名称system("title 贪吃蛇");return 0;
}

控制台屏幕上的坐标COORD

COORD是WindowsAPI中定义的⼀个结构体,表⽰⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系(0,0)。

COORD类型的声明

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

给坐标赋值

COORD pos = { 10, 15 };

GetStdHandle
 

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

HANDLE GetStdHandle(DWORD nStdHandle);

例子:

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

GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息
 

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;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

dwSize,由光标填充的字符单元格的百分⽐。此值介于1到100之间。光标外观会变化,范围从完
全填充单元格到单元底部的⽔平线条。
 bVisible,游标的可⻅性。如果光标可⻅,则此成员为TRUE。

CursorInfo.bVisible = false; //隐藏控制台光标

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类型的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);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}

GetAsyncKeyState

获取按键情况

SHORT GetAsyncKeyState(int vKey;
}

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

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


 

#include <stdio.h>
#include <windows.h>
int main()
{while (1){if (KEY_PRESS(0x30)){printf("0\n");}}
}

设计地图

窗⼝的坐标如下所⽰,横向的是X轴,从左向右依次增⻓,纵向是Y轴,从上到下依次增⻓。

 C语⾔的标准中不断加⼊了国际化的⽀持。⽐如:加⼊了宽字符的类型
wchar_t 和宽字符的输⼊和输出函数,加⼊了<locale.h>头⽂件,其中提供了允许程序员针对特定
地区(通常是国家或者说某种特定语⾔的地理区域)调整程序⾏为的函数。

<locale.h>本地化

类项

LC_COLLATE:影响字符串⽐较函数 strcoll() 和 strxfrm() 。
• LC_CTYPE:影响字符处理函数的⾏为。
• LC_MONETARY:影响货币格式。
• LC_NUMERIC:影响 printf() 的数字格式。
• LC_TIME:影响时间格式 strftime() 和 wcsftime() 。
• LC_ALL:针对所有类项修改,将以上所有类别设置为给定的语⾔环境。

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

C标准给第⼆个参数仅定义了2种可能取值:"C"(正常模式)和" "(本地模式)。

比如切换为本地模式:

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

宽字符的打印

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

#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"%lc\n", ch1);wprintf(L"%lc\n", ch2);wprintf(L"%lc\n", ch3);wprintf(L"%lc\n", ch4);return 0;
}

地图坐标

我们假设实现⼀个棋盘27⾏,58列的棋盘(⾏和列可以根据⾃⼰的情况修改),再围绕地图画出墙

蛇⾝和⻝物


初始化状态,假设蛇的⻓度是5,蛇⾝的每个节点是●,在固定的⼀个坐标处,⽐如(24,5)处开始出现
蛇,连续5个节点。
注意:蛇的每个节点的x坐标必须是2个倍数,否则可能会出现蛇的⼀个节点有⼀半⼉出现在墙体中,另外⼀般在墙外的现象,坐标不好对⻬。
关于⻝物,就是在墙体内随机⽣成⼀个坐标(x坐标必须是2的倍数),坐标不能和蛇的⾝体重合,然后打印★。

数据结构设计


在游戏运⾏的过程中,蛇每次吃⼀个⻝物,蛇的⾝体就会变⻓⼀节,如果我们使⽤链表存储蛇的信
息,那么蛇的每⼀节其实就是链表的每个节点。每个节点只要记录好蛇⾝节点在地图上的坐标就⾏,
所以蛇节点结构如下:
 

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

封装snake结构维护贪吃蛇

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//正常结束
};

游戏设计流程

核⼼逻辑实现分析

游戏主逻辑

设置程序⽀持本地模式,然后进⼊游戏的主逻辑

# define _CRT_SECURE_NO_WARNINGS 
#include <locale.h>
void test()
{int ch = 0;srand((unsigned int)time(NULL));//生成随机数do{Snake snake = { 0 };//创建结构体GameStart(&snake);GameRun(&snake);GameEnd(&snake);SetPos(20, 15);//设定光标位置printf("再来⼀局吗?(Y/N):");ch = getchar();//接收用户的输入值getchar();//清理屏幕} while (ch == 'Y');SetPos(0, 27);//重新设定光标位置
}
int main()
{//修改当前地区为本地模式,为了⽀持中⽂宽字符的打印setlocale(LC_ALL, "");//测试逻辑test();return 0;
}

游戏开始(GameStart)


这个模块完成游戏的初始化任务:
• 控制台窗⼝⼤⼩的设置
• 控制台窗⼝名字的设置
• ⿏标光标的隐藏
• 打印欢迎界⾯
• 创建地图
• 初始化第蛇
• 创建第⼀个⻝物

# define _CRT_DEFINE_NO_WARNINGS 
void GameStart(pSnake ps)
{//设置控制台窗⼝的⼤⼩,30⾏,100列//mode 为DOS命令system("mode con cols=100 lines=30");//设置cmd窗⼝名称system("title 贪吃蛇");//获取标准输出的句柄(⽤来标识不同设备的数值)HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//影藏光标操作CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态//打印欢迎界⾯WelcomeToGame();//打印地图CreateMap();//初始化蛇InitSnake(ps);//创造第⼀个⻝物CreateFood(ps);
}


打印欢迎界⾯

void WelcomeToGame()
{SetPos(40, 15);printf("欢迎来到贪吃蛇⼩游戏");SetPos(40, 25);//让按任意键继续的出现的位置好看点system("pause");system("cls");SetPos(25, 12);printf("⽤ ↑ . ↓ . ← . → 分别控制蛇的移动, F3为加速,F4为减速\n");SetPos(25, 13);printf("加速将能得到更⾼的分数。\n");SetPos(40, 25);//让按任意键继续的出现的位置好看点system("pause");system("cls");
}



创建地图
 

#define WALL L'□'

初始化蛇⾝

void InitSnake(pSnake ps)
{pSnakeNode cur = NULL;int i = 0;//创建蛇⾝节点,并初始化坐标//头插法for (i = 0; i < 5; i++){//创建蛇⾝的节点cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake()::malloc()");return;}//设置坐标cur->next = NULL;cur->x = POS_X + i * 2;cur->y = POS_Y;//头插法if (ps->_pSnake == NULL){ps->_pSnake = cur;}else{cur->next = ps->_pSnake;ps->_pSnake = cur;}}//打印蛇的⾝体cur = ps->_pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//初始化贪吃蛇数据ps->_SleepTime = 200;ps->_Socre = 0;ps->_Status = OK;ps->_Dir = RIGHT;ps->_foodWeight = 10;
}

创建第⼀个⻝物
 

先随机⽣成⻝物的坐标
◦ x坐标必须是2的倍数
◦ ⻝物的坐标不能和蛇⾝每个节点的坐标重复
• 创建⻝物节点,打印⻝物
 

#define FOOD L'★'
void CreateFood(pSnake ps)
{int x = 0;int y = 0;
again://产⽣的x坐标应该是2的倍数,这样才可能和蛇头坐标对⻬。do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);pSnakeNode cur = ps->_pSnake;//获取指向蛇头的指针//⻝物不能和蛇⾝冲突while (cur){if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode)); //创建⻝物if (pFood == NULL){perror("CreateFood::malloc()");return;else{pFood->x = x;pFood->y = y;SetPos(pFood->x, pFood->y);wprintf(L"%c", FOOD);ps->_pFood = pFood;}}

游戏运⾏

KEY_PRESS

检测按键状态,我们封装了⼀个宏

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

PrintHelpInfo
 

void PrintHelpInfo()
{//打印提⽰信息SetPos(64, 15);printf("不能穿墙,不能咬到⾃⼰\n");SetPos(64, 16);printf("⽤↑.↓.←.→分别控制蛇的移动.");SetPos(64, 17);printf("F3 为加速,F4 为减速\n");SetPos(64, 18);printf("ESC :退出游戏.space:暂停游戏.");
}

蛇⾝移动(SnakeMove)

void SnakeMove(pSnake ps)
{//创建下⼀个节点pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SnakeMove()::malloc()");return;}//确定下⼀个节点的坐标,下⼀个节点的坐标根据,蛇头的坐标和⽅向确定switch (ps->_Dir){case UP:{pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;}break;case DOWN:{pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;}break;case LEFT:{pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;}break;}//如果下⼀个位置就是⻝物if (NextIsFood(pNextNode, ps)){EatFood(pNextNode, ps);}else//如果没有⻝物{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps);
}

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

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

相关文章

matlab保存示波器数据

再重新运行一下示波器 然后就可以在工作区看见&#xff08;这里没有运行所以没有&#xff09; 将保存到文件夹中方便后续绘图

华为云FunctionGraph构建高可用系统的实践

导语 每年&#xff0c;网上都会报道XXX系统异常不可用&#xff0c;给客户带来巨大的经济损失。云服务的客户基数更大&#xff0c;一旦出现问题&#xff0c;都将给客户和服务自身带来极大影响。本文将基于华为云FunctionGraph自身的实践&#xff0c;详细介绍如何构建高可用的Se…

权威认证!瀚高股份IvorySQL通过强制性国标GB18030-2022最高级别认证

近日&#xff0c;GB 18030-2022《信息技术 中文编码字符集》应用推广大会暨“汉字守护计划”成果发布会在京召开。瀚高股份开源关系型数据库IvorySQL通过 GB 18030-2022《信息技术 中文编码字符集》强制性国家标准测试&#xff0c;达到最高实现级别&#xff08;3级&#xff09;…

基于springboot实现海滨学院班级回忆录的设计项目【项目源码+论文说明】计算机毕业设计

基于springboot实现海滨学院班级回忆录的设计演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了海滨学院班级回忆录的开发全过程。通过分析海滨学院班级回忆录管理的不足&#xff0c;创建了一个计算机管理海…

【Pytorch】(十五)模型部署:ONNX和ONNX Runtime

文章目录 &#xff08;十五&#xff09;模型部署&#xff1a;ONNX和ONNX RuntimeONNX 和 ONNX Runtime的关系将PyTorch模型导出为ONNX格式使用Netron可视化ONNX模型图检查ONNX模型验证ONNX Runtime推理结果使用ONNX Runtime运行超分模型 &#xff08;十五&#xff09;模型部署&…

第十五届蓝桥杯省赛第二场C/C++B组D题【前缀总分】题解(AC)

暴力解法 O ( 26 n 5 ) O(26n^5) O(26n5) 枚举将第 i i i 个字符串的第 j j j 个字符改为 c c c 的所有方案&#xff0c;时间复杂度 O ( 26 n 2 ) O(26n^2) O(26n2)&#xff0c;修改并计算总分&#xff0c; O ( n 3 ) O(n^3) O(n3)。 暴力优化 O ( 26 n 3 log ⁡ n ) O…

基于Python实现心脏病数据可视化DEA+预测【500010103.1】

一、数据说明 该心脏病数据集是通过组合 5 个已经独立可用但以前未合并的流行心脏病数据集来策划的。在这个数据集中&#xff0c;5 个心脏数据集结合了 11 个共同特征&#xff0c;使其成为迄今为止可用于研究目的的最大心脏病数据集。 该数据集由 1190 个实例和 11 个特征组成…

《第二行代码》第二版学习笔记(6)——内容提供器

文章目录 一 运行时权限2.权限分类3 运行时申请权限 二、内容提供器1、 ContentResolver的基本用法2、现有的内容提供器3、创建自己的内容提供器2.1 创建内容提供器的步骤2.2 跨程序数据共享 内容提供器&#xff08;Content Provider&#xff09;主要用于在不同的应用程序之间实…

Python | Leetcode Python题解之第52题N皇后II

题目&#xff1a; 题解&#xff1a; class Solution:def totalNQueens(self, n: int) -> int:def backtrack(row: int) -> int:if row n:return 1else:count 0for i in range(n):if i in columns or row - i in diagonal1 or row i in diagonal2:continuecolumns.add…

【VsCode】使用VsCode学习VUE+TS必备插件

目录标题 《Auto Close Tag》&#x1f495;《Auto Rename Tag》&#x1f495;《Path Intellisense》《Open in Browser》&#x1f495;《IntelliCode》《Vue-Official》&#x1f495;《Prettier - Code formatter》&#x1f495;《ESLint》&#x1f495; 《Auto Close Tag》&am…

Docker镜像的创建 和 Dockerfile

一. Docker 镜像的创建 创建镜像有三种方法&#xff0c;分别为基于已有镜像创建、基于本地模板创建以及基于 Dockerfile 创建。 1 基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改docker run -it --name web3 centos:7 /bin/bash …

maven修改默认编码格式为UTF-8

执行mvn -version查看maven版本信息发现&#xff0c;maven使用的编码格式为GBK。 为什么想到要修改编码格式呢&#xff1f;因为idea中我将文件格式统一设置为UTF-8&#xff08;如果不知道如何修改文件编码&#xff0c;可以参考文末&#xff09;&#xff0c;然后使用maven打包时…

docker 和 docker-compose的区别

Docker 和 Docker Compose 是两个相关但具有不同功能的工具&#xff0c;它们在容器化应用的生命周期管理中扮演不同的角色&#xff1a; Docker&#xff1a; Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者打包应用及其依赖包到一个可移植的容器中&#xff0c;这样…

ESP32与SD卡交互实现:文件读写实战与初始化详解及引脚定义

本代码实现ESP32与SD卡的交互&#xff0c;包括定义SPI引脚、创建自定义SPI类实例、编写WriteFile与ReadFile函数进行文件读写。setup函数初始化串口、SPI、SD卡&#xff0c;向“/test.txt”写入“myfirstmessage”&#xff0c;读取并打印其内容。loop函数留空待扩展。 1. 需要…

Lock-It for Mac(应用程序加密工具)

OSXBytes Lock-It for Mac是一款功能强大的应用程序加密工具&#xff0c;专为Mac用户设计。该软件具有多种功能&#xff0c;旨在保护用户的隐私和数据安全。 Lock-It for Mac v1.3.0激活版下载 首先&#xff0c;Lock-It for Mac能够完全隐藏应用程序&#xff0c;使其不易被他人…

PCV库之调用SIFT.py中process_image()执行错误的解决方案

背景介绍: windows10,python3.x,64位AMD R9处理器,ROG电脑,pycharm开发,已经安装好了PCV库 如何安装PCV库 请看我的博客Python之PCV库安装教程以及解说-CSDN博客文章浏览阅读111次&#xff0c;点赞5次&#xff0c;收藏3次。GitHub - Ultravioletrayss/PCVfile: 文档内含有pyt…

Nginx 配置 SSL(HTTPS)详解

Nginx作为一款高性能的HTTP和反向代理服务器&#xff0c;自然支持SSL/TLS加密通信。本文将详细介绍如何在Nginx中配置SSL&#xff0c;实现HTTPS的访问。 随着互联网安全性的日益重要&#xff0c;HTTPS协议逐渐成为网站加密通信的标配。Nginx作为一款高性能的HTTP和反向代理服务…

OpenCV 实现霍夫圆变换

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV实现霍夫变换 下一篇:OpenCV 实现重新映射 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 HoughCircles()检测图像中的圆圈。 理论 Hough 圆变换 H…

Cgicc搭建交叉编译环境(移植到arm)

Cgicc GUN Project官网连接&#xff1a;Cgicc- GNU Project - Free Software Foundation 1. 下载源码 Cgicc下载地址&#xff1a; [via http] Index of /gnu/cgicc [via FTP] ftp://ftp.gnu.org/gnu/cgicc/ 目前最新版&#xff1a;3.2.20 2. 源码构建原理 一般&#xff…

在VSCode中调试其他软件执行的python文件

在VSCode中调试其他软件执行的python文件 0. 实际场景 我有一段python代码想在Metashape中运行&#xff0c;但是又想在中间某一步停下来查看变量值。由于Metashape的python环境不容易在vscode中配置&#xff0c;所以直接用vscode调试单个文件的方式无法实现这个想法。还好&am…