111. UE5 GAS RPG 实现角色技能和场景状态保存到存档

实现角色的技能存档保存和加载

首先,我们在LoadScreenSaveGame.h文件里,增加一个结构体,用于存储技能相关的所有信息

//存储技能的相关信息结构体
USTRUCT(BlueprintType)
struct FSavedAbility
{
	GENERATED_BODY()

	//需要存储的技能
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="ClassDefaults")
	TSubclassOf<UGameplayAbility> GameplayAbility;

	//当前技能的等级
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
	int32 AbilityLevel = 0;

	//当前技能的标签
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
	FGameplayTag AbilityTag = FGameplayTag();

	//当前技能的状态标签
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
	FGameplayTag AbilityStatus = FGameplayTag();

	//当前技能装配到的插槽,如果技能未装配则为空
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
	FGameplayTag AbilityInputTag = FGameplayTag();

	//当前技能的类型(主动技能还是被动技能)
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
	FGameplayTag AbilityType = FGameplayTag();
};

然后重新设置==运算符的方法,如果我们在判断FSavedAbility是否相等时,会通过此函数运算返回布尔结果。

//自定义运算符==,如果左右都是FSavedAbility类型的值,将通过函数内的值判断是否相等。
inline bool operator==(const FSavedAbility& Left, const FSavedAbility& Right)
{
	return Left.AbilityTag.MatchesTagExact(Right.AbilityTag);
}

然后我们在SaveGame类里添加一个属性,用于保存所有技能属性。

	/************************** 技能 **************************/

	UPROPERTY()
	TArray<FSavedAbility> SavedAbilities;

有了相关数据可以存储到存档后,我们可以在角色保存时,实现保存技能相关数据。
在保存数据的时候,我们先将存档里的技能数组清空,然后使用RPGASC->ForEachAbility技能委托遍历所有应用到角色身上的技能,通过结构体设置技能数据,并通过AddUnique添加到数组(前面我们添加了operator==覆写了获取相等的设置)

void ARPGHero::SaveProgress_Implementation(const FName& CheckpointTag)
{
	if(const ARPGGameMode* GameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this)))
	{
		...

		SaveGameData->bFirstTimeLoadIn = false; //保存完成将第一次加载属性设置为false

		if(!HasAuthority()) return;

		URPGAbilitySystemComponent* RPGASC = Cast<URPGAbilitySystemComponent>(AbilitySystemComponent);
		SaveGameData->SavedAbilities.Empty(); //清空数组

		//使用ASC里创建的ForEach函数循环获取角色的技能,并生成技能结构体保存
		FForEachAbility SaveAbilityDelegate;
		SaveAbilityDelegate.BindLambda([this, RPGASC, SaveGameData](const FGameplayAbilitySpec& AbilitySpec)
		{
			//获取技能标签和
			const FGameplayTag AbilityTag = URPGAbilitySystemComponent::GetAbilityTagFromSpec(AbilitySpec);
			UAbilityInfo* AbilityInfo = URPGAbilitySystemLibrary::GetAbilityInfo(this);
			FRPGAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AbilityTag);

			//创建技能结构体
			FSavedAbility SavedAbility;
			SavedAbility.GameplayAbility = Info.Ability;
			SavedAbility.AbilityLevel = AbilitySpec.Level;
			SavedAbility.AbilityTag = AbilityTag;
			SavedAbility.AbilityStatus = RPGASC->GetStatusTagFromAbilityTag(AbilityTag);
			SavedAbility.AbilityInputTag = RPGASC->GetInputTagFromAbilityTag(AbilityTag);
			SavedAbility.AbilityType = Info.AbilityType;

			SaveGameData->SavedAbilities.AddUnique(SavedAbility);
		});
		//调用ForEach技能来执行存储到存档
		RPGASC->ForEachAbility(SaveAbilityDelegate);

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

ForEach技能就是传入一个委托,然后遍历所有的应用技能。
在这里插入图片描述
接着,在ASC里增加一个通过存档数据设置角色技能的函数。
我们遍历存储的技能,根据技能是主动技能还是被动技能,应用给角色。

