贪吃蛇项目:GameRun与GameEnd部分:游戏的主体运行与善后部分

news2024/12/29 7:43:41

准备工作:打印得分信息

            在进行GameStart之前,我们需要在地图的右侧打印帮助信息,以及目前玩家的得分情况和一个食物在当前速度下的得分情况(加速的状态下按比例增加食物的分数,减速的状态下则相反),至于打印的方法,在上两篇文章中已经介绍完毕,这里我们直接给出实现代码:

void GameIntroduction()
{
	Set_Pos(65, 10);
	wprintf(L"↑ ↓ ← →进行移动\n");
	Set_Pos(65, 11);
	wprintf(L"退出游戏请按Esc\n");
	Set_Pos(65, 12);
	wprintf(L"暂停请按空格\n");
	Set_Pos(65, 13);
	wprintf(L"小键盘1,2键加减速\n");
}

void ScoreStat(pSnake ps)
{
	REPOSITION(63, 8);
	wprintf(L"当前总分数%d", ps->_Socre);
	REPOSITION(63, 7);
	wprintf(L"当前速度一个食物分数为%d", ps->_foodWeight);
}

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
	} while (ps->_Status == OK);
}

           打印获得的成绩放在循环里面,则是因为每次玩家按完加减速之后,得分的权重都会改变,要实时更新。而我们的介绍信息则只需要打印一遍。

一,键位检测的实现

在此之前,我们要先定义一个宏:

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

            这里我们只需要知道它能检测键位是否被按过即可,不做过多介绍,如果想更为细节的了解,可以参考官网的解释:getAsyncKeyState 函数 (winuser.h) - Win32 apps | Microsoft Learn

接下来我们用多个if-else语句来实现玩家按下不同键位时的检测:

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
	} while (ps->_Status == OK);
}

           这里当玩家按上键时调整蛇的方向为上,但如果此时方向朝下调整方向为上,就会使蛇自己咬住自己。左右方向也是同理。下面为实现的暂停函数(Pause):

void Pause()
{
	while (!KEY_PRESS(VK_SPACE))
	{
		Sleep(200);
	}
}

当玩家在此按下空格键时,我们结束暂停的状态。

           当然,在每次检测完后,用Sleep函数暂停一下,至于暂停的时间,其实就是根据蛇的移动速度来设置:

Sleep(ps->_SleepTime);

二,蛇的移动函数的实现

2.1下一个位置节点的初始化

           我们这里使用SnakeMove来命名我们的移动函数。由于我们的链表需要使用malloc开辟,所以我们需要用malloc来开辟蛇的下一个位置的节点,当然在开辟完成后,我们还需要检验开辟是否成功:

	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}

           我们已经知道,控制台的长宽之比为1 :2,所以,如果接下来蛇往左移动,则他的x坐标则需要增加两个字符位置,向上向下则只需要移动y一个字符位置即可:

NextNode->x = ps->_pSnake->x;
NextNode->y = ps->_pSnake->y;
NextNode->next = NULL;
switch (ps->_Dir)
{
	case RIGHT:
    {
		NextNode->x += 2;
		NextNode->y += 0;
		break;
	}
	case LEFT:
	{
		NextNode->x -= 2;
		NextNode->y += 0;
		break;
	}
	case UP:
	{
		NextNode->x += 0;
		NextNode->y += 1;
		break;
	}
	case DOWN:
	{
		NextNode->x += 0;
		NextNode->y -= 1;
		break;
	}
}

2.2判断下一个位置是否为食物

           接下来如果下一个位置为食物,或不为食物,我们也需要检测,首先我们设置一个函数NestIsFood来检验下一个位置是否为食物:

int NextIsFood(pSnakeNode psn, pSnake ps)
{
	return(psn->x == ps->_pFood->x && psn->y == ps->_pFood->y);
}

           直接返回值即可,如果下一个位置为食物,我们用EatFood函数将蛇的长度加一,否则我们使用NoFood来让蛇移动一格:

