c语言贪食蛇游戏

news2024/12/29 8:57:52

演示视频

目录

一.概述 

二.游戏开始前

修改控制台程序标题和大小

 Win32 API

 GetStdHandle函数

GetConsoleCursorInfo函数和SetConsoleCursorInfo函数

SetConsoleCursorPosition函数 

游戏开篇界面处理

创建地图

蛇身节点以及食物节点初始化

蛇身的初始化 

整体蛇节点初始化的代码

食物节点初始化

食物节点初始化完整代码 

三.游戏运行阶段 

游戏按键的设置

虚拟按键代码

snakemove移动函数

撞墙机制

咬到自己机制 

游戏运行阶段的全部代码如下,从下往上看

五.贪食蛇完整代码

测试.c文件代码

贪食蛇的声明.h文件

贪食蛇的实现.h代码


一.概述 

贪食蛇游戏设计,分为游戏开始前和游戏运行以及游戏结束三个阶段,我这个是利用win32 API直接在命令框设计的游戏,游戏运行阶段主要是解决游戏界面,提示信息等方面。游戏运行阶段会去解决初始化蛇身和食物,以及根据按键情况去移动蛇的方面。游戏结束阶段会告知游戏结束的原因和释放链表节点(蛇身以及食物都是通过链表来表示,其实也可以通过动态顺序表来做),游戏结束一般来说会是撞墙结束,咬到自己结束,以及正常退出三种情况。

二.游戏开始前

正常的控制台程序结束标题位置一般都是默认给出了,如果要修改标题要怎么修改呢,控制台程序命令框的大小能不能修改呢。同时光标一闪一闪很影响观感,也应该隐藏起来。

修改控制台程序标题和大小

对于windows命令框可以直接通过  title 新名称来修改命令框标题

 而命令框的大小可以通过mode con cols=要修改的大小 lines=有修改的大小,来进行修改大小,cols是行大小,lines是列大小

而对于编译器来说可不可以使用同样的语句来修改控制台程序界面的大小呢

 还没使用就已经报错了,如果你想使用和windows系统一样的语句进行修改,那么需要加上windows.h头文件,并且使用system才能使用系统语句

代码和运行结果如下,使用getchar()是使程序一直停留在运行阶段,方便测试,如果不这样的话运行结束会直接还原

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
void text()
{
	 system("title 贪食蛇");
	 system("mode con cols=100 lines=30");
	 getchar();
}
int main()
{
	text();
}

 2.光标的隐藏以及改变输入位

 Win32 API

控制程序光标的各种操作是通过win32 API来进行操作的,Windows这个多作业系统除了协调应⽤程序的执行、分配内存、管理资源之外,它同时也是⼀个很大的服务中心,调⽤这个服务中心的各种服务(每⼀种服务就是⼀个函数),可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应⽤程序(Application),所以便称之为Application Programming Interface,简称API函数。WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。

不过话说回来,如果你要画图又没怎么接触这些图形库,还是先用Easyx吧,这个更容易初学者上手一点,Win32要处理很多细节

Win32 API是windows系统提供的,所以直接使用windows.h头文件就可以使用了

 GetStdHandle函数

 GetStdHandle是用来获取句柄的函数,属于windows API函数,GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。句柄说直白点其实就是一个“授权的凭证”,你要通过这个“授权许可凭证”才能进行一系列操作,可以操纵鼠标的光标,还可以用来控制窗口的位置、大小和状态。

语法如下

HANDLE  GetStdHandle(
  DWORD nStdHandle
);

函数参数如下 

在Windows编程中,标准输入、标准输出和标准错误的句柄值分别为-10、-11和-12。这些特殊的负数值是为了与普通句柄值区分开来。通常情况下,普通句柄值是正整数,而这些特殊句柄值是为了表示标准输入输出而特意赋予的负数值。其实你不填参数值,它也默认是-10,-11,-12

比如获取标准输出的句柄可以表示为HANDLE WINAPI GetStdHandle( STD_OUTPUT_HANDLE)

HANDLE是一种数据类型,是专门接收句柄用的。

GetConsoleCursorInfo函数和SetConsoleCursorInfo函数

GetConsoleCursorInfo函数是用来查看检索光标大小和可见性信息的函数,SetConsoleCursorInfo是将修改后的结果设置回去的函数。

具体用法是首先获取句柄,然后通过GetConsoleCursorInfo函数来获取光标信息,再然后进行修改,然后通过SetConsoleCursorInfo把修改后的结果设置回去


 HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取句柄
 CONSOLE_CURSOR_INFO Info;
 GetConsoleCursorInfo(houtput, &Info);//获取光标控制台信息
 Info.bVisible = false;//隐藏控制台光标
 SetConsoleCursorInfo(houtput, &Info);//把修改后的结果设置回去

  CONSOLE_CURSOR_INFO这是个结构体,是专门用来存放光标信息的结构体,这个结构体成员是是光标可见性和光标大小

bVisible 是光标可见性,false是隐藏,true是正常显示。有些c编译器不支持布尔值 ,用0表示false,1表示true也可以实现操作

dwSize是光标大小,现在的光标大小一般默认是百分之25,介于1到100之间

SetConsoleCursorPosition函数 

这个函数是用来设置光标位置的,一般光标是默认放在左上角进行输出的,而想到屏幕中间输出文字可以通过这个函数来实现。

COORD是存放光标位置的结构体,成员是横坐标x,纵坐标y

COORD定义

用法如下

void setpos(int x, int y)
{
	COORD pos = { x,y };
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(houtput, pos);
}

因为要用到很多次,所以单独设置一个函数

游戏开篇界面处理

然后就可以开始准备游戏界面的处理了

首先打印开篇界面

 此时开篇界面的代码

void setpos(int x, int y)
{
	COORD pos = { x,y };
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(houtput, pos);
}

那么如何控制请按任意键继续呢,这些字不是直接打印出来的,windows提供了系统函数pause进行暂停,请按任意键继续是这个函数调用了自动产生的

void welcome()
{
	setpos(40, 10);
	printf("欢迎来到贪食蛇小游戏\n");
	setpos(43, 15);
	system("pause");
	getchar();
}

然后开始处理第二个界面 

但是在打印之前要先清理上一个界面的数据,通过windows自带的cls就可以清屏了

void welcomemap()
{
	setpos(40, 10);
	printf("欢迎来到贪食蛇游戏\n");
	setpos(41, 15);
	system("pause");
	system("cls");//清屏
	setpos(38, 10);
	printf("用 ↑ ↓ → ←键操作蛇\n");
	setpos(38, 13);
	printf("f3表示加速,f4表示减速,加速能得到更多的分数");
	setpos(38, 18);
	system("pause");
	system("cls");
}//欢迎界面