void URPGAbilitySystemComponent::AddCharacterAbilitiesFormSaveData(ULoadScreenSaveGame* SaveGameData)
{
	for(const FSavedAbility& Data : SaveGameData->SavedAbilities)
	{
		const TSubclassOf<UGameplayAbility> LoadedAbilityClass = Data.GameplayAbility;

		FGameplayAbilitySpec LoadedAbilitySpec = FGameplayAbilitySpec(LoadedAbilityClass, Data.AbilityLevel);
		LoadedAbilitySpec.DynamicAbilityTags.AddTag(Data.AbilityInputTag); //设置技能激活输入标签
		LoadedAbilitySpec.DynamicAbilityTags.AddTag(Data.AbilityStatus); //设置技能状态标签

		//主动技能的处理
		if(Data.AbilityType == FRPGGameplayTags::Get().Abilities_Type_Offensive)
		{
			GiveAbility(LoadedAbilitySpec); //只应用不激活
		}
		//被动技能的处理
		else if(Data.AbilityType == FRPGGameplayTags::Get().Abilities_Type_Passive)
		{
			//确保技能已经装配
			if(Data.AbilityStatus.MatchesTagExact(FRPGGameplayTags::Get().Abilities_Status_Equipped))
			{
				GiveAbilityAndActivateOnce(LoadedAbilitySpec); //应用技能并激活
			}
			else
			{
				GiveAbility(LoadedAbilitySpec); //只应用不激活
			}
		}
	}

	bStartupAbilitiesGiven = true;
	AbilityGivenDelegate.Broadcast();
}

接下来,我们编译打开UE,查看现在角色身上装配的技能,这些技能我们保存需要技能对应的资产数据
在这里插入图片描述
接着,我们给一些不需要操作的被动技能添加标签,这个被动技能主要是监听属性加点,我们通过加点是,会发送事件,此技能会接受事件通过GE给角色增加属性值。
在这里插入图片描述
我们在技能的数据资产里增加对应的配置,由于不需要显示,我们不需要设置Icon
在这里插入图片描述
还有之前制作的眩晕技能也需要配置数据
在这里插入图片描述
删除多余的测试技能,就可以去测试。
在这里插入图片描述

处理加载时的一些bug

首先,第一个bug是我这边通过存档进入时,激活的技能不显示,这个问题的原因是初始化时,对应的面板控制器没有初始化,不使用存档时没这个问题是因为我们打开对应面板时进行的初始化。
解决方案是,在HUD初始化面板时,我们将对应的控制器都初始化一下即可
在这里插入图片描述
第二个问题,被动技能特效无法显示,出现这个问题的原因是因为在ASC通过存档初始化技能时,对应的被动技能效果组件还没有执行绑定监听,解决这个问题的方式是,我们在绑定监听时,调用一次即可。
在这里插入图片描述

实现保存场景状态

我们实现了对技能的保存,接下来,我们实现可以在存档里,将角色进入过的场景的状态也保存。
我们要在存档里保存场景的数据,首先在场景里创建对应的数据类型,对于场景的Actor,我们考虑使用结构体保存,并通过UE内置的序列器,进行对Actor的数据进行序列化存储到存档,并在使用的时候,通过反序列化,应用会角色身上。
这里,我们增加两个结构体,一个用于保存关卡场景里的Actor,另一个是保存所在的关卡,这样 ,我们可以通过进入的关卡,获取到对应关卡的Actor数据,并应用回去。

//保存场景中的Actor结构体
USTRUCT()
struct FSavedActor
{
	GENERATED_BODY()

	UPROPERTY()
	FName ActorName = FName();

	UPROPERTY()
	FTransform Transform = FTransform();

	//Actor身上序列号的数据,必须通过UPROPERTY定义过,只在保存存档时使用。
	UPROPERTY()
	TArray<uint8> Bytes;
};

//自定义运算符==,如果结构体内的ActorName相同,这代表这两个结构体为相同结构体
inline bool operator==(const FSavedActor& Left, const FSavedActor& Right)
{
	return Left.ActorName == Right.ActorName;
}

//地图相关数据保存
USTRUCT()
struct FSavedMap
{
	GENERATED_BODY()

	UPROPERTY()
	FString MapAssetName = FString();

	UPROPERTY()
	TArray<FSavedActor> SavedActors;
};

接着,我们在存档类里,添加一个属性,可以通过此属性可以获取到所有保存的关卡数据,并增加两个函数 ,用于获取对应的关卡数据和判断存档里是否有对应关卡的数据。

	UPROPERTY()
	TArray<FSavedMap> SavedMaps;

	//通过地图名称获取地图数据
	FSavedMap GetSavedMapWithMapName(const FString& InMapName);

	//判断存档是否含有对于地图数据
	bool HasMap(const FString& InMapName);

