当前位置: 首页 > 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); // 输…...

【开发实践】前端jQuery+gif图片实现载入界面

一、需求分析 载入界面&#xff08;Loading screen&#xff09;是指在计算机程序或电子游戏中&#xff0c;当用户启动应用程序或切换到新的场景时&#xff0c;显示在屏幕上的过渡界面。它的主要作用是向用户传达程序正在加载或准备就绪的信息&#xff0c;以及提供一种视觉上的反…...

解析消费全返:谈谈那些关于商业的小妙招

每天五分钟讲解商业模式&#xff0c;大家好我是模式策划啊浩。 在数字化时代&#xff0c;商业模式正在经历前所未有的变革。其中&#xff0c;消费全返的概念正在逐渐崭露头角&#xff0c;引领着商业创新的新潮流。消费全返&#xff0c;顾名思义&#xff0c;是指消费者在购买商…...

如何在MinIO存储服务中通过Buckets实现远程访问管理界面上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统&#xff0c;它可以100%的运行在标准硬件上&#xff0c;即X86等…...

算法 - 二分法 / 双指针 / 三指针 / 滑动窗口

文章目录 &#x1f37a; 二分法&#x1f37b; 旋转数组&#x1f942; 33. 搜索旋转排序数组 [旋转数组] [目标值] (二分法) &#x1f37b; 元素边界&#x1f942; 34. 在排序数组中查找元素的第一个和最后一个位置 [有序数组] > [元素边界] > (二分法)&#x1f942; 81. …...

ChatGPT3.5、GPT4.0、DALL·E 3和Midjourney对话与绘画智能体验

MidTool&#xff08;https://www.aimidtool.com/&#xff09;是一个集成了多种先进人工智能技术的助手&#xff0c;它融合了ChatGPT3.5、GPT4.0、DALLE 3和Midjourney等不同的智能服务&#xff0c;提供了一个多功能的体验。下面是这些技术的简要介绍&#xff1a; ChatGPT3.5&am…...

MySQL中锁的概述

按照锁的粒度来分可分为&#xff1a;全局锁&#xff08;锁住当前数据库的所有数据表&#xff09;&#xff0c;表级锁&#xff08;锁住对应的数据表&#xff09;&#xff0c;行级锁&#xff08;每次锁住对应的行数据&#xff09; 加全局锁&#xff1a;flush tables with read lo…...

5396. 棋盘

5396. 棋盘 - AcWing题库 二维差分数组 #include <iostream> #include <vector> using namespace std;int main() {int n, m;cin >> n >> m;vector<vector<int>> v(n 2, vector<int>(n 2));while (m--) {int x1, x2, y1, y2;cin…...

阿里云地域和可用区分布表,2024更新

2024年阿里云服务器地域分布表&#xff0c;地域指数据中心所在的地理区域&#xff0c;通常按照数据中心所在的城市划分&#xff0c;例如华北2&#xff08;北京&#xff09;地域表示数据中心所在的城市是北京。阿里云地域分为四部分即中国、亚太其他国家、欧洲与美洲和中东&…...

Pandas实战100例 | 案例 49: 数值运算

案例 49: 数值运算 知识点讲解 Pandas 提供了进行基本数学运算的简便方法,允许你在 DataFrame 的列之间执行加法、减法、乘法和除法等操作。 数值运算: 直接对 DataFrame 的列应用算术运算符(+, -, *, /)可以执行相应的数值运算。示例代码 # 准备数据和示例代码的运行结果…...

OSI七层协议和五层协议

【 1 】互联网协议交互的基础 硬件设备 光缆 【 2 】OSI七层协议 物理层&#xff08;Physical Layer&#xff09;&#xff1a;负责传输比特流&#xff08;0和1&#xff09;以及物理连接的建立和维护。数据链路层&#xff08;Data Link Layer&#xff09;&#xff1a;提供可…...