处理完就这个样子了

 

创建地图

地图的打印我采用的是宽字符“□”,单字符(一个字节的空间)通常是指一个字母、数字或标点符号,但是复杂的特殊符号方框五角星之类的用的是宽字符(两个字节的空间),c语言是美国人发明的,默认ASCII编码形式,所以要打印宽字符需要setlocale函数来进行本地化,具体用法如下

setlocale(LC_ALL, "");

 头文件是<locale.h>,LC_ALL是针对所有项进行修改,具体有
• 数字量的格式 LC_NUMERIC
• 货币量的格式    LC_MONETARY      • 字符集  LC_CTYPE
• ⽇期和时间的表⽰形式 LC_TIME      •所有格式LC_ALL

""双引号表示的是默认本地化,vs编译器双引号里面不加空格,否则会本地化失败,也不会报错,反正就一直打印不出来宽字符。也可以写的具体点setlocale(LC_ALL, "zh_CN");或者指定编码格式setlocale(LC_ALL, "zh_CN.UTF-8");
setlocale(LC_ALL, NULL);是不进行任何操作,仅仅用来查看当前locale设置成了什么

设置完之后就可以着手打印地图了,需要注意的是宽字符只是横坐标x占两个字节,但是纵坐标依旧是一个字节,大致如下

所以一个方格横坐标相当于纵坐标的两倍,如果我想把墙体设置为正方形的话,横坐标是0到54,坐标最后到了56除二为28个格子,而纵坐标是1到27共27个格子,因为横坐标已经打印了0,所以纵坐标从1开始,加上0坐标的各种也28个格子

#define wall L'□'

 

宽字符打印格式是wprintf,我已经提前 把要作为墙体的宽字符方框□要宏定义了,方便修改#define wall L'□'

因为宽字符是占两个字节,所以它每次打印的横坐标x都必须是2的倍数(0也是2的倍数),所以每次i都要+2而不是往常的i++,而第一个横着的墙体纵坐标y是不变的,一直是0,只需要改变x就行

接下来打印最左边竖着的墙,x轴是不变的,y轴每次都要变,所以只需要改变y值就行了,y轴还是一个字节每次加1就行,第0行横坐标的时候已经打印了,所以从1开始打印

然后是最下面横着的墙打印,y轴是一直保持27不变的,竖着的墙坐标到27就停止了,所以跟它连接的横着的墙y轴从27开始。x轴因为要和竖着的行衔接,所以第0行其实已经被打印过了,所以从2开始,每次增加2(宽字符x轴占两个字节)

再然后最右边竖着的墙 ,x轴不变,打印最上面墙的时候条件是i<56,这里没有等号,所以到不了56,而每次i都加2,所以最右边竖着的墙从54开始往下打印就行。也就是x一直保持54,而y轴变化

,由于第一行和最后一行都已经打印过了,所以条件为int i = 1; i < 27; i++

再然后打印右侧的提示信息,这个自己设置好光标直接打印就行,最右的墙最后坐标是56,所以x轴坐标设置要大于56

蛇身节点以及食物节点初始化

我采用的是单链表作为蛇身节点和食物节点用的,所以我采用了结构体snakenode首先对蛇身节点和食物节点都进行初始化,其次贪食蛇整体不只有蛇身节点这一个属性,还有方向 游戏状态,食物分数,总分等多个属性,所以又用另外一个结构体snakegame来表示游戏的各种属性

snakenode节点只有两个成员横坐标x,纵坐标y

 snakegame是维护整条贪食蛇的

因为游戏状态和方向比较多,所以用枚举方式一一表示了

蛇身的初始化 

蛇身的初始化采用的是不带头结点的单链表的头插法,在调用初始化函数snakeInit之前就已经把头结点置为空了,然后循环建立节点cur,如果蛇链表的头结点为空,那么就让第一个cur作为头结点

if (ps->psnake == NULL)
{
	cur->next = ps->psnake;//最后一个节点置空
	ps->psnake = cur;
}

因为头插法第一个插入的节点是链表的最后一个,是需要置空的,而ps->psnake之前初始化的时已经置为空了,所以cur->next=ps->psnake; 

如果头节点不为空,那么就将新建节点的next指向头结点,然后将ps->snake头节点指向新建立的节点,这样新建立的节点成了新的头节点

else
{
	cur->next = ps->psnake;
	ps->psnake = cur;
}

蛇身节点我是准备设置五个节点,因为每个宽字符占两个字节,所以i+=2,把cur的x坐标和y坐标设置,y的坐标设置为5不动,只改变x的坐标。cur的坐标设置完了之后用setpos函数在同样的坐标上打印身体宽字符图案

for循环的条件如下

for (int i = 0; i <10; i+=2)

cur坐标和打印身体如下

cur->x = 24 + i;
cur->y = 5;//设置cur的x和y坐标
setpos(cur->x, cur->y);//在cur坐标上打印蛇的身体
wprintf(L"%lc", BODY);

再然后顺便初始化一下贪食蛇的其他数据

ps->Dir = right;//方向
ps->foodweight = 10;//一个食物的分数
ps->score = 0;//总分
ps->sleeptime = 200;//休眠时间
ps->statues = ok;//游戏状态

整体蛇节点初始化的代码
void snakeInit(Snake* ps)
{
	
	for (int i = 0; i <10; i+=2)
	{
		snakenode* cur = (snakenode*)malloc(sizeof(snakenode));
		if (ps->psnake == NULL)
		{
			cur->next = ps->psnake;
			ps->psnake = cur;
		}
		else
		{
			cur->next = ps->psnake;
			ps->psnake = cur;
		}
		cur->x = 24 + i;
		cur->y = 5;//设置cur的x和y坐标
		setpos(cur->x, cur->y);//在cur坐标上打印蛇的身体
		wprintf(L"%lc", BODY);
	}
	ps->Dir = right;//方向
	ps->foodweight = 10;//一个食物的分数
	ps->score = 0;//总分
	ps->sleeptime = 200;//休眠时间
	ps->statues = ok;//游戏状态
}//蛇身节点初始化

食物节点初始化