实现对应的函数,通过遍历判断名称来实现。

FSavedMap ULoadScreenSaveGame::GetSavedMapWithMapName(const FString& InMapName)
{
	for(const FSavedMap& Map : SavedMaps)
	{
		if(Map.MapAssetName == InMapName)
		{
			return Map;
		}
	}
	return FSavedMap();
}

bool ULoadScreenSaveGame::HasMap(const FString& InMapName)
{
	for(const FSavedMap& Map : SavedMaps)
	{
		if(Map.MapAssetName == InMapName)
		{
			return true;
		}
	}
	return false;
}

接着,我们增加一个新的接口,新的接口可以用于判断当前场景中的哪些Actor需要保存到存档里
在这里插入图片描述
我们命名新接口
在这里插入图片描述
需要保存的场景的Actor都需要继承此接口。
在这里插入图片描述
我们在接口里增加两个函数,一个是用于判断是否需要修改位置变换,这个功能可以在解密游戏里,解开机关后,开启了某扇密门后,将其保存起来,防止下次还需要继续重新开启。另一个是在从存档里读取数据后,更新Actor。

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

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "SaveInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class USaveInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class RPG_API ISaveInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:

	//设置Actor是否需要修改位置变换
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	bool ShouldLoadTransform();

	//在存档读取完数据后,调用更新Actor
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void LoadActor();
};

接着,我们修改检查点的类,我们需要将检查点的数据存储到存档里,这里增加了一个变量,用于判断当前检查点是否被激活,并且覆写继承接口的函数。我们不需要修改存档点的位置变换,这里直接返回false,如果像机关密门那种,则需要保存,我们可以设置为true。
将bReached,设置SaveGame时,如果我们将实例序列化存档数据时,它的值将会被存入到存档中,在反序列化时,将存档数据重新设置回来。

	/*   Save Interface   */
	virtual bool ShouldLoadTransform_Implementation() override { return false; } //是否需要修改变换,检查点不需要
	virtual void LoadActor_Implementation() override; //通过存档二进制修改Actor数据后,更新Actor
	/*   End Save Interface   */

	//当前检查点是否已经被激活,设置SaveGame表示该值将会被存储到存档文件中
	UPROPERTY(BlueprintReadOnly, SaveGame)
	bool bReached = false;

我们实现一下LoadActor函数,在从存档读取数据设置完Actor,调用它实现一些处理。

void ACheckPoint::LoadActor_Implementation()
{
	if(bReached)
	{
		HandleGlowEffects();
	}
}

实现场景状态的存储和读取

要实现场景状态的存储和读取,我们在GameMode里增加两个函数,分别处理存储和读取。

	//保存关卡中的状态到当前存档中
	void SaveWorldState(UWorld* World) const;
	//从存档中加载当前关卡的状态
	void LoadWorldState(UWorld* World) const;

首先我们实现对关卡的状态存储,这里说一下逻辑,首先获取到关卡名称,和游戏实例,游戏实例有存档的相关信息,获取到存档对象,判断对应关卡在存档内是否有对应的数据存储,如果没有,新创建一个。
然后获取到对应的关卡数据,将数据内存储的Actor数据清除,遍历关卡内的所有Actor,找到继承保存接口的Actor,创建一个对应Actor的存储数据结构体,通过FMemoryWriter将Actor身上需要保存到存档的数据设置到存档结构体内。
最后,将地图的数据存储到存档对象里。

