109. UE5 GAS RPG 实现检查点的存档功能

在这一篇文章里,我们接着实现存档的功能,保存当前玩家的生成位置,游戏里有很多中方式去实现玩家的位置存储,这里我们采用检查点的方式,当玩家接触到当前检查点后,我们可以通过检查点进行保存玩家的状态,后续也能够实现检查点移动玩家等等功能。

实现定义角色生成位置

存档加载关卡后,需要一个出生位置,如果场景里有多个PlayerStart,我们如何确定让角色在哪个PlayerStart生成呢?
答案是,我们可以为每个PlayerStart设置标签,然后覆写GameMode的选择初始点的函数来实现。

首先,我们实现对数据的全局存储,这里需要使用到GameInstance,我们将其作为父类,实现一个派生类,来实现自定义的需求。
在这里插入图片描述
设置自定义命名
在这里插入图片描述
在类里,我们存储几个值,一个是切换关卡时需要获取的PlayerStart的标签命名,另外就是如果需要保存,所需的存档名称和索引。

UCLASS()
class RPG_API URPGGameInstance : public UGameInstance
{
	GENERATED_BODY()

public:

	//角色进入关卡后默认生成的PlayerStart的Tag
	UPROPERTY()
	FName PlayerStartTag = FName();

	//当前使用的或后续保存内容到的存档名称
	UPROPERTY()
	FString LoadSlotName = FString();

	//当前使用活后续保存的存档索引
	UPROPERTY()
	int32 LoadSlotIndex = 0;
};

然后在我们自定义的GameMode里增加一个参数用于设置玩家生成的PlayerStart的标签

	//角色切换关卡后默认生成位置的PlayerStart的标签
	UPROPERTY(EditDefaultsOnly)
	FName DefaultPlayerStartTag;

	//覆写父类的选择PlayerStart函数,修改为可以通过Tag获取生成位置
	virtual AActor* ChoosePlayerStart_Implementation(AController* Player) override;

函数实现这里,我们会获取到关卡里的所有的PlayerStart,然后从GameInstance获取需要生成的标签,遍历获取到对应的PlayerStart生成,所以,只需要在进入关卡前,将GameInstance的标签修改了然后进入场景时,就可以自动寻找对应的PlayerStart去生成。

AActor* ARPGGameMode::ChoosePlayerStart_Implementation(AController* Player)
{
	const URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());
	
	//获取关卡里的所有PlayerStart实例
	TArray<AActor*> Actors;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerStart::StaticClass(), Actors);
	
	if(Actors.Num() > 0)
	{
		//获取到第一个实例对象
		AActor* SelectedActor = Actors[0];
		for(AActor* Actor : Actors)
		{
			if(APlayerStart* PlayerStart = Cast<APlayerStart>(Actor))
			{
				//判断PlayerStart的Tag设置是否为指定的Tag
				if(PlayerStart->PlayerStartTag == RPGGameInstance->PlayerStartTag)
				{
					SelectedActor = PlayerStart;
					break;
				}
			}
		}
		return SelectedActor;
	}
	return nullptr;
}

添加PlayerStart标签配置

我们需要在存档里实现对关卡里的开始标签的存储,在读取存档进入关卡时,可以明确知道角色需要在哪里生成。
所以,我们需要在LoadScreenSaveMode(存档类)和存档ViewModel视图模型里增加PlayerStart标签配置属性。

	//存储玩家关卡出生位置的标签
	UPROPERTY()
	FName PlayerStartTag;

在创建新存档时,使用GameMode设置的默认PlayerStart标签
在这里插入图片描述
接着在GameMode存储存档时,将存档的视图模型的中的PlayerStart标签存储到存档
在这里插入图片描述
存储没问题了,就是读取存档时,将存档里存储的PlayerStart标签设置给存档的视图模型
在这里插入图片描述
最后,在我们在加载界面视图模型进入游戏的函数里,在调用加载关卡之前,将PlayerStart标签存储到GameInstance里,进入关卡后,然后再通过我们覆写的函数获取对应标签的PlayerStart