void EatFood(pSnake ps, pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		Set_Pos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Socre += ps->_foodWeight;
	free(ps->_pFood);
	FoodInit(ps);
}
void NoFood(pSnake ps, pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		Set_Pos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	REPOSITION(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

           这里我们说明一下NoFood函数中打印两个空格的原因,因为我们的蛇是通过打印移动的,所以当我们把NextNode节点接到蛇头上时,我们需要把最后一个节点删除,但仔细思考一下,上回打印蛇身的字符是否还会保留,这会使它遗留在屏幕上。所以我们要打印两个空格(因为我们的蛇身为宽字符占两个字节)将其从屏幕上抹除。

2.3判断蛇是否咬住自身或撞墙

           这里我们用两个函数KillByWall,KillBySelf来分别表示蛇是否撞墙,蛇是否咬住自己。是否撞墙我们只需要判断蛇头位置是否与墙体位置重合,而是否咬住自己只需要判断蛇头位置是否与自身的其他部分重合:

int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if ((ps->_pSnake->x == cur->x) && (ps->_pSnake->y == cur->y))
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

int KillByWall(pSnake ps)
{
	if ((ps->_pSnake->x == 0) || (ps->_pSnake->x == 56) || (ps->_pSnake->y == 0) || (ps->_pSnake->y == 26))
	{
		ps->_Status = KILL_BY_WALL;
		return 1;
	}
	return 0;
}

           其实设置为void类型也可以,不过为了区分情况,方便起见,我用返回1或0来区分是否撞墙(咬自己)。

2.4GameRun部分代码

void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

2.5SnakeMove部分代码

void SnakeMove(pSnake ps)
{
	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}
	NextNode->x = ps->_pSnake->x;
	NextNode->y = ps->_pSnake->y;
	NextNode->next = NULL;
	switch (ps->_Dir)
	{
		case RIGHT:
	    {
			NextNode->x += 2;
			NextNode->y += 0;
			break;
		}
		case LEFT:
		{
			NextNode->x -= 2;
			NextNode->y += 0;
			break;
		}
		case UP:
		{
			NextNode->x += 0;
			NextNode->y += 1;
			break;
		}
		case DOWN:
		{
			NextNode->x += 0;
			NextNode->y -= 1;
			break;
		}
	}
	if (NextIsFood(NextNode,ps))
	{
		EatFood(ps, NextNode);
	}
	else
	{
		NoFood(NextNode,ps);
	}

	KillByWall(ps);
	KillBySelf(ps);
}

三,GameEnd部分

           这一部分其实没有什么好说的,因为我们上面的代码已经将蛇的状态信息设置好了,所以我们这里只需要根据上面储存进去的信息来打印我们目前的游戏状态即可:

void GameEnd(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake;
	Set_Pos(24, 12);
	switch (ps->_Status)
	{
	case END_NOMAL:
		printf("你主动退出游戏\n");
		break;
	case KILL_BY_SELF:
		printf("你咬到自己了 ,游戏结束!\n");
		break;
	case KILL_BY_WALL:
		printf("你撞墙了,游戏结束!\n");
		break;
	}
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

四,完整游戏代码

4.1Snake.h

#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <windows.h>
#include <stdlib.h>
#include <locale.h>
#include <time.h>

#define WALL L'□'
#define FOOD L'★'
#define BODY L'●'
#define POS_X 24
#define POS_Y 5

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

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

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

void REPOSITION(short x, short y);//调整输入的光标位置

void WelcomeMenu();//设置欢迎与介绍菜单

void GameMap();//设置游戏地图

void GameIntroduction();//设置在游戏过程中的提醒

void GameStart(pSnake ps);//游戏的初始化

void SnakeInit(pSnake ps);//蛇身的初始化

void FoodInit(pSnake ps);//初始化食物

void GameRun(pSnake ps);//游戏主体运行部分

void ScoreStat(pSnake ps);//分数统计

void Pause();//空格暂停

void SnakeMove(pSnake ps);//控制蛇移动的函数

int NextIsFood(pSnakeNode psn, pSnake ps);//判断下一个位置是否为食物

void EatFood(pSnake ps, pSnakeNode psn);//是食物的情况下吃掉食物

void NoFood(pSnakeNode psn, pSnake ps);//非食物的情况下进行移动

int KillBySelf(pSnake ps);

int KillByWall(pSnake ps);

void GameEnd(pSnake ps);

4.2Snake.c

           这里面的设置位置函数是REPOSITION(这是我第一遍做成功的代码,至于文章里面Set_Pos是我为了写文章又重新写了一遍代码)。

#include "snake.h"

void REPOSITION(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput,pos);
}

void WelcomeMenu()
{
	REPOSITION(35, 10);
	wprintf(L"欢迎来到贪吃蛇小游戏");
	REPOSITION(35, 20);
	system("pause");
	system("cls");
	REPOSITION(35, 10);
	wprintf(L"按 ↑ ↓ ← →键操控贪吃蛇移动\n");
	REPOSITION(35, 11);
	wprintf(L"按小键盘‘1’或‘2’键加速或减速\n");
	REPOSITION(35, 12);
	wprintf(L"Tips:加速吃食物有额外分数加成");
	REPOSITION(35, 20);
	system("pause");
	system("cls");
}


void GameMap()
{
	REPOSITION(0, 0);
	int i = 0;
	for (; i < 58; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	REPOSITION(0, 26);
	for (i = 0; i < 58; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		REPOSITION(0, i);
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i < 26; i++)
	{
		REPOSITION(56, i);
		wprintf(L"%lc", WALL);
	}
}


void GameIntroduction()
{
	REPOSITION(65, 10);
	wprintf(L"↑ ↓ ← →进行移动\n");
	REPOSITION(65, 11);
	wprintf(L"退出游戏请按Esc\n");
	REPOSITION(65, 12);
	wprintf(L"暂停请按空格\n");
	REPOSITION(65, 13);
	wprintf(L"小键盘1,2键加减速\n");
}


void GameStart(pSnake ps)
{
	srand((unsigned int)time(NULL));
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo = { 25,false };
	SetConsoleCursorInfo(houtput, &CursorInfo);
	WelcomeMenu();
	GameMap();
	SnakeInit(ps);
	FoodInit(ps);
}

void SnakeInit(pSnake ps)
{
	int i = 0;
	pSnakeNode cur = NULL;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("SnakeInit():malloc()cur:");
			return;
		}
		cur->next = NULL;
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		if (ps->_pSnake == NULL)
		{
			ps->_pSnake = cur;
		}
		else
		{
			cur->next = ps->_pSnake;
			ps->_pSnake = cur;
		}
	}
	cur = ps->_pSnake;
	while (cur)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Dir = RIGHT;
	ps->_foodWeight = 10;
	ps->_SleepTime = 300;
	ps->_Socre = 0;
	ps->_Status = OK;
}