void ARPGGameMode::SaveWorldState(UWorld* World) const
{
	//获取关卡名称
	FString WorldName = World->GetMapName();
	WorldName.RemoveFromStart(World->StreamingLevelsPrefix); //从关卡名称这里移除指定前缀,当前为移除通常用于标识流式加载的关卡文件前缀

	//获取到游戏实例
	URPGGameInstance* RPGGI = Cast<URPGGameInstance>(GetGameInstance());
	check(RPGGI);

	//获取存档
	if(ULoadScreenSaveGame* SaveGame = GetSaveSlotData(RPGGI->LoadSlotName, RPGGI->LoadSlotIndex))
	{
		if(!SaveGame->HasMap(WorldName))
		{
			//如果存档不包含对应关卡内容,将创建一个对应的数据结构体存储
			FSavedMap NewSavedMap;
			NewSavedMap.MapAssetName = WorldName;
			SaveGame->SavedMaps.Add(NewSavedMap);
		}

		//获取对应的存档关卡数据结构体
		FSavedMap SavedMap = SaveGame->GetSavedMapWithMapName(WorldName);
		SavedMap.SavedActors.Empty(); //存储的内容

		//使用迭代起,便利场景里的每一个Actor,将需要保存Actor数据保存到结构体内
		for(FActorIterator It(World); It; ++It)
		{
			AActor* Actor = *It;

			//判断Actor是否存在,并判断Actor是否需要存储
			if(!IsValid(Actor) || !Actor->Implements<USaveInterface>()) continue;

			//创建存储结构体
			FSavedActor SavedActor;
			SavedActor.ActorName = Actor->GetFName();
			SavedActor.Transform = Actor->GetTransform();

			//创建一个 FMemoryWriter,用于将数据写入SavedActor.Bytes
			FMemoryWriter MemoryWriter(SavedActor.Bytes);

			//创建一个序列化器,将对象的成员以名称和值的形式保存到 MemoryWriter。
			FObjectAndNameAsStringProxyArchive Archive(MemoryWriter, true);
			Archive.ArIsSaveGame = true; //设置序列化方式为保存到存档的模式

			//将Actor所需要保存的数据写入到Archive,Archive将把数据存储到SavedActor.Bytes
			Actor->Serialize(Archive);

			SavedMap.SavedActors.AddUnique(SavedActor);
		}

		//找到对应的名称的结构体,将数据存储到存档对象内
		for(FSavedMap& MapToReplace : SaveGame->SavedMaps)
		{
			if(MapToReplace.MapAssetName == WorldName)
			{
				MapToReplace = SavedMap;
			}
		}

		//保存存档
		UGameplayStatics::SaveGameToSlot(SaveGame, RPGGI->LoadSlotName, RPGGI->LoadSlotIndex);
	}
}

接着是加载关卡状态,我们通过关卡名称和游戏实例获取到存档实例,判断存档实例是否存在此关卡的存档数据。
如果存在此关卡数据,我们将遍历此关卡的所有Actor,如果Actor包含存储接口,我们将判断存档里是否存储了此Actor对应的数据,然后通过MemoryReader读取存档数据,进行反序列化,将数据应用回Actor。
最后通过接口函数,调用Actor更新自身状态。

void ARPGGameMode::LoadWorldState(UWorld* World) const
{
	//获取关卡名称
	FString WorldName = World->GetMapName();
	WorldName.RemoveFromStart(World->StreamingLevelsPrefix); //从关卡名称这里移除指定前缀,当前为移除通常用于标识流式加载的关卡文件前缀
	
	//获取到游戏实例
	URPGGameInstance* RPGGI = Cast<URPGGameInstance>(GetGameInstance());
	check(RPGGI);

	//判断获取的存档是否存在
	if(UGameplayStatics::DoesSaveGameExist(RPGGI->LoadSlotName, RPGGI->LoadSlotIndex))
	{
		//获取存档
		ULoadScreenSaveGame* SaveGame = Cast<ULoadScreenSaveGame>(UGameplayStatics::LoadGameFromSlot(RPGGI->LoadSlotName, RPGGI->LoadSlotIndex));
		if(SaveGame == nullptr)
		{
			UE_LOG(LogRPG, Error, TEXT("加载对应存档失败"));
		}

		//判断存档是否含有对应关卡的数据
		if(SaveGame->HasMap(WorldName))
		{
			//遍历场景内的所有Actor,寻找存档内对应的数据并应用到场景
			for(FActorIterator It(World); It; ++It)
			{
				AActor* Actor = *It;

				if(!Actor->Implements<USaveInterface>()) continue;

				//遍历存档里对应关卡的所有actor数据
				for(FSavedActor SavedActor : SaveGame->GetSavedMapWithMapName(WorldName).SavedActors)
				{
					//查找到对应的actor的存档数据
					if(SavedActor.ActorName == Actor->GetFName())
					{
						//判断当前Actor是否需要设置位置变换
						if(ISaveInterface::Execute_ShouldLoadTransform(Actor))
						{
							Actor->SetActorTransform(SavedActor.Transform);
						}

						//反序列化,创建一个FMemoryReader实例用于从二进制数据中读取内容
						FMemoryReader MemoryReader(SavedActor.Bytes);

						//FObjectAndNameAsStringProxyArchive 代理类,用于序列化和反序列化对象的属性 true:表示允许使用字符串形式的对象和属性名称(便于调试和可读性)。
						FObjectAndNameAsStringProxyArchive Archive(MemoryReader, true);
						Archive.ArIsSaveGame = true; //指定反序列化是用于加载存档数据。
						Actor->Serialize(Archive); //执行反序列化,将二进制数据设置到actor属性上

						//修改Actor上的属性后,调用函数更新Actor的显示
						ISaveInterface::Execute_LoadActor(Actor);
					}
				}
			}			
		}
	}
}

