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

贪吃蛇游戏

文章目录

    • 前言
    • 一.Win32API
      • 1.1GetStdHandle
      • 1.2GetConsoleCursorInfo
      • 1.3SetConsoleCursorInfo
      • 1.4SetConsoleCursorPosition
      • 1.5GetAsyncKeyState
      • 1.6setlocale
      • 二.游戏设计
      • 三.GameStart
        • 3.1蛇的创建
        • 3.2分文件
        • 3.3控制台设置
        • 3.4WelComeToGame
        • 3.5CreateMap
        • 3.6InitSnack
        • 3.7CreateFood
      • 四.GameRun
        • 4.1GameHelpInfo
        • 4.2判断按键
        • 4.3SnackMove
      • 五.GameEnd

前言

贪吃蛇是一款人人皆知的经典游戏,本篇文章使用C语言在Windows控制台环境下简单模拟实现贪吃蛇小游戏。

这篇博文需要读者熟悉C语言的指针、结构体、枚举、动态内存管理、以及数据结构的单链表等。补充知识有Windows操作系统为应用程序提供的功能接口函数Win32 API。

一.Win32API

API对应的英文单词是(Application Programming Interface),是Windows操作系统提供的32位平台应用程序接口,就叫做Win32API,是各种接口的集合。

为了实现贪吃蛇游戏,我们需要学习一些应用程序接口,借这些接口的功能来实现游戏效果,比如光标的隐藏,光标的定位。

在这里插入图片描述

在Windows中,上面是控制台应用程序,在Linux经常被叫做终端,我们写的贪吃蛇游戏打算在这个应用程序上运行。

在这里插入图片描述

在创建空项目时,创建了一个控制台程序。(博主使用VS2019编译器)

在前面反复提控制台,就是为了告诉读者控制台是一个应用程序,而Win32API就是提供给应用程序使用的函数接口,可以达到开启视窗、描绘图形、使用周边设备等目的。

1.1GetStdHandle

GetStdHandle是一个Windows API函数,这个函数可以从标准设备(标准输入、标准输出、标准错误)中获取一个句柄,控制台是一个标准输出设备。

每个设备都有一个句柄,并且句柄值不同。使用相应设备的句柄就可以控制这个设备。

在这里插入图片描述

以下这句代码,可以获取控制台的句柄(注意包含头文件<windows.h>)

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

1.2GetConsoleCursorInfo

在这里插入图片描述

该函数的参数有两个(1.句柄,2.光标类型结构体变量的地址),作用是获取句柄设备上的光标信息放到结构体变量里去。

在这里插入图片描述

CONSOLE_CURSOR_INFO是Windows操作系统提供的一个描述光标的结构体类型,成员变量dwSize表示光标的大小,bVisible表示光标的可见性,当bVisible被赋值成false时,光标可以实现隐藏

创建一个光标结构体类型变量,使用GetConsoleCursorInfo这个函数获取控制台上的光标信息,放到我们创建的结构体变量中。

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//获取控制台句柄
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//把控制台的光标信息存入光标结构体变量CursorInfo中

1.3SetConsoleCursorInfo

设置句柄设备上的光标。

在这里插入图片描述

第一个参数是句柄,第二个参数是光标结构体类型变量的地址。意思是:将句柄设备上的光标设置成第二个参数传的光标。

于是通过1.21.3的组合,就可以设置控制台的光标了!代码如下:

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);
//把可见性设为不可见,并设置进控制台
CursorInfo.bVisible = false;
SetConsoleCursorInfo(hOutput, &CursorInfo);

注意,我们必须获取控制台光标信息存到变量中,改变该变量的可见性,再设置进控制台。

不能单单创建一个光标变量,设置不可见性就设置进控制台。简而言之就是以下代码无法有效隐藏控制台光标:

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
CursorInfo.bVisible = false;
SetConsoleCursorInfo(hOutput, &CursorInfo);//error

1.4SetConsoleCursorPosition

设置光标在控制台的位置。当我们输出一句“hello world”的时候,文字默认在左顶角(原点)开始输出,如何让文字在我们想要的位置输出呢?