食物的位置是随机出现的,食物节点的初始化要用到随机函数生成随机数,请注意这个随机是针对节点的成员x和y来说的。创建随机x和y轴时要注意不能生成的节点在蛇身体的五个节点上,然后要在墙里面不能在墙上或者墙外面。其次y没什么要求,在墙内就行,而x必须是2的倍数,因为节点都采用了宽字符打印,如果不是2的倍数,有可能生成的食物半边在墙内,另外半边在墙外

	int x; int y;
again:
	do {
		x = rand()%51 + 2;
		y = rand()%26 + 1;//控制节点坐标生成在墙内

	} while (x % 2 != 0);//宽字符x必须是2的倍数


	snakenode* cur = ps->psnake;
	while (cur)
	{
		if (x == cur->x &&y == cur->y)//判断生成的坐标是否是蛇身节点
			goto again;//如果是蛇身节点那么就跳转回上面重新生成x,y
		cur = cur->next;
	}

对于rand函数,rand()%51是生成0到50之间的随机数,加2 就变成了生成2到52之间的随机数(包括52),因为如果坐标是0,那么就生成在竖着的墙上了,坐标是54就生成在最右边竖着的墙上了。所以范围是2到52。rand()%26 + 1也是同理

食物节点初始化完整代码 
void foodInit(Snake* ps)
{
	int x; int y;
again:
	do {
		x = rand()%51 + 2;
		y = rand()%26 + 1;//控制节点坐标生成在墙内

	} while (x % 2 != 0);//宽字符x必须是2的倍数


	snakenode* cur = ps->psnake;
	while (cur)
	{
		if (x == cur->x &&y == cur->y)//判断生成的坐标是否是蛇身节点
			goto again;//如果是蛇身节点那么就跳转回上面重新生成x,y
		cur = cur->next;
	}


	ps->pfood = (snakenode*)malloc(sizeof(snakenode));//pfood是维护食物节点的指针
	ps->pfood->x = x; ps->pfood->y = y;
	setpos(ps->pfood->x, ps->pfood->y);
	wprintf(L"%lc", FOOD);
}

三.游戏运行阶段 

这个阶段回去处理游戏按键与节点怎么对应起来以及游戏是怎么运行的

游戏按键的设置

如何将按键与游戏操作结合起来呢,将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。win32 API给了一个函数GetAsyncKeyState ,GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。

贪食蛇游戏检查最低位是不是1就可以了,可以用GetAsyncKeyState的返回值按位&1就可以知道最低是1还是0了

GetAsyncKeyState函数有一个参数,即虚拟键码(Virtual Key Code),用于指定要检查状态按键。

贪食蛇游戏我们只需要用到上下左右,F3 F4 空格,esc退出就可以了

在代码开头写成宏方便操作#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)

这个VK就是我们要检查的具体虚拟按键代码,比如要检查↑,那么就是 KEY_PRESS(VK_UP),具体虚拟按键表格如下