实现场景存储和读取

对应的函数实现了,最后一步,我们需要知道在什么时候存储和什么时候去读取。
存储我们选择在玩家角色激活检查点时,我们将bReached设置为true,并调用保存状态函数,将数据保存到关卡内。

void ACheckPoint::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	//if(OtherActor->ActorHasTag("Player")) //如果只需要判断是不是玩家角色通过标签判断即可
	if(OtherActor->Implements<UPlayerInterface>())
	{
		//设置当前检查点已被玩家激活
		bReached = true;

		if(ARPGGameMode* RPGGameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this)))
		{
			//保存场景状态
			RPGGameMode->SaveWorldState(GetWorld());
		}
		
		//修改存档当的检测点
		IPlayerInterface::Execute_SaveProgress(OtherActor, PlayerStartTag);
		
		//如果与碰撞体重叠的是
		HandleGlowEffects();
	}
}

在读取时,我们选择在玩家PossessedBy里,它将调用加载存档函数,我们将读取写在读取完技能之后,实现场景的加载。
在这里插入图片描述
最后,测试即可。

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

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

相关文章

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…

从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;二&#xff09;—— 深入探索 CSS 选择器的奥秘 前言一、CSS基本选择器1. 通配选择器2. 元素选择器3. 类选择器4. id选择器5.基本选择器总结 二、CSS复合选择器1. 后代选择器2. 子选择器3. 相邻兄弟选择器4.交集选择器5…

【机器学习chp7】SVM

参考1&#xff0c;笔记 SVM笔记.pdf 参考2&#xff1a;王木头视频 什么是SVM&#xff0c;如何理解软间隔&#xff1f;什么是合叶损失函数、铰链损失函数&#xff1f;SVM与感知机横向对比&#xff0c;挖掘机器学习本质_哔哩哔哩_bilibili 目录 一、SVM模型 二、构建决策函…

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

HarmonyOS4+NEXT星河版入门与项目实战(20)------状态管理@ObjectLink @Observed

文章目录 1、用法图解2、案例实现1、任务类改造2、参数改造变量3、完整代码4、运行效果4、总结1、用法图解 2、案例实现 上一节的案例中,一直有一个功能没有生效,就是任务完成后对应的任务行变灰,任务字体出现中划线删除的效果。而该功能一直不生效的原因就是要改变的数据值…

2024年工信部大数据分析师证书报考条件是怎样的?有什么用

大数据分析师&#xff0c;乃是这样一类专业人才&#xff0c;他们凭借着先进且高效的数据分析技术以及各类实用工具&#xff0c;对规模庞大、纷繁复杂的海量数据展开全面而细致的清洗、处理、分析以及解读工作。其工作的核心目标在于为企业的决策制定提供有力依据&#xff0c;推…

基于vite创建的react18项目的单元测试

题外话 最近一个小伙伴进了字节外包&#xff0c;第一个活就是让他写一个单元测试。 嗯&#xff0c;说实话&#xff0c;在今天之前我只知道一些理论&#xff0c;但是并没有实操过&#xff0c;于是我就试验了一下。 通过查询资料&#xff0c;大拿们基本都说基于vite的项目&…

探秘嵌入式位运算:基础与高级技巧

目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算&#xff08;&&#xff09; 1.1.2. 或运算&#xff08;|&#xff09; 1.1.3. 异或运算&#xff08;^&#xff09; 1.1.4. 取反运算&#xff08;~&#xff09; 1.1.5. 双重按位取反运算符&#xff08;~~&#xf…

SpringBoot - 优雅的实现【账号登录错误次数的限制和锁定】

文章目录 Pre需求实现步骤简易实现1. 添加依赖2. 配置文件3. 自定义注解4. AOP切面5. 使用自定义注解&#xff1a;6. 测试 附总结 Pre SpringBoot - 优雅的实现【流控】 需求 需求描述&#xff1a; 登录错误次数限制&#xff1a;在用户登录时&#xff0c;记录每个账号的登录错…

SRIO DRP动态速率配置说明(详细讲解)