void FoodInit(pSnake ps)
{
	int x = 0;
	int y = 0;
	again:
	do
	{
		x = rand()%53 + 2;
		y = rand()%24 + 1;
	} while (x % 2 != 0);
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		goto again;
		cur = cur->next;
	}
	pSnakeNode cur2 = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (cur2 == NULL)
	{
		perror("malloc():FoofInit:cur2:");
		return;
	}
	cur2->next = NULL;
	cur2->x = x;
	cur2->y = y;
	REPOSITION(x, y);
	wprintf(L"%lc", FOOD);
	ps->_pFood = cur2;
	cur2 = NULL;
}

void ScoreStat(pSnake ps)
{
	REPOSITION(63, 8);
	wprintf(L"当前总分数%d", ps->_Socre);
	REPOSITION(63, 7);
	wprintf(L"当前速度一个食物分数为%d", ps->_foodWeight);
}

void Pause()
{
	while (!KEY_PRESS(VK_SPACE))
	{
		Sleep(200);
	}
}

int NextIsFood(pSnakeNode psn, pSnake ps)
{
	return(psn->x == ps->_pFood->x && psn->y == ps->_pFood->y);
}

void EatFood(pSnake ps,pSnakeNode psn)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Socre += ps->_foodWeight;
	free(ps->_pFood);
	FoodInit(ps);
}