为此,我们先来谈谈控制台上的坐标系吧。

在这里插入图片描述

从原点出发,向右为x轴、向下为y轴、逐渐增大。在Windows中使用COORD这个结构体来表示坐标。

在这里插入图片描述

创建这个坐标结构体类型变量,比如:

COORD pos = {3, 4};//这个坐标是3列4行的意思,x是竖,y是横。

接着使用SetConsoleCursorPosition这个函数可以做到设置光标位置,参数如下:

在这里插入图片描述

​ 在句柄对应设备上,设置COORD类型变量为打印起始点。

//封装成这个函数,传参x和y,就可以指定控制台位置输出了。
void SetPos(int x, int y)
{COORD pos = { x, y };HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput, pos);
}
// 比如,SetPos(64, 15)把控制台光标设置在64列15行处,此时如果打印“hello world”,就不是在左顶角打印了。

1.5GetAsyncKeyState

在这里插入图片描述

这是一个判断按键情况的函数,键盘上每一个键都有一个对应的虚拟键值,请看下图:

在这里插入图片描述

在这里插入图片描述

GetAsyncKeyState函数接收一个虚拟键值,然后返回一个short类型的数值,如果这个short类型(16个bit位)的最低位为1,则说明这个虚拟键值对应的键被按过。

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

GetAsyncKeyState(VK)返回值按位与1,如果结果为真,则返回1,说明该键被按过,否则为0。

1.6setlocale

计算机语言早期是美国以英语语种设计的语言,所以对其它国家语言兼容性不好,随着国际化越来越加深,计算机语言也支持了本地化(使用者所在地区的语言习惯)比如金钱符号本地化前是$,本地化后¥,以及日期的表示习惯。

对于本文而言,最重要的是宽字符的打印。

英文字母占控制台屏幕缓冲区一个字符位,而宽字符它占两个字符位。要使用宽字符,需要使用setlocale函数设置本地环境。

在这里插入图片描述

category是setlocale的第一参数,是本地化的选项。LC_ALL将所有选项都本地化,还有其它单个选项,比如LC_TIME就只本地化时间。

locale是setlocale的第二个参数,只有两个选项,“C”或“ ”。双引号“ ”是执行本地化,而“C"是默认。

于是写上下面这句代码就可以进行本地化:

//设置本地环境setlocale(LC_ALL, "");

以上就是写贪吃蛇需要的Win32API接口函数的学习,下面进入游戏设计环节。

二.游戏设计

贪吃蛇游戏是一条蛇在围起来的地图里走动,通过↑、↓、←、→键控制蛇的行走方向,吃地图里的食物逐渐变长,分数累增的游戏。

这样,我们设计蛇头用宽字符○表示、蛇的身体用●、地图上的墙用□、食物使用★。

期望:一开始在一个大小合适的控制台窗口,在合适的位置打印信息。告诉玩家这是贪吃蛇游戏、规则介绍、打印地图、初始化蛇等。

接着是游戏运行界面,有帮助信息、总分数的变化、控制蛇在地图里走动,蛇吃食物等。

​最后游戏结束后给我们反馈游戏因为什么原因结束的,是撞墙了?还是吃到自己?

从这个期望中,我们分三部分:分别是游戏之前的准备(GameStart),游戏运行(GameRun)和游戏结束(GameEnd)。

三.GameStart

3.1蛇的创建

蛇是由一个个结点链接起来的整体,想要在控制台上准确打印出一条蛇,结点里存的信息应是用来表示坐标的,于是:

typedef struct SnackNode
{//x、y组合标识控制台上唯一的坐标int x;int y;struct SnackNode* next;
}SnackNode, *pSnackNode;

但是我们玩的是蛇,而不是一个一个结点,这时我们思考游戏在运行的时候,怎样能控制整条蛇、吃食物的总分数、蛇的速度、蛇的方向等等。

通过再封装一个结构体,完成对以上的整体控制:

enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
};enum GAME_STATUS
{OK,//蛇正常运行END_NORMAL,//家里有事,不玩游戏了,按Esc正常退出KILL_BY_WALL,//撞墙了KILL_BY_SELF//咬到自己了
};typedef struct Snack
{pSnackNode _pSnack;//蛇头结点控制整条蛇pSnackNode _pFood;//维护食物的指针int _Score;int _FoodWeight;int _SleepTime;//控制蛇的速度enum DIRECTION _Dir;//表示蛇的行走方向enum GAME_STATUS _Status;//蛇的状态
}Snack, *pSnack;

这里的*pSnack的意思是:相当于typedef struct Snack *(指针)重定义为pSnack,上面蛇结点指针也是一样的。

可能不熟悉贪吃蛇的读者现在不太理解,为什么蛇结构里需要有维护食物的指针,往下看就明白了。

现在蛇结构蓝图设计好了,开始写代码!

3.2分文件

在这里插入图片描述

Test.c文件用来测试,Snack.c文件用来写函数实现,Snack.h文件写头文件、写函数声明以及定义标识符、宏等。

现在进入GameStart的实现部分(Snack.c),按照预先的期望在大小合适的控制台上打印欢迎信息。

3.3控制台设置

为了方便讲解,博主在程序中会加入让运行逻辑停下来的getchar()函数。

在这里插入图片描述

注意:如果读者的控制台大小无法设置,可能是控制台的设置问题,请按下面步骤进行解决。

在这里插入图片描述

title让控制台标题变为贪吃蛇只在程序运行时生效,当程序结束后,标题便不再是我们设置的了。

3.4WelComeToGame

打印欢迎界面的时候,文字在屏幕中间显示是比较好的,而且最好不要有光标在控制台上一闪一闪的。

所以在这里需要前面的两步铺垫:如何隐藏光标、如何控制光标位置。

在这里插入图片描述

void SetPos(int x, int y)
{COORD pos = { x, y };HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput, pos);
}void WelComeToGame()
{//隐藏光标HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO Cursor;GetConsoleCursorInfo(hOutput, &Cursor);Cursor.bVisible = false;SetConsoleCursorInfo(hOutput, &Cursor);SetPos(40, 14);printf("欢迎来到贪吃蛇小游戏");SetPos(80, 27);system("pause");//清屏system("cls");SetPos(36, 14);printf("使用↑、↓、←、→键控制蛇的移动");SetPos(80, 27);system("pause");//为下面打印地图做好准备system("cls");//清完屏后,光标会到原点
}

在这里插入图片描述

system(“pause”)是让程序暂停下来,并且会自发在控制打印出“请按任意键继续. . .”,所以定位完“欢迎来到…”后,要给这句话再定位一下。

接着再介绍一下规则:

在这里插入图片描述

到这里这个函数就完成了。下面到了游戏界面,我们要打印地图。

如果行列设置不合适,显示有问题,读者可以自行设置。

3.5CreateMap

创建地图,墙使用的宽字符是□,并且要执行本地化,支持宽字符的打印。

在这里插入图片描述

宽字符占两个字符位(列),但是和ab一样都只占一行,使用wprintf打印宽字符,格式串前面加L,字符前面加L。

控制台屏幕是100列30行,那么我们就创建一个58列28行的地图吧!

在这里插入图片描述

void CreateMap()
{setlocale(LC_ALL, "");int i = 0;//上for (i = 0; i <= 56; i += 2){//#define WALL L'□'wprintf(L"%lc", WALL);}//下SetPos(0, 27);for (i = 0; i <= 56; i += 2){wprintf(L"%lc", WALL);}//左for (i = 1; i <= 26; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 1; i <= 26; i++){SetPos(56, i);wprintf(L"%lc", WALL);}//上图中的getchar()是为了不让程序结束//结束时打印的信息会覆盖下面的墙
}
3.6InitSnack

地图创建好后,初始化出一条蛇并打印在地图上。

在这里插入图片描述