虚拟按键代码
虚拟按键描述
VK_LBUTTON0x01鼠标左键
VK_RBUTTON0x02鼠标右键
VK_CANCEL0x03控制中断处理
VK_MBUTTON0x04鼠标中键
VK_XBUTTON10x05X1 鼠标按钮
VK_XBUTTON20x06X2 鼠标按钮
-0x07保留
VK_BACK0x08BACKSPACE 键
VK_TAB0x09TAB 键
-0x0A-0B保留
VK_CLEAR0x0CCLEAR 键
VK_RETURN0x0DENTER键
-0x0E-0楼未分配
VK_SHIFT0x10换档键
VK_CONTROL0x11CTRL 键
VK_MENU0x12Alt 键
VK_PAUSE0x13暂停键
VK_CAPITAL0x14CAPS LOCK 键
VK_KANA0x15IME 假名模式
VK_HANGUL0x15IME 韩文模式
VK_IME_ON0x16IME 开启
VK_JUNJA0x17IME Junja 模式
VK_FINAL0x18IME 最终模式
VK_HANJA0x19IME 汉字模式
VK_KANJI0x19IME 汉字模式
VK_IME_OFF0x1AIME 关闭
VK_ESCAPE0x1B电调键
VK_CONVERT0x1CIME 转换
VK_NONCONVERT0x1DIME 非转换
VK_ACCEPT0x1EIME 接受
VK_MODECHANGE0x1FIME 模式更改请求
VK_SPACE0x20空格键
VK_PRIOR0x21PAGE UP 键
VK_NEXT0x22PAGE DOWN 键
VK_END0x23END 键
VK_HOME0x24HOME键
VK_LEFT0x25向左箭头键
VK_UP0x26向上箭头键
VK_RIGHT0x27向右箭头键
VK_DOWN0x28向下箭头键
VK_SELECT0x29SELECT 键
VK_PRINT0x2APRINT 密钥
VK_EXECUTE0x2BEXECUTE 键
VK_SNAPSHOT0x2CPRINT SCREEN 键
VK_INSERT0x2DINS 密钥
VK_DELETE0x2EDEL键
VK_HELP0x2FHELP 键
0x300 键
0x311 键
0x322 键
0x333键
0x344键
0x355键
0x366键
0x377键
0x388键
0x399键
-0x3A-40定义
0x41一把钥匙
0x42B键
0x43C键
0x44D键
0x45E键
0x46F键
0x47G键
0x48H键
0x49I 键
0x4AJ 键
0x4BK键
0x4CL键
0x4DM键
0x4EN键
0x4FO键
0x50P键
0x51Q键
0x52R键
0x53S 键
0x54T键
0x55U键
0x56V键
0x57W键
0x58X键
0x59Y 键
0x5AZ键
VK_LWIN0x5B左 Windows 键
VK_RWIN0x5C右 Windows 键
VK_APPS0x5D应用程序密钥
-0x5E保留
VK_SLEEP0x5F计算机睡眠键
VK_NUMPAD00x60数字键盘 0 键
VK_NUMPAD10x61数字键盘 1 键
VK_NUMPAD20x62数字键盘 2 键
VK_NUMPAD30x63数字键盘 3 键
VK_NUMPAD40x64数字键盘 4 键
VK_NUMPAD50x65数字键盘 5 键
VK_NUMPAD60x66数字键盘 6 键
VK_NUMPAD70x67数字键盘 7 键
VK_NUMPAD80x68数字键盘 8 键
VK_NUMPAD90x69数字键盘 9 键
VK_MULTIPLY0x6A乘法键
VK_ADD0x6B添加密钥
VK_SEPARATOR0x6C分隔键
VK_SUBTRACT0x6D减去键
VK_DECIMAL0x6E十进制键
VK_DIVIDE0x6F分割键
VK_F10x70F1 键
VK_F20x71F2 键
VK_F30x72F3 键
VK_F40x73F4 键
VK_F50x74F5 键
VK_F60x75F6 键
VK_F70x76F7 键
VK_F80x77F8 键
VK_F90x78F9 键
VK_F100x79F10 键
VK_F110x7AF11 键
VK_F120x7BF12 键
VK_F130x7CF13 键
VK_F142岳F14 键
VK_F150x7EF15 键
VK_F160x7FF16 键
VK_F170x80F17 键
VK_F180x81F18 键
VK_F190x82F19 键
VK_F200x83F20 键
VK_F210x84F21 键
VK_F220x85F22 键
VK_F230x86F23 键
VK_F240x87F24 键
-0x88-8楼保留
VK_NUMLOCK0x90NUM LOCK 键
VK_SCROLL0x91SCROLL LOCK键
-0x92-96OEM 特定
-0x97-9楼未分配
VK_LSHIFT0xA0左 SHIFT 键
VK_RSHIFT0xA1右 SHIFT 键
VK_LCONTROL0xA2左 CONTROL 键
VK_RCONTROL0xA3右 CONTROL 键
VK_LMENU0xA4左 Alt 键
VK_RMENU0xA5右 Alt 键
VK_BROWSER_BACK0xA6浏览器后退键
VK_BROWSER_FORWARD0xA7浏览器转发键
VK_BROWSER_REFRESH0xA8浏览器刷新键
VK_BROWSER_STOP0xA9浏览器停止键
VK_BROWSER_SEARCH0xAA浏览器搜索键
VK_BROWSER_FAVORITES0xAB浏览器收藏夹键
VK_BROWSER_HOME0xAC浏览器“开始”和“主页”键
VK_VOLUME_MUTE0xAD音量静音键
VK_VOLUME_DOWN0xAE降低音量键
VK_VOLUME_UP0xAF音量调高键
VK_MEDIA_NEXT_TRACK0xB0下一曲目键
VK_MEDIA_PREV_TRACK0xB1上一页 Track 键
VK_MEDIA_STOP0xB2停止媒体键
VK_MEDIA_PLAY_PAUSE0xB3播放/暂停媒体键
VK_LAUNCH_MAIL0xB4启动邮件密钥
VK_LAUNCH_MEDIA_SELECT0xB5选择媒体密钥
VK_LAUNCH_APP10xB6启动应用程序 1 键
VK_LAUNCH_APP20xB7启动应用程序 2 键
-0xB8-B9型保留
VK_OEM_10xBA用于杂项字符;它可能因键盘而异。对于美标键盘,按键;:
VK_OEM_PLUS0xBB对于任何国家/地区,关键+
VK_OEM_COMMA0xBC对于任何国家/地区,关键,
VK_OEM_MINUS0xBD对于任何国家/地区,关键-
VK_OEM_PERIOD0xBE对于任何国家/地区,关键.
VK_OEM_20xBF用于杂项字符;它可能因键盘而异。对于美标键盘,按键/?
VK_OEM_30xC0用于杂项字符;它可能因键盘而异。对于美标键盘,按键`~
-0xC1-DA保留
VK_OEM_40xDB用于杂项字符;它可能因键盘而异。对于美标键盘,按键[{
VK_OEM_50xDC用于杂项字符;它可能因键盘而异。对于美标键盘,按键\\|
VK_OEM_60xDD用于杂项字符;它可能因键盘而异。对于美标键盘,按键]}
VK_OEM_70xDE用于杂项字符;它可能因键盘而异。对于美标键盘,按键'"
VK_OEM_80xDF用于杂项字符;它可能因键盘而异。
-0xE0保留
-0xE1OEM 特定
VK_OEM_1020xE2美国标准键盘上的键,或非美国 102 键键盘上的键<>\\|
-0xE3-E4型OEM 特定
VK_PROCESSKEY0xE5IME PROCESS 密钥
-0xE6OEM 特定
VK_PACKET0xE7用于传递 Unicode 字符,就好像它们是击键一样。键是用于非键盘输入法的 32 位虚拟键值的低位字。有关详细信息,请参阅 KEYBDINPUT、SendInput、WM_KEYDOWN 和 WM_KEYUP 中的备注VK_PACKET
-0xE8未分配
-0xE9-F5型OEM 特定
VK_ATTN0xF6收件人键
VK_CRSEL0xF7CrSel 密钥
VK_EXSEL0xF8ExSel 密钥
VK_EREOF0xF9擦除EOF密钥
VK_PLAY0xFA播放键
VK_ZOOM0xFB缩放键
VK_NONAME0xFC保留
VK_PA10xFDPA1 密钥
VK_OEM_CLEAR0xFE清除键

 对于左键,如果按了左键还要判断现在方向是不是朝右,然后才能把方向改为左边,因为朝右是绝对改变不了方向为左边的

if (KEY_PRESS(VK_LEFT) && ps->Dir != right)
	ps->Dir = left;

 对于右键,如果按了右键还要判断现在方向是不是朝左,然后才能把方向改为右边,因为朝左是绝对改变不了方向为右边的

if (KEY_PRESS(VK_RIGHT) && ps->Dir != left)
	ps->Dir = right;

方向为上和下也是同理,不能产生冲突

if (KEY_PRESS(VK_UP) && ps->Dir != down)
    ps->Dir = up;
if (KEY_PRESS(VK_DOWN) && ps->Dir != up)
    ps->Dir = down; 

 具体方向键的移动另外做了一个函数snakemove(ps);

方向键设置完了,现在设置功能键 

我是打算把空格键设置为暂停,Sleep是修眠函数,可以设置一个死循环,如果按了空格键就进入循环休眠,再按一次空格键就break跳出循环停止休眠。这样就达到暂停的效果了

if (KEY_PRESS(VK_SPACE))
{
	while (1)
	{
		Sleep(200);
		if (KEY_PRESS(VK_SPACE))
			break;
	}
}

然后是退出ESC键,只需要在按这个键的时候,把状态从ok改为end就行了

if (KEY_PRESS(VK_ESCAPE))
	ps->statues = end;
if (KEY_PRESS(VK_F4))
{
	if (ps->sleeptime < 350)
	{
		ps->sleeptime += 20;
		ps->foodweight -= 2;
		if (ps->sleeptime >= 350)
		{
			ps->foodweight = 1;
		}
	}
}

snakemove移动函数

上面解决了按键问题,现在来解决一下按键对应的移动。先新建一个nextnode节点,这是下一步产生的节点

对于按了左键来说(一般此时都是向上或者向下的状态按左键),nextnode的x坐标要蛇头节点x-2,因为每次都是蛇头移动,而纵坐标y是保持不变的。

if (ps->Dir == left)
{
	nextnode->x = ps->psnake->x - 2;
	nextnode->y = ps->psnake->y;
}

对于按了右键来说(一般此时也都是向上或者向下的状态按右键),而nextnode的x坐标是加2,y轴依旧是不变的

if (ps->Dir == right)
{
	nextnode->x = ps->psnake->x + 2;
	nextnode->y = ps->psnake->y;
}

对于按了上键来说(一般此时蛇方向是向左或者向右状态),此时nextnode的x轴是不变的,y轴-1就可以了

if (ps->Dir == up)
{
	nextnode->y = ps->psnake->y - 1;
	nextnode->x = ps->psnake->x;
}

对于按了下键来说(一般此时蛇方向是向左或者向右状态),此时nextnode的x轴是不变的,y轴+1就可以了

if (ps->Dir == down)
{
	nextnode->y = ps->psnake->y + 1;
	nextnode->x = ps->psnake->x;
}

解决了下一个节点的坐标问题,然后来考虑下一个节点正好是食物节点以及不是食物节点的情况。判断是否是食物节点很好判断,直接if (nextnode->x == ps->pfood->x && nextnode->y == ps->pfood->y)

对于下一个节点是食物,我另外做了一个函数eatfood();如果下一个节点是食物,那直接头插法插进蛇身链表就可以了,同时蛇头变为这个食物节点,然后以新的食物节点作为头结点打印蛇身。  完了之后,因为吃了食物,所以总分数score要加上食物的分数foodweight。最后删除原有的食物节点,重新初始化一个食物节点

void eatfood(Snake* ps, snakenode* nextnode)
{
	nextnode->next= ps->psnake;
	ps->psnake =nextnode;
	snakenode* cur = ps->psnake;//头插食物节点
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;//打印蛇身
	}
	ps->score += ps->foodweight;//分数更新
	free(ps->pfood);//释放旧的食物节点
	foodInit(ps);//新建食物节点
}//吃食物

对于下一个位置不是食物节点,首先下一个位置也要成为新头节点,然后打印蛇身,但是最后一个节点要打印空格,这样看上去就像删除了最后一个节点一样。

void notfood(Snake*ps, snakenode*nextnode)
{
	nextnode->next = ps->psnake;
	ps->psnake = nextnode;
	snakenode* cur = ps->psnake;
	while (cur->next->next)//找到最后一个节点
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	setpos(cur->next->x, cur->next->y);
	printf("  ");//这个空格是两个空格
	free(cur->next);
	cur->next = NULL;
}

撞墙机制

因为我之前已经枚举了游戏状态,有一个状态是killbywall,所以只有判断蛇头是不是和四面墙的坐标重叠,你也可以是刚碰到墙不是重叠就判断撞墙

void _killbywall(Snake* ps)
{
	if (ps->psnake->x== 0 || ps->psnake->x == 54 || ps->psnake->y == 0 || ps->psnake->y == 27)
		ps->statues = killbywall;
}//撞墙

咬到自己机制 

同样也是用蛇头去判断,我选取的是蛇头的next节点以及之后的节点,作为咬到的判断条件。然后把状态改成killbyself

void _killbyself(Snake* ps)
{
	snakenode* cur = ps->psnake->next;
	while (cur)
	{
		if (ps->psnake->x == cur->x && ps->psnake->y == cur->y)
		{
			ps->statues = killbyself;
			break;
		}
		cur = cur->next;
	}
}//咬到自己

整个游戏的运行阶段就结束了,因为F3和F4按键是运行阶段设置的,所以我把打印分数和食物分数放到了 gamerun(Snake* ps)函数里,同时要注意的是每次按键都要设置休眠时间,不然的话会卡顿。

游戏运行阶段的全部代码如下,从下往上看

//游戏运行阶段

void _killbywall(Snake* ps)
{
	if (ps->psnake->x== 0 || ps->psnake->x == 54 || ps->psnake->y == 0 || ps->psnake->y == 27)
		ps->statues = killbywall;
}//撞墙

void _killbyself(Snake* ps)
{
	snakenode* cur = ps->psnake->next;
	while (cur)
	{
		if (ps->psnake->x == cur->x && ps->psnake->y == cur->y)
		{
			ps->statues = killbyself;
			break;
		}
		cur = cur->next;
	}
}//咬到自己

void eatfood(Snake* ps, snakenode* nextnode)
{
	nextnode->next= ps->psnake;
	ps->psnake =nextnode;
	snakenode* cur = ps->psnake;//头插食物节点
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;//打印蛇身
	}
	ps->score += ps->foodweight;//分数更新
	free(ps->pfood);//释放旧的食物节点
	foodInit(ps);//新建食物节点
}//吃食物

void notfood(Snake*ps, snakenode*nextnode)
{
	nextnode->next = ps->psnake;
	ps->psnake = nextnode;
	snakenode* cur = ps->psnake;
	while (cur->next->next)//找到最后一个节点
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	setpos(cur->next->x, cur->next->y);
	printf("  ");//这个空格是两个空格
	free(cur->next);
	cur->next = NULL;
}
void snakemove(Snake* ps)
{
	snakenode* nextnode = (snakenode*)malloc(sizeof(snakenode));
	if (ps->Dir == left)
	{
		nextnode->x = ps->psnake->x - 2;
		nextnode->y = ps->psnake->y;
	}
	if (ps->Dir == right)
	{
		nextnode->x = ps->psnake->x + 2;
		nextnode->y = ps->psnake->y;
	}
	if (ps->Dir == up)
	{
		nextnode->y = ps->psnake->y - 1;
		nextnode->x = ps->psnake->x;
	}
	if (ps->Dir == down)
	{
		nextnode->y = ps->psnake->y + 1;
		nextnode->x = ps->psnake->x;
	}

	if (nextnode->x == ps->pfood->x && nextnode->y == ps->pfood->y)
		eatfood(ps, nextnode);
	else
	{
		notfood(ps, nextnode);
	}
	_killbywall(ps);
	_killbyself(ps);
}

void gamerun(Snake* ps)
{
	do
	{
		setpos(61, 8);
		printf("总分:%3d", ps->score);
		setpos(70, 8);
		printf("食物的分数:%02d", ps->foodweight);
		if (KEY_PRESS(VK_LEFT) && ps->Dir != right)
			ps->Dir = left;
		if (KEY_PRESS(VK_RIGHT) && ps->Dir != left)
			ps->Dir = right;
		if (KEY_PRESS(VK_UP) && ps->Dir != down)
			ps->Dir = up;
		if (KEY_PRESS(VK_DOWN) && ps->Dir != up)
			ps->Dir = down;


		if (KEY_PRESS(VK_SPACE))
		{
			while (1)
			{
				Sleep(200);
				if (KEY_PRESS(VK_SPACE))
					break;
			}
		}

		if (KEY_PRESS(VK_ESCAPE))
			ps->statues = end;
		if (KEY_PRESS(VK_F3))
		{
			if (ps->sleeptime >=50)
			{
				ps->sleeptime -= 20;
				ps->foodweight += 2;
			}
		}
		if (KEY_PRESS(VK_F4))
		{
			if (ps->sleeptime < 350)
			{
				ps->sleeptime += 20;
				ps->foodweight -= 2;
				if (ps->sleeptime >= 350)
				{
					ps->foodweight = 1;
				}
			}
		}
		Sleep(ps->sleeptime);
		snakemove(ps);
	} while (ps->statues == ok);
}

四.游戏结束阶段

游戏结束阶段就是收尾阶段,把各种死亡原因打印一下,告知为什么死的,然后释放蛇身节点

void endgame(Snake* ps)
{
	if (ps->statues==end)
	{
		setpos(20, 13);
		printf("您主动已经退出了游戏\n");
	}
	else if (ps->statues == killbyself)
	{
		setpos(20, 13);
		printf("您咬到了自己\n");
	}
	else if (ps->statues == killbywall)
	{
		setpos(20, 13);
		printf("您撞墙了\n");
	}

	while (ps->psnake)
	{
		snakenode* cur = ps->psnake->next;
		free(ps->psnake);
		ps->psnake = cur;
	}
	ps = NULL;
}//游戏结束阶段

然后我还在main那里加了一个循环以便于重新开始游戏

#include"贪食蛇的声明.h"
void text()
{
	char ch = 0;
	do
	{
	setlocale(LC_ALL, "");
	gamestart();
	Snake ps = {0};//里面的成员先全赋值为0
	snakeInit(&ps);
	foodInit(&ps);
	gamerun(&ps);
	endgame(&ps);
	setpos(20, 15);
	printf("再来一局吗?(Y/N):");//Y是重新开始
	scanf("%c", &ch);
	getchar();// 清理\n
} while (ch == 'Y' || ch == 'y');
}
int main()
{
		srand((unsigned int)time(NULL));
		text();
}

五.贪食蛇完整代码

测试.c文件代码

#include"贪食蛇的声明.h"
void text()
{
	char ch = 0;
	do
	{
	setlocale(LC_ALL, "");
	gamestart();
	Snake ps = {0};//里面的成员先全赋值为0
	snakeInit(&ps);
	foodInit(&ps);
	gamerun(&ps);
	endgame(&ps);
	setpos(20, 15);
	printf("再来一局吗?(Y/N):");//Y是重新开始
	scanf("%c", &ch);
	getchar();// 清理\n
} while (ch == 'Y' || ch == 'y');
}
int main()
{
		srand((unsigned int)time(NULL));
		text();
}

贪食蛇的声明.h文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)
#include<stdio.h>
#include<windows.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>
#define wall L'□'
#include<stdlib.h>
#define BODY L'■'
#define FOOD L'★'
void setpos(int x, int y);
void gamestart();

enum statue
{
	ok = 1,
	end,
	killbywall,//撞墙
	killbyself//咬到自己
};

enum direction
{
	up=1,
	down,
	left,
	right
};
typedef  struct snakenode
{
	int x;
	int y;
	struct snakenode* next;
}snakenode;//蛇身节点和食物节点

typedef struct snakegame
{
	snakenode* psnake;//蛇身体节点
	snakenode *pfood;//食物节点
	int score;//总分
	int foodweight;//食物分数
	enum statue statues;//游戏状态
	enum direction Dir;//方向
	int sleeptime;//睡眠时间
}Snake;//维护蛇的结构体

void snakeInit(Snake* ps);
void foodInit(Snake* ps);
void gamerun(Snake* ps);
void snakemove(Snake* ps);
void endgame(Snake* ps);

贪食蛇的实现.h代码

#include"贪食蛇的声明.h"
void setpos(int x, int y)
{
	COORD pos = { x,y };
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(houtput, pos);

}
void welcome()
{
	setpos(40, 10);
	printf("欢迎来到贪食蛇小游戏\n");
	setpos(43, 15);
	system("pause");
	system("cls");//清屏
	setpos(38, 10);
	printf("用 ↑ ↓ → ←键操作蛇\n");
	setpos(38, 13);
	printf("f3表示加速,f4表示减速,加速能得到更多的分数");
	setpos(38, 18);
	system("pause");
	system("cls");
	
}
void createmap()
{
	for (int i = 0; i < 56; i += 2)
	{
		setpos(i, 0);
		wprintf(L"%lc", wall);
	}//打印第一个横着的墙
	for (int i = 1; i < 28; i++)
	{
		setpos(0, i);
		wprintf(L"%lc", wall);
	}//打印最左边竖着的墙
	for (int i = 2; i < 56; i += 2)
	{
		setpos(i, 27);
		wprintf(L"%lc", wall);
	}//最下面横着的墙
	for (int i = 1; i < 27; i++)
	{
		setpos(54, i);
		wprintf(L"%lc", wall);
	}
	setpos(61, 10);
	printf("用 ↑ ↓ → ←键操作蛇\n");
	setpos(61, 12);
	printf("f3表示加速,f4表示减速\n");
	setpos(61, 15);
	printf("加速能得到更多的分数\n");//打印墙体旁边的提示信息
	setpos(61, 17);
	printf("esc键退出游戏\n");
	setpos(61, 19);
	printf("空格键暂停\n");
}

void gamestart()
{
	system("title 贪食蛇");
	system("mode con cols=100 lines=30");
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO Info;
	GetConsoleCursorInfo(houtput, &Info);//获取光标控制台信息
	Info.bVisible = 0;//隐藏光标
	SetConsoleCursorInfo(houtput, &Info);//把修改后的结果设置回去
	welcome();
	createmap();
}

void snakeInit(Snake* ps)
{
	
	for (int i = 0; i <10; i+=2)
	{
		snakenode* cur = (snakenode*)malloc(sizeof(snakenode));
		if (ps->psnake == NULL)
		{
			cur->next = ps->psnake;
			ps->psnake = cur;
		}
		else
		{
			cur->next = ps->psnake;
			ps->psnake = cur;
		}
		cur->x = 24 + i;
		cur->y = 5;//设置cur的x和y坐标
		setpos(cur->x, cur->y);//在cur坐标上打印蛇的身体
		wprintf(L"%lc", BODY);
	}
	ps->Dir = right;//方向
	ps->foodweight = 10;//一个食物的分数
	ps->score = 0;//总分
	ps->sleeptime = 200;//休眠时间
	ps->statues = ok;//游戏状态
}//蛇身节点初始化

void foodInit(Snake* ps)
{
	int x; int y;
again:
	do {
		x = rand()%51 + 2;
		y = rand()%26 + 1;//控制节点坐标生成在墙内

	} while (x % 2 != 0);//宽字符x必须是2的倍数


	snakenode* cur = ps->psnake;
	while (cur)
	{
		if (x == cur->x &&y == cur->y)//判断生成的坐标是否是蛇身节点
			goto again;//如果是蛇身节点那么就跳转回上面重新生成x,y
		cur = cur->next;
	}


	ps->pfood = (snakenode*)malloc(sizeof(snakenode));//pfood是维护食物节点的指针
	ps->pfood->x = x; ps->pfood->y = y;
	setpos(ps->pfood->x, ps->pfood->y);
	wprintf(L"%lc", FOOD);
}//食物节点初始化



//游戏运行阶段

void _killbywall(Snake* ps)
{
	if (ps->psnake->x== 0 || ps->psnake->x == 54 || ps->psnake->y == 0 || ps->psnake->y == 27)
		ps->statues = killbywall;
}//撞墙

void _killbyself(Snake* ps)
{
	snakenode* cur = ps->psnake->next;
	while (cur)
	{
		if (ps->psnake->x == cur->x && ps->psnake->y == cur->y)
		{
			ps->statues = killbyself;
			break;
		}
		cur = cur->next;
	}
}//咬到自己

void eatfood(Snake* ps, snakenode* nextnode)
{
	nextnode->next= ps->psnake;
	ps->psnake =nextnode;
	snakenode* cur = ps->psnake;//头插食物节点
	while (cur)
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;//打印蛇身
	}
	ps->score += ps->foodweight;//分数更新
	free(ps->pfood);//释放旧的食物节点
	foodInit(ps);//新建食物节点
}//吃食物

void notfood(Snake*ps, snakenode*nextnode)
{
	nextnode->next = ps->psnake;
	ps->psnake = nextnode;
	snakenode* cur = ps->psnake;
	while (cur->next->next)//找到最后一个节点
	{
		setpos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	setpos(cur->next->x, cur->next->y);
	printf("  ");//这个空格是两个空格
	free(cur->next);
	cur->next = NULL;
}
void snakemove(Snake* ps)
{
	snakenode* nextnode = (snakenode*)malloc(sizeof(snakenode));
	if (ps->Dir == left)
	{
		nextnode->x = ps->psnake->x - 2;
		nextnode->y = ps->psnake->y;
	}
	if (ps->Dir == right)
	{
		nextnode->x = ps->psnake->x + 2;
		nextnode->y = ps->psnake->y;
	}
	if (ps->Dir == up)
	{
		nextnode->y = ps->psnake->y - 1;
		nextnode->x = ps->psnake->x;
	}
	if (ps->Dir == down)
	{
		nextnode->y = ps->psnake->y + 1;
		nextnode->x = ps->psnake->x;
	}

	if (nextnode->x == ps->pfood->x && nextnode->y == ps->pfood->y)
		eatfood(ps, nextnode);
	else
	{
		notfood(ps, nextnode);
	}
	_killbywall(ps);
	_killbyself(ps);
}

void gamerun(Snake* ps)
{
	do
	{
		setpos(61, 8);
		printf("总分:%3d", ps->score);
		setpos(70, 8);
		printf("食物的分数:%02d", ps->foodweight);
		if (KEY_PRESS(VK_LEFT) && ps->Dir != right)
			ps->Dir = left;
		if (KEY_PRESS(VK_RIGHT) && ps->Dir != left)
			ps->Dir = right;
		if (KEY_PRESS(VK_UP) && ps->Dir != down)
			ps->Dir = up;
		if (KEY_PRESS(VK_DOWN) && ps->Dir != up)
			ps->Dir = down;


		if (KEY_PRESS(VK_SPACE))
		{
			while (1)
			{
				Sleep(200);
				if (KEY_PRESS(VK_SPACE))
					break;
			}
		}

		if (KEY_PRESS(VK_ESCAPE))
			ps->statues = end;
		if (KEY_PRESS(VK_F3))
		{
			if (ps->sleeptime >=50)
			{
				ps->sleeptime -= 20;
				ps->foodweight += 2;
			}
		}
		if (KEY_PRESS(VK_F4))
		{
			if (ps->sleeptime < 350)
			{
				ps->sleeptime += 20;
				ps->foodweight -= 2;
				if (ps->sleeptime >= 350)
				{
					ps->foodweight = 1;
				}
			}
		}
		Sleep(ps->sleeptime);
		snakemove(ps);
	} while (ps->statues == ok);
}
void endgame(Snake* ps)
{
	if (ps->statues==end)
	{
		setpos(20, 13);
		printf("您主动已经退出了游戏\n");
	}
	else if (ps->statues == killbyself)
	{
		setpos(20, 13);
		printf("您咬到了自己\n");
	}
	else if (ps->statues == killbywall)
	{
		setpos(20, 13);
		printf("您撞墙了\n");
	}

	while (ps->psnake)
	{
		snakenode* cur = ps->psnake->next;
		free(ps->psnake);
		ps->psnake = cur;
	}
	ps = NULL;
}//游戏结束阶段

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

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

相关文章

通过 docker-compose 部署 Flink

概要 通过 docker-compose 以 Session Mode 部署 flink 前置依赖 Docker、docker-composeflink 客户端docker-compose.yml version: "2.2" services:jobmanager:image: flink:1.17.2ports:- "8081:8081"command: jobmanagervolumes:- ${PWD}/checkpoin…

JSDoc 注释规范

JSDoc 注释 在 前端项目中&#xff0c;注释格式包含了一些特殊标记&#xff0c;如 param、returns 等&#xff0c;这种注释通常是用来标记函数或方法的参数和返回值的数据类型和描述。 这种注释格式通常被称为 JSDoc 注释。在实际开发中&#xff0c;这样的注释可以被一些工具解…

[总结]HTML+JS逆向混淆混合

国外的题果然考得与众不同 [secrypt_cen.html] 这次是HTML网页&#xff0c;然后JS加密判断 翻看JS代码 {width"5.75in" height"3.375in"} 很显然&#xff0c;关键的代码在checkPassword JS混淆是必备的 去混淆一条龙走起 先将关键代码提取出来 JavaScriptf…

Java项目使用jasypt加密和解密配置文件中关键信息

一、使用背景 项目中application.yml 配置文件中&#xff0c;如数据库、redis、加密算法的私钥等各种配置的username&#xff0c;password的值都是明文的&#xff0c;其实存在一定的安全隐患&#xff0c;如果被人拿到这些配置文件&#xff0c;将直接对系统安全构成极大威胁&…

Python库-PyAutoGUI

pyautogui是一个Python库&#xff0c;可以自动控制键盘和鼠标&#xff0c;非常适合进行自动化任务。它可以用于各种场景&#xff0c;比如自动化测试、数据录入任务&#xff0c;甚至是简单的游戏机器人。下面是一个关于pyautogui的入门教程&#xff0c;包括它的安装、基本使用方…

Hadoop-IDEA开发平台搭建

1.安装下载Hadoop文件 1&#xff09;hadoop-3.3.5 将下载的文件保存到英文路径下&#xff0c;名称一定要短。否则容易出问题&#xff1b; 2&#xff09;解压下载下来的文件&#xff0c;配置环境变量 3&#xff09;我的电脑-属性-高级设置-环境变量 4.详细配置文件如下&#…

python-分享篇-屏保计时器

文章目录 代码效果 代码 import turtle, time def drawGap():turtle.penup()turtle.fd(5) def drawLine(draw):drawGap()turtle.pendown() if draw else turtle.penup()turtle.fd(40)drawGap()turtle.right(90) def drawDigit(d):drawLine(True) if d in [2,3,4,5,6,8,9] else…

一台Mac同时安装vue2和vue3

背景&#xff1a;电脑需要运行vue2和vue3项目&#xff0c;就得同时有vue2和vue3环境&#xff0c;之前以配置好vue2了&#xff0c;现在增加vue3 1. 新建一个安装vue3的目录 进入vue3文件夹安装vue3 // 注意这里没有参数-g&#xff0c;因为-g全局安装的命令 npm install vue/cli…

laravel distinct查询问题,laravel子查询写法

直接调用后&#xff0c;count查询会和实际查询的数据对不上&#xff0c;count还是查询全部数据&#xff0c;而实际的列表是去重的。 给distinct加上参数&#xff0c;比如去重的值的id&#xff0c;就加id。 另一种写法是使用group by id 子查询。 sql语句&#xff1a; selec…

介绍 MSTest Runner – CLI、Visual Studio 等

作者&#xff1a;Amaury Lev Marco Rossignoli Jakub Jareš 排版&#xff1a;Alan Wang 我们很高兴推出 MSTest 运行器&#xff0c;这是一款全新的轻量级 MSTest 测试运行器。这个新的运行器使测试更加便携和可靠&#xff0c;运行速度更快&#xff0c;并且具有可扩展性&#x…

如何安装x11vnc并结合cpolar实现win远程桌面Deepin

文章目录 1. 安装x11vnc2. 本地远程连接测试3. Deepin安装Cpolar4. 配置公网远程地址5. 公网远程连接Deepin桌面6. 固定连接公网地址7. 固定公网地址连接测试 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff…

【C++】基础知识讲解(命名空间、缺省参数、重载、输入输出)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 命名空间 命名空间的定义 命名空间的使用 命名空间的嵌套使用 C输入&输出 std命名空间的使用惯例&…

穿越周期,海信稳居全球第二的底气和底盘

【潮汐商业评论/原创】 颠覆创新&#xff0c;凡墙皆是门&#xff0c;而因循守旧&#xff0c;凡门皆是墙。 面对充满不确定性的时代&#xff0c;用什么驱散迷雾走向增长&#xff1f;这是当下中国大部分企业所面临的困惑。 选择用什么答案来应对这个问题&#xff0c;也决定了企…

stable-diffusion | v1-5-pruned.ckpt和v1-5-pruned-emaonly.ckpt的区别

https://github.com/runwayml/stable-diffusion?tabreadme-ov-file#reference-sampling-script 对于 1.5 模型&#xff0c;其中可能包括四部分&#xff1a;标准模型、文本编码器、VAE模型、EMA模型。 标准模型&#xff1a;生成图片的核心模块&#xff0c;潜空间中的前向扩散和…

【Django】Django中的缓存

缓存 1 缓存的定义 定义&#xff1a;缓存是一类可以更快的读取数据的介质统称&#xff0c;也指其他可以加快数据读取的存储方式&#xff0c;一般用来存储临时数据&#xff0c;常用介质的是读取速度很快的内存。 意义&#xff1a;视图渲染有一定成本&#xff0c;数据库的频繁查…

电力负荷预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型(结合时间序列)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型(结合时间序列) 所谓预测,就是指通过对事物进行分析及研究,并运用合理的方法探索事物的发展变化规律,对其未来发展做出预先估计和判断…

UE4 C++创建摄像机摇臂和相机并且设置Transform

新建MyPawn C类 .h #include "GameFramework/SpringArmComponent.h" //SpringArm组件 #include "Camera/CameraComponent.h" //Camera组件class 工程名称_API AMyPawn : public APawn { //定义组件变量 public:UPROPERTY(VisibleAnywhere, BlueprintRead…

【数据库原理及应用】简答题归纳总结

第一章 数据库概论 1.人工管理阶段数据管理的特点&#xff1a; &#xff08;1&#xff09;数据不保存在机器中 &#xff08;2&#xff09;无专用的软件对数据进行管理 &#xff08;3&#xff09;只有程序的概念&#xff0c;没有文件的概念 &#xff08;4&#xff09;数据面向程…

2024-02-06 TCP/UDP work

1. 画出TCP三次握手和四次挥手的示意图&#xff0c;并且总结TCP和UDP的区别 三次握手&#xff1a; 4次挥手&#xff1a; tcp/udp区别 TCP 1. 稳定&#xff0c;提供面向连接的&#xff0c;可靠的数据传输服务 2. 传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、…

在 Docker 中启动 ROS2 里的 rivz2 和 rqt 出现错误的解决方法

1. 出现错误&#xff1a; 运行 ros2 run rivz2 rivz2 &#xff0c;报错如下 &#xff1a; No protocol specified qt.qpa.xcb: could not connect to display :1 qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was f…