void UMVVM_LoadScreen::EnterGameButtonPressed(const int32 Slot)
{
	ARPGGameMode* RPGGameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this));

	//设置全局数据,方便后续使用
	URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(RPGGameMode->GetGameInstance());
	RPGGameInstance->LoadSlotName = LoadSlots[Slot]->GetSlotName();
	RPGGameInstance->LoadSlotIndex = LoadSlots[Slot]->SlotIndex;
	RPGGameInstance->PlayerStartTag = LoadSlots[Slot]->PlayerStartTag;

	//进入场景
	RPGGameMode->TravelToMap(LoadSlots[Slot]);
}

创建蓝图

接下来,我们编译打开UE,在BP_GameMode里设置默认选择的PlayerStart的标签
在这里插入图片描述
接着,我们基于GameInstance类创建一个蓝图
在这里插入图片描述
设置命名
在这里插入图片描述
在项目设置里,将默认的GameInstance修改为我们所需的GameInstance
在这里插入图片描述
最后,我们在场景里设置PlayerStart的标签,注意,如果多个PlayerStart设置了相同的对应的标签,角色将在第一个获取的PlayerStart的位置生成。
在这里插入图片描述

创建检查点

在正常游戏流程里,为了保存游戏进度,开发者会使用某种方式让进度保存下来,比如到达某个进度后自动保存,又或者像生化危机里的打字机。
这里,我们将实现一种检查点的类,在角色接触后,自动保存当前进度。
在这里插入图片描述
命名为检查点类,我们将在里面增加一些额外的内容。
在这里插入图片描述
在类里,我们将增加两个属性,用于显示检查点的模型和触发保存游戏的碰撞盒子

private:

	//检查点显示的模型
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<UStaticMeshComponent> CheckpointMesh;

	//检查点模型使用的碰撞体
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<USphereComponent> Sphere;

然后增加一个函数,用于玩家角色和碰撞球碰撞后的逻辑处理

	/**
	 * 球碰撞体和物体发生碰撞后的回调
	 * @param OverlappedComponent 发生重叠事件的自身的碰撞体对象
	 * @param OtherActor 目标的actor对象
	 * @param OtherComp 目标的碰撞体组件
	 * @param OtherBodyIndex 目标身体的索引
	 * @param bFromSweep 是否为瞬移检测到的碰撞
	 * @param SweepResult 如果位置发生过瞬移(直接设置到某处),两个位置中间的内容会记录到此对象内
	 */
	UFUNCTION()
	virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

接着增加一个函数,玩家角色碰撞后的函数处理,主要里面是创建了一个新的材质实例,修改自发光,表示检查点已经激活。

	//当玩家角色和检测点产生碰撞后,检查点被激活触发此函数
	void HandleGlowEffects();

由于自发光亮起需要时间轴,这个比较方便在蓝图里实现,我们再增加一个需蓝图实现的函数。

	/**
	 * 检查点激活后的处理,需要在蓝图中对其实现
	 * @param DynamicMaterialInstance 传入检查点模型的材质实例
	 */
	UFUNCTION(BlueprintImplementableEvent)
	void CheckpointReached(UMaterialInstanceDynamic* DynamicMaterialInstance);

以下是整个.h文件

// 版权归暮志未晚所有。

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerStart.h"
#include "CheckPoint.generated.h"

class USphereComponent;
/**
 * 
 */
UCLASS()
class RPG_API ACheckPoint : public APlayerStart
{
	GENERATED_BODY()

public:

	//构造函数
	ACheckPoint(const FObjectInitializer& ObjectInitializer);

protected:

	virtual void BeginPlay() override;
	
	/**
	 * 球碰撞体和物体发生碰撞后的回调
	 * @param OverlappedComponent 发生重叠事件的自身的碰撞体对象
	 * @param OtherActor 目标的actor对象
	 * @param OtherComp 目标的碰撞体组件
	 * @param OtherBodyIndex 目标身体的索引
	 * @param bFromSweep 是否为瞬移检测到的碰撞
	 * @param SweepResult 如果位置发生过瞬移(直接设置到某处),两个位置中间的内容会记录到此对象内
	 */
	UFUNCTION()
	virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	/**
	 * 检查点激活后的处理,需要在蓝图中对其实现
	 * @param DynamicMaterialInstance 传入检查点模型的材质实例
	 */
	UFUNCTION(BlueprintImplementableEvent)
	void CheckpointReached(UMaterialInstanceDynamic* DynamicMaterialInstance);

	//当玩家角色和检测点产生碰撞后,检查点被激活触发此函数
	void HandleGlowEffects();
private:

	//检查点显示的模型
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<UStaticMeshComponent> CheckpointMesh;

	//检查点模型使用的碰撞体
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<USphereComponent> Sphere;
};

在cpp里,我们对函数进行实现,首先在构造函数里,我们实例化模型和碰撞体。

ACheckPoint::ACheckPoint(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{
	//关闭帧更新
	PrimaryActorTick.bCanEverTick = false;

	//创建检测点显示模型
	CheckpointMesh = CreateDefaultSubobject<UStaticMeshComponent>("CheckpointMesh");
	CheckpointMesh->SetupAttachment(GetRootComponent());
	CheckpointMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); //设置查询并产生物理
	CheckpointMesh->SetCollisionResponseToChannels(ECR_Block); //设置阻挡所有物体与其重叠

	//设置球碰撞体
	Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
	Sphere->SetupAttachment(CheckpointMesh);
	Sphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly); //设置其只用作查询使用
	Sphere->SetCollisionResponseToChannels(ECR_Ignore); //设置其忽略所有碰撞检测
	Sphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); //设置其与Pawn类型物体产生重叠事件
}

在游戏开始时,绑定球碰撞体的重叠函数

void ACheckPoint::BeginPlay()
{
	Super::BeginPlay();

	//绑定重叠事件
	Sphere->OnComponentBeginOverlap.AddDynamic(this, &ACheckPoint::OnSphereOverlap);
}

接着实现重叠函数,在触发重叠时,我们需要实现保存当前的检查点标签,然后在调用碰撞后处理函数

void ACheckPoint::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	//if(OtherActor->ActorHasTag("Player")) //如果只需要判断是不是玩家角色通过标签判断即可
	if(OtherActor->Implements<UPlayerInterface>())
	{
		//修改存档当的检测点
		IPlayerInterface::Execute_SaveProgress(OtherActor, PlayerStartTag);
		
		//如果与碰撞体重叠的是
		HandleGlowEffects();
	}
}

然后我们取消碰撞检测,提升性能,并创建一个新的材质实例,调用蓝图函数实现渐变发光效果。

void ACheckPoint::HandleGlowEffects()
{
	//取消碰撞检查
	Sphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	//创建一个新材质实例,修改效果
	UMaterialInstanceDynamic* DynamicMaterialInstance = UMaterialInstanceDynamic::Create(CheckpointMesh->GetMaterial(0), this);
	CheckpointMesh->SetMaterial(0, DynamicMaterialInstance);
	CheckpointReached(DynamicMaterialInstance); //触发检查点修改材质后的回调
}

编译代码,打开UE,创建一个基于类的蓝图
在这里插入图片描述
在检测点里,我们需要修改碰撞体大小和检查点的模型
在这里插入图片描述
大致效果如下,可以按需设置
在这里插入图片描述
在平视角,我们需要将PlayerStart和模型水平,这样保证放置的时候,防止PlayerStart的位置靠下,生成角色生成到地面以下。
在这里插入图片描述
拖入场景中,点击End建,检测点将会自动附着到地面,青蓝色箭头是玩家在检查点生成位置和朝向,黄色碰撞球是激活检测点范围。
在这里插入图片描述
接着,我们修改材质,增加自发光相关节点,设置GlowEnd最大亮度,以及GlowControl来控制进度,GlowControl值为1时,将达到亮度的最大值。
在这里插入图片描述
接着,我们创建一个实例,去调节对应的参数。
在这里插入图片描述
接着,在蓝图里,实现碰撞函数回调,使用时间轴修改GlowControl
在这里插入图片描述
在时间轴里去修改更新的值
在这里插入图片描述
我们将放置到场景里的检查点的设置其标签,可以用来实现保存通过标签去寻找位置。
在这里插入图片描述

实现PlayerStart标签的保存

我们要实现玩家角色在场景中接触到检查点后,更新存档,将当前的检查点的值保存到存档里。
首先在GameMode类里增加两个函数,一个用于获取当前使用的存档,另一个是将修改后的存档保存下来。

	//获取到当前游戏进行中所使用的存档数据
	ULoadScreenSaveGame* RetrieveInGameSaveData() const;

	/**
	 * 保存游戏中的进度
	 * @param SaveObject 需要保存的数据
	 */
	void SaveInGameProgressData(ULoadScreenSaveGame* SaveObject) const;