pSnackNode BuySnackNode(int x, int y)
{pSnackNode tmp = (pSnackNode)malloc(sizeof(SnackNode));if (tmp == NULL){perror("BuySnackNode malloc fail");exit(-1);}tmp->x = x;tmp->y = y;tmp->next = NULL;return tmp;
}void InitSnack(pSnack ps)
{assert(ps);//创建蛇结点并连起来成“蛇”int i = 0;pSnackNode cur = NULL;for (i = 0; i < 5; i++){//#define POS_X 24 蛇尾的起点坐标POS_X和POX_Y//#define POS_Y 5cur = BuySnackNode(POS_X + i * 2, POS_Y);//单链表头插法if (ps->_pSnack == NULL){ps->_pSnack = cur;}else{cur->next = ps->_pSnack;ps->_pSnack = cur;}}//打印蛇身cur = ps->_pSnack;int count = 0;while(cur){SetPos(cur->x, cur->y);//第一次进来打印蛇头符号if (!(count++)){	//#define HEAD L'○'wprintf(L"%lc", HEAD);}else{	//#define BODY L'●'wprintf(L"%lc", BODY);}cur = cur->next;}//其它设置ps->_pFood = NULL;//食物还没创建,先赋空指针ps->_Score = 0;ps->_FoodWeight = 10;ps->_SleepTime = 150;//程序暂停时间,控制蛇的速度ps->_Dir = RIGHT;//初始蛇的方向为右ps->_Status = OK;//蛇运行状态是正常的
}
3.7CreateFood

创建食物,本质上也是创建蛇结点,蛇吃食物身体变长相当于把食物这个结点链接到蛇上。

食物的创建是有约束的:食物的x坐标应该和蛇一样,都是2的倍数。x列0-57总共58个,每个宽字符占2个字符位,食物也是宽字符,除去0-1和56-57是墙,2到54是食物的x坐标

食物行坐标在1-26之间,宽字符行与普通字符都是占一行,0行和27行被墙占了,食物不能与墙有重叠的。

还有一点是,食物不要与蛇的身体重合并且任意生成,以上这些约束要留意,下面开始写代码:

在这里插入图片描述