目录 一、SRIO IP时钟结构 1、时钟内部结构 2、时钟直接的关系 3、时钟计算原理 ​二、SRIO DRP介绍 ​1、MMCM DRP配置(xapp888) 2、CPLL DRP配置(ug476) 关于CPLL DRP配置详细介绍&#xff1a; GTX中CPLL、QPLL DRP动态配置方法&#xff08;详解&#xff09;-CSDN博客…

动态规划之背包问题

0/1背包问题 1.二维数组解法 题目描述&#xff1a;有一个容量为m的背包&#xff0c;还有n个物品&#xff0c;他们的重量分别为w1、w2、w3.....wn&#xff0c;他们的价值分别为v1、v2、v3......vn。每个物品只能使用一次&#xff0c;求可以放进背包物品的最大价值。 输入样例…

推荐一款龙迅HDMI2.0转LVDS芯片 LT6211UX LT6211UXC

龙迅的HDMI2.0转LVDS芯片LT6211UX和LT6211UXC是两款高性能的转换器芯片&#xff0c;它们在功能和应用上有所差异&#xff0c;同时也存在一些共同点。以下是对这两款芯片的详细比较和分析&#xff1a; 一、LT6211UX 主要特性&#xff1a; HDMI2.0至LVDS和MIPI转换器。HDMI2.0输…

深度学习模型:循环神经网络(RNN)

一、引言 在深度学习的浩瀚海洋里&#xff0c;循环神经网络&#xff08;RNN&#xff09;宛如一颗独特的明珠&#xff0c;专门用于剖析序列数据&#xff0c;如文本、语音、时间序列等。无论是预测股票走势&#xff0c;还是理解自然语言&#xff0c;RNN 都发挥着举足轻重的作用。…

[STM32]从零开始的STM32 FreeRTOS移植教程

一、前言 如果能看到这个教程的话&#xff0c;说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗&#xff1f;是的&#xff0c;我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS&#xff0c;再到最…

《操作系统 - 清华大学》5 -4:虚拟技术

文章目录 0. 虚拟存储的定义1. 目标2.局部性原理3. 虚拟存储的思路与规则4. 虚拟存储的基本特征5. 虚拟页式存储管理5.1 页表表项5.2 示例 0. 虚拟存储的定义 1. 目标 虚拟内存管理技术&#xff0c;简称虚存技术。那为什么要虚存技术&#xff1f;在于前面覆盖和交换技术&#…

2024APMCM亚太杯数学建模C题【宠物行业】原创论文分享

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年APMCM亚太地区大学生数学建模竞赛C题的成品论文。 给大家看一下目录吧&#xff1a; 目录 摘 要&#xff1a; 10 一、问题重述 14 二&#xff0e;问题分析 15 2.1问题一 15 2.2问题二 15 2.3问题三…

YOLOv8模型pytorch格式转为onnx格式

一、YOLOv8的Pytorch网络结构 model DetectionModel((model): Sequential((0): Conv((conv): Conv2d(3, 64, kernel_size(3, 3), stride(2, 2), padding(1, 1))(act): SiLU(inplaceTrue))(1): Conv((conv): Conv2d(64, 128, kernel_size(3, 3), stride(2, 2), padding(1, 1))(a…

零基础3分钟快速掌握 ——Linux【终端操作】及【常用指令】Ubuntu

1.为啥使用Linux做嵌入式开发 能广泛支持硬件 内核比较高效稳定 原码开放、软件丰富 能够完善网络通信与文件管理机制 优秀的开发工具 2.什么是Ubuntu 是一个以桌面应用为主的Linux的操作系统&#xff0c; 内核是Linux操作系统&#xff0c; 具有Ubuntu特色的可视…

VScode 连不上远程云服务器

今天下午写代码&#xff0c;打开 VScode 突然发现连不上云服务器了&#xff0c;一开始以为自己密码输错了&#xff0c;试了好多次&#xff0c;依然是这样的 经过查资料发现&#xff0c;应该是版本的自动升级导致的&#xff01;解决方案如下&#xff1a; 1、删除 windows 端的 …

图像分割——区域增长

一 区域增长 图像灰度阈值分割技术都没有考虑到图像像素空间的连通性。区域增长法则正好相反,顾及像素的连接性. 方法&#xff1a;1&#xff09;选择一个或一组种子&#xff1b; 2&#xff09;选择特征及相似性判决准则&#xff1b; 3&#xff09;从该种子开始向外生长&#x…