实现这里,我们可以在GameInstance身上获取到存档使用的Name和Index,通过这两项获取到存档数据。
保存函数这里,我们还需要使用存档的标签去修改GameInstance身上的PlayerStart的标签。然后保存。

ULoadScreenSaveGame* ARPGGameMode::RetrieveInGameSaveData() const
{
	const URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());

	//从游戏实例获取到存档名称和索引
	const FString InGameLoadSlotName = RPGGameInstance->LoadSlotName;
	const int32 InGameLoadSlotIndex = RPGGameInstance->LoadSlotIndex;

	//获取已保存的存档数据
	return GetSaveSlotData(InGameLoadSlotName, InGameLoadSlotIndex);
}

void ARPGGameMode::SaveInGameProgressData(ULoadScreenSaveGame* SaveObject) const
{
	URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());

	//修改下一次复活的检测点
	RPGGameInstance->PlayerStartTag = SaveObject->PlayerStartTag;

	//从游戏实例获取到存档名称和索引
	const FString InGameLoadSlotName = RPGGameInstance->LoadSlotName;
	const int32 InGameLoadSlotIndex = RPGGameInstance->LoadSlotIndex;

	//保存存档
	UGameplayStatics::SaveGameToSlot(SaveObject, InGameLoadSlotName, InGameLoadSlotIndex);
}

接着在玩家角色接口这里增加一个函数,用于碰撞触发后保存存档使用

	//保存游戏进度
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
	void SaveProgress(const FName& CheckpointTag);

在玩家基类里覆写

virtual void SaveProgress_Implementation(const FName& CheckpointTag) override;

实现这里,我们获取到GameMode,然后获取存档,修改存档数据,并保存回去。

void ARPGHero::SaveProgress_Implementation(const FName& CheckpointTag)
{
	if(const ARPGGameMode* GameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this)))
	{
		//获取存档
		ULoadScreenSaveGame* SaveGameData = GameMode->RetrieveInGameSaveData();
		if(SaveGameData == nullptr) return;

		//修改存档数据
		SaveGameData->PlayerStartTag = CheckpointTag;

		//保存存档
		GameMode->SaveInGameProgressData(SaveGameData);
	}
}

我们在与检查点碰撞时,已经调用此函数,实现了存档的修改保存。
在这里插入图片描述
最后,我们在场景里多加几个检查点,来测试效果。创建文档,角色会生成在一个检查点上,然后我们走到另一个检查点上,重新进入游戏,查看角色下一次会不会生成在最后退出的检查点旁边,如果能够证明代码无误。
在这里插入图片描述

实现角色已经激活的检测点一直高亮

我们现在制作的当前检查点效果,还没有实现的一项是,让玩家已经激活的检查点一直保持高亮状态,这样,如果玩家迷路了,可以清除的得知这一段路之前探索过。
为了实现这个效果,我们需要将之前已经探索到的检查点都记录下来,然后在进入场景后,每次激活,将信息记录到存档里。在进入一个新关卡时,在GameMode的BeginPlayer会触发,我们会在此函数里处理检查点是否需要高亮。
首先,我们在SaveGame类增加一个参数,用于存储检查点数组,用于存储角色已经激活的检查点

	//当前已经激活的检测点
	UPROPERTY()
	TArray<FName> ActivatedPlayerStatTags = TArray<FName>();

然后将检查点类的激活函数修改为public,这样,可以在类以外调用
在这里插入图片描述
接着,我们增加一个私有函数用于高亮已经激活的检查点

private:
	
	//高亮已经激活的检查点
	void HighlightEnabledCheckpoints(TArray<AActor*> CheckPoints) const;

函数实现,我们将获取存档,并遍历所有的检查点,如果检查点的Tag存在于已激活的数组内,我们将检查点进行高亮显示。

void ARPGGameMode::HighlightEnabledCheckpoints(TArray<AActor*> CheckPoints) const
{
	//获取存档
	ULoadScreenSaveGame* SaveGameData = RetrieveInGameSaveData();
	if(SaveGameData == nullptr) return;

	//遍历关卡内的所有的检查点,如果数组里存在,将高亮显示
	for(AActor* Actor : CheckPoints)
	{
		if(ACheckPoint* CheckPoint = Cast<ACheckPoint>(Actor))
		{
			if(SaveGameData->ActivatedPlayerStatTags.Contains(CheckPoint->PlayerStartTag))
			{
				CheckPoint->HandleGlowEffects();
			}
		}
	}
}