void CreateFood(pSnack ps)
{assert(ps);int x = 0;int y = 0;
again:do {	//随机数的使用,在主函数里设置一次生成起点x = rand() % 53 + 2;//取模53得到0~52的余数+2->2~54y = rand() % 26 + 1;//产生1~26之间的随机数} while (x % 2 != 0);//x是奇数重新生成坐标pSnackNode cur = ps->_pSnack;while (cur){//判断蛇结点与食物结点是否重合if (cur->x == x && cur->y == y){goto again;}cur = cur->next;}//到这里,食物结点坐标合法pSnackNode FoodNode = BuySnackNode(x, y);//打印食物在地图上的位置SetPos(x, y);wprintf(L"%lc", FOOD);//#define FOOD L'★'//出了创建食物的作用域,食物结点将丢失,于是使用蛇结构食物指针维护ps->_pFood = FoodNode;
}

到了这一步,游戏的所有准备工作都做好了,进入游戏阶段。

四.GameRun

游戏玩耍阶段,控制台左边是蛇在地图里走动,右边设置分数变化和按键说明的信息,比如:按空格键暂停、按Esc键正常退出等等。

在这里插入图片描述

4.1GameHelpInfo

在这里插入图片描述

void GameHelpInfo()
{SetPos(64, 14);printf("1.使用↑.↓.←.→键控制蛇的移动");SetPos(64, 15);printf("2.按F2键加速、F3减速");SetPos(64, 16);printf("3.蛇不能撞墙,不能咬到自己");SetPos(64, 17);printf("4.Space——暂停、Esc——正常退出");SetPos(84, 24);printf("@啊苏");
}
4.2判断按键

因为分数是时刻变化的,所以获得分数不在帮助信息里打印,细想什么是跟随的游戏一直在变的呢?没错就是玩家的按键逻辑,将分数的打印放在按键里。

在这里插入图片描述

判断按键的情况在下面的代码中进行讲解:

void Pause()
{while (1){Sleep(100);if (PRESS_KEY(VK_SPACE)){break;}}
}void GameRun(pSnack ps)
{assert(ps);//打印帮助信息GameHelpInfo();//判断按键情况do{SetPos(64, 10);printf("获得的分数:%-4d", ps->_Score);SetPos(64, 11);printf("每个食物的分数:%-2d", ps->_FoodWeight);//键盘上的↑键对应的虚拟值是VK_UP这个常数if (PRESS_KEY(VK_UP) && ps->_Dir != DOWN){	//#define PRESS_KEY(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)ps->_Dir = UP;}else if (PRESS_KEY(VK_DOWN) && ps->_Dir != UP){	//想让蛇的方向朝下,前提是蛇原型方向不能是朝上走的ps->_Dir = DOWN;}else if (PRESS_KEY(VK_LEFT) && ps->_Dir != RIGHT){ps->_Dir = LEFT;}else if (PRESS_KEY(VK_RIGHT) && ps->_Dir != LEFT){ps->_Dir = RIGHT;}else if (PRESS_KEY(VK_F2)){//最多加速三次(从设定的速度开始算)if (ps->_SleepTime > 30){//_SleepTime控制蛇的速度,越短蛇走的越快ps->_SleepTime -= 40;ps->_FoodWeight += 5;}}else if (PRESS_KEY(VK_F3)){//最多减速一次(从设定的速度开始算)if (ps->_SleepTime < 190){ps->_SleepTime += 40;ps->_FoodWeight -= 5;}}else if (PRESS_KEY(VK_ESCAPE)){ps->_Status = END_NORMAL;break;}else if (PRESS_KEY(VK_SPACE)){Pause();//暂停函数}} while (ps->_Status == OK);//只有蛇正常运行时,才能正常让玩家按键控制方向
}

读者可以在搜索引擎上找GetAsyncKeyState这个函数,然后里面有关于虚拟键值的超链接,点击跳转即可查看。

这么多按键是代码看起来很复杂,但其逻辑并不难理解,但cpu处理速度很快,不用担心处理不过来。

然后睡眠时间现在就起作用了。

在这里插入图片描述

在判断按键后,用于Sleep函数让程序停下来一段时间,_SleepTime = 150,150是毫秒。

在短暂的停止后,蛇开始移动!

4.3SnackMove
//判断蛇下一位置是否为结点
int NextIsFood(pSnack ps, pSnackNode pnext)
{	//食物指针的用处体现了,在游戏期间,食物指针能很好的维护着食物,防止内存泄漏if (pnext->x == ps->_pFood->x && pnext->y == ps->_pFood->y){//如果蛇结点里的食物坐标与蛇下一步走的位置相同 返回1确认是食物return 1;}else{//返回0说明蛇的下一位置不是食物return 0;}
}//注意食物结点的坐标与预创建的结点坐标一致,但不是同一个结点!
void EatFood(pSnack ps, pSnackNode pnext)
{assert(ps);//预创建的结点成为蛇头,pnext->next = ps->_pSnack;ps->_pSnack = pnext;//然后打印蛇pSnackNode cur = ps->_pSnack;int count = 0;while (cur){SetPos(cur->x, cur->y);if (!(count++)){wprintf(L"%lc", HEAD);}else{wprintf(L"%lc", BODY);}cur = cur->next;}//获得分数ps->_Score += ps->_FoodWeight;//释放食物结点,食物结点free(ps->_pFood);ps->_pFood = NULL;//重新生成食物,这个创建食物的函数会打印食物在地图上CreateFood(ps);
}void NotFood(pSnack ps, pSnackNode pnext)
{assert(ps);//不是食物也要把预创建的结点链接进来成为蛇头pnext->next = ps->_pSnack;ps->_pSnack = pnext;//把蛇尾给去掉保持长度不变,使用前后指针,打印蛇身pSnackNode cur = ps->_pSnack;pSnackNode curPrev = ps->_pSnack;int count = 0;while (cur->next){SetPos(cur->x, cur->y);if (!(count++)){wprintf(L"%lc", HEAD);}else{wprintf(L"%lc", BODY);}curPrev = cur;cur = cur->next;}//到这里cur是旧蛇尾,要把这里的宽字符打印成空格,打印空格覆盖掉地图上的宽字符SetPos(cur->x, cur->y);printf("  ");//释放旧蛇尾free(cur);//把新的蛇尾next指针赋空curPrev->next = NULL;
}void SnackMove(pSnack ps)
{assert(ps);//蛇的移动选择预开辟下一位置结点方法pSnackNode pNext = NULL;pSnackNode pHead = ps->_pSnack;//旧蛇头//根据蛇的方向,选择下一结点的位置switch (ps->_Dir){	//pNext是预创建的结点!case UP:pNext = BuySnackNode(pHead->x, pHead->y - 1);//上的话,列不变行减1break;case DOWN:pNext = BuySnackNode(pHead->x, pHead->y + 1);break;case LEFT:pNext = BuySnackNode(pHead->x - 2, pHead->y);//左是行不变,列减2,因为宽字符占两列break;case RIGHT:pNext = BuySnackNode(pHead->x + 2, pHead->y);break;}//蛇方向下一个结点有两种情况:是食物和不是食物if (NextIsFood(ps, pNext)){//是食物就把食物吃了,把pNext结点链接进蛇并成为蛇头EatFood(ps, pNext);}else{NotFood(ps, pNext);}}

到这里,玩家就能正常在使用上下左右等键控制蛇的移动,加减速、暂停等。接下来要处理蛇在运行时,状态从OK变为不Ok的逻辑。

在这里插入图片描述

void KillByWall(pSnack ps)
{assert(ps);if (ps->_pSnack->x == 0 ||ps->_pSnack->x == 56 ||ps->_pSnack->y == 0 ||ps->_pSnack->y == 27)ps->_Status = KILL_BY_WALL;
}void KillBySelf(pSnack ps)
{assert(ps);pSnackNode cur = ps->_pSnack->next;//蛇头以后的结点与蛇头相比是否有坐标一致的while (cur){if (cur->x == ps->_pSnack->x && cur->y == ps->_pSnack->y){ps->_Status = KILL_BY_SELF;break;}cur = cur->next;}
}

到这里,蛇的逻辑就完整了,但是游戏结束后,还没能得到很好的善后处理,比如链表的释放、告诉玩家是怎么游戏结束的等等。

下面进入到游戏结束环节:

五.GameEnd

游戏结束后,在合适的位置打印信息给玩家:

void GameEnd(pSnack ps)
{assert(ps);SetPos(15, 10);switch (ps->_Status){case END_NORMAL:printf("主动退出,游戏结束");break;case KILL_BY_WALL:printf("撞到墙了,游戏结束");break;case KILL_BY_SELF:printf("咬到自己,游戏结束");break;}//释放蛇pSnackNode cur = ps->_pSnack;while (cur){pSnackNode curnext = cur->next;free(cur);cur = curnext;}
}

在这里插入图片描述

程序在结束时有这句话,我们可以在程序结束前定好光标位置,让这句话不要影响游戏效果。

除了这个之外,游戏最重要的一个再来一局逻辑还没有设计,我们把最后的坑补上。

void Test()
{int input = 0;do {Snack s = { 0 };//游戏开始GameStart(&s);//游戏运行GameRun(&s);//游戏结束GameEnd(&s);SetPos(15, 12);printf("是否想要再来一局(Y/N):");input = getchar();getchar();//清空输入缓冲区}while(input == 'Y' || input == 'y');SetPos(0, 28);
}

到这里,贪吃蛇小游戏实现完毕!

希望这篇博文对想实现贪吃蛇小游戏的读者有帮助。

相关文章:

贪吃蛇游戏

文章目录 前言一.Win32API1.1GetStdHandle1.2GetConsoleCursorInfo1.3SetConsoleCursorInfo1.4SetConsoleCursorPosition1.5GetAsyncKeyState1.6setlocale二.游戏设计三.GameStart3.1蛇的创建3.2分文件3.3控制台设置3.4WelComeToGame3.5CreateMap3.6InitSnack3.7CreateFood 四.…...

DPDK trace 的简单使用

文章目录 前言trace的简单使用 前言 日志用于记录不太频繁&#xff0c;比较高level的事情。trace记录频繁发生的事情&#xff0c;它的开销低。 trace可以在运行时&#xff0c;通过参数控制是否启用&#xff1b;可以在任何时间点&#xff0c;将trace记录的缓冲区保存到文件系统…...

《游戏-01_2D-开发》

首先利用安装好的Unity Hub创建一个unity 2D&#xff08;URP渲染管线&#xff09;项目 选择个人喜欢的操作格局&#xff08;这里采用2 by 3&#xff09; 在Project项目管理中将双栏改为单栏模式&#xff08;个人喜好&#xff09; 找到首选项&#xff08;Preferences&#xff09…...

如何禁用WordPress站点的管理员电子邮件验证或修改检查频率?

今天boke112百科登录某个WordPress站点时&#xff0c;又出现“管理员邮件确认”的提示&#xff0c;要求确认此站点的管理员电子邮箱地址是否仍然正确。具体如下图所示&#xff1a; 如果点击“稍后提醒我”&#xff0c;那么管理员邮件验证页面就会在3天后重新显示。 说实话&…...

三、MySQL实例初始化、设置、服务启动关闭、环境变量配置、客户端登入(一篇足以从白走到黑)

目录 1、选择安装的电脑类型、设置端口号 2、选择mysql账号密码加密规则 3、设置root账户密码 4、设置mysql服务名和服务启动策略 5、执行设置&#xff08;初始化mysql实例&#xff09; 6、完成设置 7、MySQL数据库服务的启动和停止 方式一&#xff1a;图形化方式 方式…...

Ubuntu20.04-剪贴板

针对图形界面用户 1.两种方式 1.1 安装Parcellite 简单轻量级剪贴板管理器 sudo apt install parcellite 1.2 安装Gpaste 更强大的剪贴板管理器&#xff0c;包含历史记录和同步功能 sudo apt install gpaste...

springmvc常用的组件

SpringMVC常用组件 以下的Handler也叫Controller。 1、DispatcherServlet&#xff1a;前端控制器&#xff0c;不需要工程师开发&#xff0c;由框架提供 作用&#xff1a;统一处理请求和响应&#xff0c;整个流程控制的中心&#xff0c;由它调用其它组件处理用户的请求 2、H…...

Mysql中设置只允许指定ip能连接访问(可视化工具的方式)

场景 Mysql中怎样设置指定ip远程访问连接&#xff1a; Mysql中怎样设置指定ip远程访问连接_navicat for mysql 设置只有某个ip可以远程链接-CSDN博客 前面设置root账户指定ip能连接访问是通过命令行的方式&#xff0c;如果通过可视化工具比如Navicat来实现。 注&#xff1a…...

vue2+webpack升级vue3+vite,报错Cannot read properties of null (reading ‘isCE‘)

同学们可以私信我加入学习群&#xff01; 正文开始 前言问题分析解决总结 前言 系列文章&#xff1a;vue2webpack升级vue3vite&#xff0c;修改插件兼容性bug 前面的文章主要是介绍&#xff0c;在升级初始阶段遇到的一些显而易见的兼容性问题和bug。随着项目迭代的不断深入&a…...

【性能调优】local模式下flink处理离线任务能力分析

文章目录 一. flink的内存管理1.Jobmanager的内存模型2.TaskManager的内存模型2.1. 模型说明2.2. 通讯、数据传输方面2.3. 框架、任务堆外内存2.4. 托管内存 3.任务分析 二. 单个节点的带宽瓶颈1. 带宽相关理论2. 使用speedtest-cli 测试带宽3. 任务分析3. 其他工具使用介绍 本…...

Zabbix监控(2)

目录 一.自动发现 配置自动发现&#xff1a;&#xff08;被动模式&#xff09; 修改三台服务器的hosts文件&#xff1a; 修改agent02的配置文件&#xff1a; 访问页面&#xff0c;删除客服端主机配置&#xff1a; 在配置的自动发现中添加规则&#xff1a; 我们重启的zab…...

uni-app中代理的两种配置方式

方式一: 在项目的 manifest.json 文件中点击 源码视图 在最底部的vue版本下编写代理代码 方式二: 在项目中创建 vue.config.js 文件然后进行配置 在页面中发起请求 完整的url&#xff1a;http://c.m.163.com/recommend/getChanListNews?channelT1457068979049&size10 …...

循环异步调取接口使用数组promiseList保存,Promise.all(promiseList)获取不到数组内容,then()返回空数组

在使用 vue vant2.13.2 技术栈的项目中&#xff0c;因为上传文件的接口是单文件上传&#xff0c;当使用批量上传时&#xff0c;只能循环调取接口&#xff1b;然后有校验内容&#xff1a;需要所有文件上传成功后才能保存&#xff0c;在文件上传不成功时点击保存按钮&#xff0c…...

C++轮子 · STL 序列容器

STL中大家最耳熟能详的可能就是容器,容器大致可以分为两类,序列型容器(SequenceContainer)和关联型容器(AssociativeContainer)这篇文章中将会重点介绍STL中的各种序列型容器和相关的容器适配器。主要内容包括 std::vectorstd::arraystd::dequestd::queuestd::stackstd::…...

浅谈智慧路灯安全智能供电方案设计

摘要: 智慧路灯&#xff0c;作为智慧城市、新基建、城市更新的主要组成部分&#xff0c;近些年在各大城市已得到很好的落地和 应用&#xff0c;但其与传统路灯相比集成大量异元异构电子设备&#xff0c;这些设备的供电电压、接口形式、权属单位各不相同&#xff0c; 如何设计一…...

C#设计模式教程(2):工厂方法模式

工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 C# 代码实现 以下是C#中实现工厂方法模式的一个简单示例: 首先,定义一个抽象产品(Product)类,它是所有具体产品的基类。 pu…...

程序员的能力-如何成为不会过时的“码农”

码农是指从事编程工作的人&#xff0c;也被称为程序员或开发者。他们使用计算机语言和工具来编写、测试和维护软件程序或网站。码农通常需要具备扎实的计算机科学知识、编程技能和问题解决能力&#xff0c;以及良好的逻辑思维和团队合作能力。他们可以在软件开发公司、科技企业…...

【OpenAI】自定义GPTs应用(GPT助手应用)及外部API接口请求

11月10日&#xff0c;OpenAI正式宣布向所有ChatGPT Plus用户开放GPTs功能 简而言之&#xff1a;GPT应用市场(简称GPTs, 全称GPT Store) Ps&#xff1a; 上图为首次进入时的页面&#xff0c;第一部分是自己创建的GPTs应用&#xff0c;下面是公开可以使用的GPTs应用 一、创建GPTs…...

canvas绘制不同样式的五角星(图文示例)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…...

C#: BitConverter 字节数组byte[ ] 转各种数据类型用法列举

说明&#xff1a;C# BitConverter 字节数组byte[ ] 转各种数据类型用法示例 1.ToBoolean(byte[] value, int startIndex)&#xff1a;将指定字节数组中从指定索引开始的两个字节转换为布尔值。 byte[] bytes { 1, 0 }; bool result BitConverter.ToBoolean(bytes, 0); // 输…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献

Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译&#xff1a; ### 胃肠道癌症的发病率呈上升趋势&#xff0c;且有年轻化倾向&#xff08;Bray等人&#xff0c;2018&#x…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...

DriveGPT4: Interpretable End-to-end Autonomous Driving via Large Language Model

一、研究背景与创新点 (一)现有方法的局限性 当前智驾系统面临两大核心挑战:一是长尾问题,即系统在遇到新场景时可能失效,例如突发交通状况或非常规道路环境;二是可解释性问题,传统方法无法解释智驾系统的决策过程,用户难以理解车辆行为的依据。传统语言模型(如 BERT…...