void NoFood(pSnakeNode psn,pSnake ps)
{
	psn->next = ps->_pSnake;
	ps->_pSnake = psn;
	pSnakeNode cur = ps->_pSnake;
	while (cur->next->next)
	{
		REPOSITION(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	REPOSITION(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);
	cur->next = NULL;
}

int KillByWall(pSnake ps)
{
	if ((ps->_pSnake->x == 0)|| (ps->_pSnake->x == 56)|| (ps->_pSnake->y == 0)|| (ps->_pSnake->y == 26))
	{
		ps->_Status = KILL_BY_WALL;
		return 1;
	}
	return 0;
}

int KillBySelf(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake->next;
	while (cur)
	{
		if ((ps->_pSnake->x == cur->x)&& (ps->_pSnake->y == cur->y))
		{
			ps->_Status = KILL_BY_SELF;
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

void SnakeMove(pSnake ps)
{
	pSnakeNode NextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (NextNode == NULL)
	{
		perror("malloc():SnakeMove:NextNode");
		return;
	}
	NextNode->x = ps->_pSnake->x;
	NextNode->y = ps->_pSnake->y;
	NextNode->next = NULL;
	switch (ps->_Dir)
	{
		case RIGHT:
	    {
			NextNode->x += 2;
			NextNode->y += 0;
			break;
		}
		case LEFT:
		{
			NextNode->x -= 2;
			NextNode->y += 0;
			break;
		}
		case UP:
		{
			NextNode->x += 0;
			NextNode->y += 1;
			break;
		}
		case DOWN:
		{
			NextNode->x += 0;
			NextNode->y -= 1;
			break;
		}
	}
	if (NextIsFood(NextNode,ps))
	{
		EatFood(ps, NextNode);
	}
	else
	{
		NoFood(NextNode,ps);
	}

	KillByWall(ps);
	KillBySelf(ps);
}


void GameRun(pSnake ps)
{
	GameIntroduction();
	do
	{
		ScoreStat(ps);
		if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = DOWN;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = UP;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_NUMPAD1))
		{
			if (ps->_SleepTime > 100)
			{
				ps->_SleepTime -= 50;
				ps->_foodWeight += 2;
			}
		}
		else if (KEY_PRESS(VK_NUMPAD2))
		{
			if (ps->_SleepTime < 500)
			{
				ps->_SleepTime += 50;
				ps->_foodWeight -= 2;
			}
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			ps->_Status = END_NOMAL;
			break;
		}
		Sleep(ps->_SleepTime);
		SnakeMove(ps);
	} while (ps->_Status == OK);
}

void GameEnd(pSnake ps)
{
	pSnakeNode cur = ps->_pSnake;
	REPOSITION(24, 12);
	switch (ps->_Status)
	{
	case END_NOMAL:
		printf("你主动退出游戏\n");
		break;
	case KILL_BY_SELF:
		printf("你咬到自己了 ,游戏结束!\n");
		break;
	case KILL_BY_WALL:
		printf("你撞墙了,游戏结束!\n");
		break;
	}
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}

4.3test.c

#include "snake.h"

void test()
{
	int ch = 0;
	do
	{
		Snake snake = { 0 };
		GameStart(&snake);//游戏初始化
		GameRun(&snake);//游戏运行
		GameEnd(&snake);//游戏的善后处理
		REPOSITION(20, 15);
		printf("再来一局吗?(y/n):");
		ch = getchar();
		getchar();
	} while (ch == 'y');
	system("cls");
}

int main()
{
	setlocale(LC_ALL, "");
	test();
	return 0;
}

           贪吃蛇的内容到这里就完结了,至于下一次更新要到7月10号左右了(一是过暑假了想摸会鱼,二是在c语言准备开数据结构的新坑),我们下篇文章见。

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

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

相关文章

历史与未来的交响曲:历史建筑保护与现代技术的完美融合

在时间的长河中&#xff0c;历史建筑如同凝固的诗篇&#xff0c;记录着过往的辉煌与沧桑。然而&#xff0c;岁月的侵蚀、自然灾害的威胁以及现代化进程的冲击&#xff0c;使这些宝贵的文化遗产面临前所未有的挑战。作为建筑设计领域的探索者&#xff0c;我们肩负着保护历史记忆…

多空分歧中,盘点全球“新股王”背后的这些在港概念股

冲榜成功。6月18日收盘&#xff0c;英伟达(NVDA.US)股价创新高&#xff0c;报135.58美元&#xff0c;总市值3.34万亿美元&#xff0c;一举超越微软、苹果公司&#xff0c;成为全球“新股王”。 不过&#xff0c;随着这一历史性时刻的出现&#xff0c;由于当前无法准确预估市场…

vue配置中的process.env

项目中的.env开头的文件是否知道是干什么的呢 主要是为了区分测试环境还是生产环境env.development为测试环境 # 测试环境 NODE_ENV development VUE_APP_BASE_API http://xxxxxxxxx // 命名一定要以 VUE_APP_ 开头&#xff0c;要不然根本取不到 .env.production为生产环境…

浏览器扩展V3开发系列之 chrome.runtime 的用法和案例

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 chrome.runtime API 提供了一系列的方法和事件&#xff0c;可以通过它来管理和维护 Chrome 扩展的生命…

用两个钟,我又在VMWARE上搞了一套内部网配置

最近要学es&#xff0c;所以打算自己用虚拟机搞个NAT&#xff0c;又搞了两个钟。为了不再费劲尝试&#xff0c;也为了造福大众&#xff0c;所以选择搞一份NAT笔记&#xff01;&#xff01;&#xff01;&#xff01; 1.初始化网关和DNS 我们给网关配置一个地址192.168.96.1&…

计算机图形学入门20:加速光线追踪

1.前言 前文说了Whitted-style光线追踪技术的原理以及光线与平面的交点计算方式&#xff0c;对于现在应用最广的Polygon Mesh显式曲面来说&#xff0c;一个复杂场景中的多边形面总数可能达到千万甚至亿万以上&#xff0c;如果每个像素发射光线都和场景中每个平面进行求交点计算…

植物大战僵尸杂交版v2.1最新直装版,苹果+安卓+PC+防闪退工具+修改工具+高清工具+通关存档整合包更新

今天我要和各位聊聊一款让全网疯狂的游戏——《植物大战僵尸杂交版》。这可不是简单的游戏&#xff0c;它可是让B站的UP主“潜艇伟伟迷”一夜成名的大作&#xff0c;让无数玩家为之疯狂的魔改神作&#xff01; 记得2009年&#xff0c;《植物大战僵尸》横空出世&#xff0c;那时…

SpringBoot优点达项目实战:登录功能实现(四)

SpringBoot优点达项目实战&#xff1a;登录功能实现&#xff08;四&#xff09; 文章目录 SpringBoot优点达项目实战&#xff1a;登录功能实现&#xff08;四&#xff09;1、查看接口2、查看数据库3、代码实现1、创建实体类2、controller实现3、service层实现4、Mapper层 4、测…

IPFoxy Tips:匿名海外代理IP的使用方法及注意事项

在互联网上&#xff0c;隐私和安全问题一直备受关注。为了保护个人隐私和数据安全&#xff0c;使用匿名代理IP是一种常用的方法。匿名代理IP可以隐藏用户的真实IP地址&#xff0c;使用户在访问网站时更加隐秘和安全。 本文将介绍匿名代理IP的基本原理和核心功能。 基本原则 匿…

Power BI 占比函数

1&#xff0c;普通层级结构占比 占比1 DIVIDE([sum_qty], CALCULATE([sum_qty],ALLSELECTED(Item[ITEM_CODE]))) //按照line为一个整理展示数据占比2 SWITCH( true(),ISINSCOPE(Item[ITEM_CODE]),DIVIDE([sum_qty], CALCULATE([sum_qty],ALLSELECTED(Item[ITEM_CODE]))), IS…

前端 CSS 经典:mix-blend-mode 属性

前言&#xff1a;这是一个混合属性&#xff0c;作用是将两个颜色混合生成一个新颜色。可以将视频和文字相融合&#xff0c;产生动态文字效果。 效果 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" />&l…

数据资产风险管理与合规性:全面识别、科学评估并有效应对数据风险,确保企业数据资产的安全性与合规性,为企业稳健发展提供坚实保障

一、引言 在数字化时代&#xff0c;数据资产已成为企业运营和决策的核心要素。然而&#xff0c;随着数据量的快速增长和技术的不断演进&#xff0c;数据资产面临的风险也日益增多&#xff0c;如数据泄露、数据篡改、数据滥用等。同时&#xff0c;数据保护法律法规的不断完善&a…

文华财经盘立方均线-支撑压力自动画线多空声音预警指标公式源码

文华财经盘立方多空均线-支撑压力自动画线指标公式源码&#xff1a; //MA5:MA(C,5); //MA10:MA(C,10); MA20:MA(C,20),COLORRED; MA60:MA(C,60),COLORGREEN; TY:CLOSE; HD:FILTER(BACKSET(FILTER(REF(TY,10)HHV(TY,2*101),10),101),10); LD:FILTER(BACKSET(FILTER(REF(T…

PatchMixer:一种用于长时间序列预测的Patch混合架构

前言 《PatchMixer: A Patch-Mixing Architecture for Long-Term Time Series Forecasting》原文地址&#xff0c;Github开源代码地址GitHub项目地址Some-Paper-CN。本项目是译者在学习长时间序列预测、CV、NLP和机器学习过程中精读的一些论文&#xff0c;并对其进行了中文翻译…

jdk1.8升级到jdk11遇到的各种问题

一、第三方依赖使用了BASE64Decoder 如果项目中使用了这个类 sun.misc.BASE64Decoder&#xff0c;就会导致错误&#xff0c;因为再jdk11中&#xff0c;该类已经被删除。 Caused by: java.lang.NoClassDefFoundError: sun/misc/BASE64Encoder 当然这个类也有替换方式&#xf…

一本好的电子画册应这样做,你做对了吗?

​一本好的电子画册&#xff0c;不仅要有吸引人的图文&#xff0c;还可能包括视频、音频等多媒体元素&#xff0c;为读者提供全方位的阅读体验。连贯性是指画册的整体设计风格、内容布局要协调一致&#xff0c;让读者在阅读过程中感受到流畅和自然。创新性则要求创作者在内容呈…

【别再用Excel了!】这款免费可视化工具能帮你轻松提升效率

现代数据分析和展示的需求已经远远超出了传统工具的能力&#xff0c;尤其是在需要快速、直观和高效地处理复杂数据的情况下。山海鲸可视化通过其强大的功能和易用性&#xff0c;成为了设计师以及各类新手用户的理想选择。下面我就以一个可视化设计师的角度&#xff0c;和大家简…

月入稳定还是创业冒险:你的选择决定未来

大家好&#xff0c;我是汇舟问卷。在现在这个环境下&#xff0c;无论是就业还是创业都不好做。在传统就业与创业之间的选择时&#xff0c;我们应避免一概而论或过度推崇某一方向。 事实上&#xff0c;并非所有人都适合创业&#xff0c;对于那些满足于稳定工作&#xff0c;每月…

深入理解计算机系统 CSAPP 家庭作业7.13

用一下496页提到的工具咯 A: whereis libm.a file lidm.a gedit libm.a libm.a是个ASCII text文件打开一看原来 libm-2.27.a 和libmvec.a才是我们要看的 所以我们cd到目标地址后 ar -t libm-2.27.a ar -t libmvec.a B: gcc -Og bar5.c foo5.c 用之前的两个文件链接后生成…

电脑复制按哪个键?还不会操作的赶紧来看!

当我们提到“电脑复制按哪个键”时&#xff0c;实际上是在讨论电脑键盘上用于执行复制操作的快捷键。复制功能在日常的电脑操作中极为常用&#xff0c;无论是文本编辑、文件处理还是图片操作&#xff0c;都离不开复制这一基本功能。以下&#xff0c;我们将深入探讨电脑复制操作…