在关卡打开后,生成角色时,我们调用此函数,进行场景关卡的检查点进行初始化高亮
在这里插入代码片
最后,还有保存已经激活的检查点,我们可以选择在保存角色的存档时候,将当前检查点的标签保存进去。
在这里插入图片描述
重点,你每个添加到关卡的检查点,要做到全局不同,也就是每个关卡的检查点都不要重名,我们可以考虑关卡+检查点的索引方式去设置检查点的tag。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浅谈电力行业网络安全与防护

3月7日&#xff0c;委内瑞拉发生迄今为止最大规模停电事件&#xff0c;让这个身处危机之中的国家雪上加霜。千里之堤溃于蚁穴&#xff0c;切莫忽视任何不安全因素的存在。电力基础设施薄弱&#xff0c;设备维护不到位&#xff0c;技术人员水平低下&#xff0c;工业控制系统防护…

UE5 第一人称射击项目学习(一)

因为工作需要&#xff0c;需要掌握ue5的操作。 选择了视频资料 UE5游戏制作教程Unreal Engine 5 C作为学习。 第一个目标是跟着视频制作出一款第一人称射击项目。 同时作为入门&#xff0c;这个项目不会涉及到C&#xff0c;而是一个纯蓝图的项目。 项目目标 这个项目将实…

Excel数据动态获取与映射

处理代码 动态映射 动态读取 excel 中的数据&#xff0c;并通过 json 配置 指定对应列的值映射到模板中的什么字段上 private void GetFreightFeeByExcel(string filePath) {// 文件名需要以快递公司命名 便于映射查询string fileName Path.GetFileNameWithoutExtension(fi…

博客文章怎么设计分类与标签

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;博客文章怎么设计分类与标签 新网站基本上算是迁移完了&#xff0c;迁移之后在写文章的过程中&#xff0c;发现个人的文章分类和标签做的太混乱了&#xff0c;分类做的像标签&#xff0c;标签也不是特别的丰富&#x…

solana链上智能合约开发案例一则

环境搭建 安装Solana CLI&#xff1a;Solana CLI是开发Solana应用的基础工具。你可以通过官方文档提供的安装步骤&#xff0c;在本地环境中安装适合你操作系统的Solana CLI版本。安装完成后&#xff0c;使用命令行工具进行配置&#xff0c;例如设置网络环境&#xff08;如开发网…

腾讯云存储COS上传视频报错

bug表现为&#xff1a;通过COS上传视频时报错"Class \"QCloud\\COSSTS\\Sts\" not found" 修复办法为&#xff1a;找到文件crmeb/services/upload/storage/Cos.php 将Sts引入由QCloud\COSSTS\Sts;改为crmeb\services\upload\extend\cos\Sts; 修改后重启服…

已有docker增加端口号,不用重新创建Docker

已有docker增加端口号&#xff0c;不用重新创建Docker 1. 整体描述2. 具体实现2.1 查看容器id2.2 停止docker服务2.3 修改docker配置文件2.4 重启docker服务 3. 总结 1. 整体描述 docker目前使用的非常多&#xff0c;但是每次更新都需要重新创建docker&#xff0c;也不太方便&…

Win11 24H2新BUG或影响30%CPU性能,修复方法在这里

原文转载修改自&#xff08;更多互联网新闻/搞机小知识&#xff09;&#xff1a; 一招提升Win11 24H2 CPU 30%性能&#xff0c;小BUG大影响 就在刚刚&#xff0c;小江在网上冲浪的时候突然发现了这么一则帖子&#xff0c;标题如下&#xff1a;基准测试&#xff08;特别是 Time…

C#桌面应用制作计算器

C#桌面应用制作简易计算器&#xff0c;可实现数字之间的加减乘除、AC按键清屏、Del按键清除末尾数字、/-按键取数字相反数、%按键使数字缩小100倍、按键显示运算结果等...... 页面实现效果 功能实现 布局 计算器主体使用Panel容器&#xff0c;然后将button控件排列放置Pane…

Cloud Native 云原生后端的开发注意事项

在云原生后端开发里&#xff0c;数据管理和存储这块得好好弄。数据库选型得综合考虑&#xff0c;像关系型数据有复杂查询需求就选 MySQL、PostgreSQL&#xff0c;海量非结构化数据就可以考虑 MongoDB、Cassandra 这些。设计数据库得遵循规范化原则&#xff0c;像设计电商订单表…

25.UE5时间膨胀,慢动作,切换地图,刷BOSS

2-27 时间膨胀、慢动作、切换地图、刷BOSS_哔哩哔哩_bilibili 目录 1.刷新BOSS逻辑 2.时间膨胀实现慢动作 3.胜利画面&#xff0c;下一关 3.1胜利画面UI 3.2第一关、第二关游戏模式 3.3下一关按钮事件的绑定 1.刷新BOSS逻辑 实现当场上的怪物都死亡后&#xff0c;进行刷…

汽车资讯新动力:Spring Boot技术革新

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车资讯网站的开发全过程。通过分析汽车资讯网站管理的不足&#xff0c;创建了一个计算机管理汽车资讯网站的方案。文章介绍了汽车资讯网站的系统分析部分&…

华为防火墙技术基本概念学习笔记

1.防火墙概述 1.1防火墙与交换机、路由器对比 路由器与交换机的本质是转发&#xff0c;防火墙的本质是控制。 防火墙与路由器、交换机是有区别的。路由器用来连接不同的网络&#xff0c;通过路由协议保证互联互通&#xff0c;确保将报文转发到目的地;交换机则通常用来组建局域…

Pytest-Bdd-Playwright 系列教程(12):步骤参数 parsers参数解析

Pytest-Bdd-Playwright 系列教程&#xff08;12&#xff09;&#xff1a;步骤参数 & parsers参数解析 前言一、什么是步骤参数&#xff1f;二、pytest-bdd 的步骤参数用法2.1 简单字符串解析2.2 自定义正则表达式解析2.3 参数类型转换 三、案例&#xff1a;基于 pytest-bdd…

EHOME视频平台EasyCVR多品牌摄像机视频平台监控视频编码H.265与Smart 265的区别?

在视频监控领域&#xff0c;技术的不断进步推动着行业向更高效、更智能的方向发展。特别是在编码技术方面&#xff0c;Smart 265作为一种新型的视频编码技术&#xff0c;相较于传统的H.265&#xff0c;有明显优势。这种技术的优势在EasyCVR视频监控汇聚管理平台中得到了充分的体…

利用redis的key失效监听器KeyExpirationEventMessageListener作任务定时提醒功能

某需求&#xff1a; 要求在任务截止日期的前3天时&#xff0c;系统自动给用户发一条消息提醒。 用定时任务的话感觉很不舒服。间隔时间不好弄。不能精准卡到那个点。 由于系统简单&#xff0c;没有使用消息列队&#xff0c;也不能使用延时队列来做。 用Timer的话开销还挺大的&a…

数造科技亮相第26届高交会并接受媒体采访,以数据智能赋能未来

11 月 14 日至 16 日&#xff0c;第二十六届中国国际高新技术成果交易会&#xff08;简称“高交会”&#xff09;在深圳成功举办。本届大会以“科技引领发展&#xff0c;产业融合聚变”为主题&#xff0c;汇聚了全球最新的科技成果&#xff0c;打造了一场科技界的盛大聚会。 在…

Facebook广告投放如何提高过审率?

在Facebook进行广告投放活动时&#xff0c;如何让广告过审应该是让很多人头疼的事情&#xff0c;前期花时间准备文案素材等&#xff0c;结果广告不过审&#xff0c;等于一切的前期准备都打水漂了&#xff0c;特别是黑五类的一些产品。许多独立站会架设斗篷&#xff0c;根据市场…

springBoot插件打包部署

打包插件spring-boot-maven-plugin 不使用插件&#xff0c;运行时&#xff0c;异常信息为“没有主清单属性” 本地部署 杀进程

VSCode+ESP-IDF开发ESP32-S3-DevKitC-1(2)第一个工程 LED心跳灯

VSCodeESP-IDF开发ESP32-S3-DevKitC-1&#xff08;2&#xff09;第一个工程 LED心跳灯 前言1.新建工程2.编写控制LED代码3.LED控制独立成.c和.h文件 前言 实际开发中很多时候我们需要有一个类似心跳灯或运行指示灯的灯以不同的状态闪烁以表示程序的运行状态&#xff0c;所以第…