78. UE5 RPG 创建技能数据并初始化技能ui

news2024/9/27 15:28:26

在上一篇文章里,我们创建了技能的UI,接下来,我们要考虑如何实现对技能UI的填充,肯定不能直接写死,需要有一些方法去实现技能的更新。我们期望能够创建一个技能数据,然后根据数据通过回调的方式实现数据的更新。
为了实现这个功能,我们会先创建一个结构体,用于存储技能的相关数据(Tag,使用的图片等),然后创建一个DataAsset,然后创建回调函数,在注册技能的时候,将技能相关的数据广播出去,在UI里接受,更新UI显示。

创建DataAsset

首先,我们基于DataAsset创建一个新的类,用于设置技能需要的相关配置
在这里插入图片描述
创建命名 AbilityInfo,技能数据
在这里插入图片描述
在类里面,我们首先创建一个结构体,用于设置技能所需哪些配置,如果需要,我们后续还可以继续添加,这里添加了四项数据

USTRUCT(BlueprintType)
struct FRPGAbilityInfo
{
	GENERATED_BODY()

	//技能标签
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	FGameplayTag AbilityTag = FGameplayTag();

	//技能输入映射标签
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	FGameplayTag InputTag = FGameplayTag();

	//技能图标
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	TObjectPtr<const UTexture2D> Icon = nullptr;

	//背景材质
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	TObjectPtr<UMaterialInterface> BackgroundMaterial = nullptr;
};

接着,我们在数据类里面增加一个参数,用于在蓝图中使用此类后,可以设置一个技能数据数组,并增加一个通过技能标签获取对应数据的方法

/**
 * 
 */
UCLASS()
class RPG_API UAbilityInfo : public UDataAsset
{
	GENERATED_BODY()

public:

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="AbilityInformation")
	TArray<FRPGAbilityInfo> AbilityInformation;

	//通过技能标签获取到技能相关数据
	FRPGAbilityInfo FindAbilityInfoForTag(const FGameplayTag& AbilityTag, bool bLogNotFound = false) const;
};

在获取技能数据的函数实现这里,我们直接遍历数组,查找到相同的技能标签返回,并增加一个参数,如果无法查询到,打印一个错误信息,方便后续调试

FRPGAbilityInfo UAbilityInfo::FindAbilityInfoForTag(const FGameplayTag& AbilityTag, const bool bLogNotFound) const
{
	for(const FRPGAbilityInfo& Info : AbilityInformation)
	{
		if(Info.AbilityTag == AbilityTag)
		{
			return Info;
		}
	}

	if(bLogNotFound)
	{
		//如果获取不到数据,打印消息
	}

	return FRPGAbilityInfo();
}

实现日志分类

在打印这里,我们想实现对于技能设置不同的打印通道,和其它默认的区分开来,这样调试起来会更加的方便。为了实现这个功能,我们需要额外的创建一个.h 和 .cpp文件
直接项目文件夹上面,右键选择添加,文件
在这里插入图片描述
在弹出窗口这里写入需要创建的文件名称
在这里插入图片描述
我们将两个文件都创建出来
在这里插入图片描述
在.h文件中,我们设置#pragma once 可以实现一次编译,多次复用。然后引入基础头文件和打印相关的头文件,并通过宏定义了一个我们自定义的打印通道。

#pragma once

#include "CoreMinimal.h"
#include "Logging/LogMacros.h"

DECLARE_LOG_CATEGORY_EXTERN(LogRPG, Log, All);

然后在cpp文件中,使用DEFINE_LOG_CATEGORY对一个打印通道进行实例化,这个宏与DECLARE_LOG_CATEGORY_EXTERN宏一起使用来实现一个新的打印通道。

#include "RPGLogChannels.h"

DEFINE_LOG_CATEGORY(LogRPG);

接着,我们可以在获取技能相关数据的函数中,引入此文件

#include "RPG/RPGLogChannels.h"

并在查询不到对应数据时,在我们自定义的日志分类中打印

	if(bLogNotFound)
	{
		//如果获取不到数据,打印消息
		UE_LOG(LogRPG, Error, TEXT("无法通过技能标签[%s]在技能数据[%s]查找到对应的技能数据"), *AbilityTag.ToString(), *GetNameSafe(this));
	}

应用技能数据

我们将技能数据的DataAsset创建完成,接下来,要实现对其的应用,我们在蓝图中创建了技能数据,需要有一个地方去设置,并可以应用。这些数据是在在UI上使用的,我们将其设置在OverlayWidgetController里面,增加一个对齐配置的配置项。OverlayWidgetController是配置在HUD类上面的,在项目运行时,就会初始化OverlayWidgetController,并应用对OverlayWidget,覆盖屏幕的OverlayWidget就会从OverlayWidgetController中获取数据。

	//技能的表格数据
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Widget Data")
	TObjectPtr<UAbilityInfo> AbilityInfo;

我们现实现对数据的设置,编译代码,打开UE,创建一个数据资产
在这里插入图片描述
类就选择我们创建的数据资产的类
在这里插入图片描述
命名为DA_AbilityInfo
在这里插入图片描述
接着打开基于OverlayWidgetController创建的蓝图,将创建的数据资产设置上去,这样,我们就可以在后续UI更新中,使用此数据,并能够实现对数据的获取。
在这里插入图片描述

给数据资产添加第一条数据

有了数据资产,我们首先将玩家角色的第一个技能添加进去,就是普通攻击火球术,我们还没有其相关的技能标签
我们首先创建一个火球术的技能标签

FGameplayTag Abilities_Fire_FireBolt; //火球术技能标签

然后在cpp里面对其注册

	GameplayTags.Abilities_Fire_FireBolt = UGameplayTagsManager::Get()
		.AddNativeGameplayTag(
			FName("Abilities.Fire.FireBolt"),
			FString("火球术技能标签")
			);

然后编译,进行设置
在这里插入图片描述
这里考虑到有可能后续玩家会修改触发技能的按键,对于技能的输入tag设置,我们后续将修改为在程序中动态设置它,并且,后续将其在蓝图中设置的功能关闭。

	//技能输入映射标签
	UPROPERTY(BlueprintReadOnly)
	FGameplayTag InputTag = FGameplayTag();

重新编译
在这里插入图片描述

广播技能数据

有了技能数据,我们需要实现在ASC应用角色技能时,UI上也能够获取到应用通知,跟随更新数据。
为了实现这点,我们需要在ASC中增加委托,并在应用技能后,进行广播触发回调。
我们在自定义ASC中增加一个委托宏,这个宏用于在技能初始化应用完成后广播回调

DECLARE_MULTICAST_DELEGATE_OneParam(FAbilityGiven, URPGAbilitySystemComponent*) //技能初始化应用后的回调委托

使用宏创建一个委托

FAbilityGiven AbilityGivenDelegate; //技能初始化应用后的回调委托

由于我们无法确定运行起来后,是技能的初始化完成,还是UI的初始化完成,所以,我们通过一个变量来记录,在技能初始化应用完成后,将其设置为true

bool bStartupAbilitiesGiven = false; //初始化应用技能后,此值将被设置为true,用于记录当前是否被初始化完成

接着在初始化应用技能的函数里,将变量设置为true,并将委托广播出去

void URPGAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
	for(const TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
	{
		FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
		if(const URPGGameplayAbility* AbilityBase = Cast<URPGGameplayAbility>(AbilitySpec.Ability))
		{
			AbilitySpec.DynamicAbilityTags.AddTag(AbilityBase->StartupInputTag); //设置技能激活输入标签
			GiveAbility(AbilitySpec); //只应用不激活
			// GiveAbilityAndActivateOnce(AbilitySpec); //应用技能并激活一次
		}
	}

	bStartupAbilitiesGiven = true;
	AbilityGivenDelegate.Broadcast(this);
}

这样,我们就实现了技能初始化应用的委托,然后,我们在Overlay的Controller的类里面,绑定此委托的回调,完成和ASC的交互,我们在OverlayWidgetController里面创建一个回调函数

void OnInitializeStartupAbilities(URPGAbilitySystemComponent* RPGAbilitySystemComponent) const; //技能初始化应用后的回调

刚好里面有我们之前书写的绑定委托的函数,我们在里面对此委托进行绑定。
这里逻辑是,我们获取到使用的ASC,将其转换为自定义ASC,通过判断变量,如果变量值为true,代表当前技能初始化应用已经完成,我们可以直接调用回调。如果变量为false,初始化还未完成状态,我们就需要去绑定委托,在技能初始化应用完成后,也可以触发委托的回调。
通过这两步,不管谁先谁后,都可以成功触发我们写在OverlayWidgetController里面的回调。并且我们也成功的获取到了ASC,并进行下一步处理。

void UOverlayWidgetController::BindCallbacksToDependencies()
{
	...

	if(URPGAbilitySystemComponent* RPGASC = Cast<URPGAbilitySystemComponent>(AbilitySystemComponent))
	{
		if(RPGASC->bStartupAbilitiesGiven)
		{
			//如果执行到此处时,技能的初始化工作已经完成,则直接调用初始化回调
			OnInitializeStartupAbilities(RPGASC);
		}
		else
		{
			//如果执行到此处,技能初始化还未完成,将通过绑定委托,监听广播的形式触发初始化完成回调
			RPGASC->AbilityGivenDelegate.AddUObject(this, &ThisClass::OnInitializeStartupAbilities);
		}
		
		//AddLambda 绑定匿名函数
		RPGASC->EffectAssetTags.AddLambda(
			[this](const FGameplayTagContainer& AssetTags) //中括号添加this是为了保证内部能够获取类的对象
			{
				for(const FGameplayTag& Tag : AssetTags)
				{

					//对标签进行检测,如果不是信息标签,将无法进行广播
					FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message"));
					// "A.1".MatchesTag("A") will return True, "A".MatchesTag("A.1") will return False
					if(Tag.MatchesTag(MessageTag))
					{
						const FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable, Tag);
						MessageWidgetRowDelegate.Broadcast(*Row); //前面加*取消指针引用
					}
				
					//将tag广播给Widget Controller 测试代码
					// const FString Msg = FString::Printf(TEXT("GE Tag in Widget Controller: %s"), *Tag.ToString()); //获取Asset Tag
					// GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, Msg); //打印到屏幕上 -1 不会被覆盖

				}
			}
		);
	}
}

接下来,我们将实现技能的初始化回调的内容逻辑,它将实现对所有的应用的技能进行类型判断,并选出需要手动触发的技能,然后获取对应的技能UI数据,并通过Controller广播给用户控件的UI。虽然逻辑稍微复杂点,但是这种方式能够将逻辑拆分开来,不会造成代码之间的耦合度过高,造成报错问题。

实现UI技能委托

现在,当角色的技能初始化应用后,会触发UI的Controller里面的初始化回调。在回调里面,我接下来将实现的是,从里面获取到主动技能,然后获取其是否是需要按键激活的技能,然后通过技能Tag去获取数据,将数据广播出去。
接下来,我们实现技能初始化应用后的回调,在控制器里,初始化后,我们进行一次判断,当前技能是否初始化成功

if(!RPGAbilitySystemComponent->bStartupAbilitiesGiven) return; //判断当前技能初始化是否完成,触发回调时都已经完成

接下来,我们要遍历调用技能的实例,对技能进行处理,这里我们创建一个新的单播委托,它只能绑定一个回调函数

DECLARE_DELEGATE_OneParam(FForEachAbility, const FGameplayAbilitySpec&); //单播委托,只能绑定一个回调

在ASC中增加一个新的函数,用于遍历技能,并通过委托回调的形式广播出去,通过这种方式,降低了和OverlayWidgetController之间的耦合,即使你换一个其它的类,也可以调用。参数我们传入单播委托

void ForEachAbility(const FForEachAbility& Delegate); //遍历技能,并将技能广播出去

在函数实现这里,我们首先使用一次域锁,在执行下面的逻辑时,传入的内容内部的数据是无法被更改变动的。然后我们遍历所有可激活的技能,通过委托广播的形式调用。

void URPGAbilitySystemComponent::ForEachAbility(const FForEachAbility& Delegate)
{
	FScopedAbilityListLock ActiveScopeLock(*this); //使用域锁将此作用域this的内容锁定(无法修改),在遍历结束时解锁,保证线程安全
	for(const FGameplayAbilitySpec& AbilitySpec : GetActivatableAbilities())
	{
		if(!Delegate.ExecuteIfBound(AbilitySpec)) //运行绑定在技能实例上的委托,如果失败返回false
		{
			UE_LOG(LogRPG, Error, TEXT("在函数[%hs]运行委托失败"), __FUNCTION__);
		}
	}
}

有了这个函数,我们在OverlayWidgetController里面就可以实现对技能的遍历,而且还不需要类型转换等操作。上面的函数可以针对每个技能实例触发一次委托回调,所以,我们创建一个委托,并绑定回调函数,就可以实现对所有技能的处理。
具体实现如下,创建委托,绑定回调,然后通过函数调用,即可将技能实例进行遍历。

	//创建单播委托
	FForEachAbility BroadcastDelegate;
	//委托绑定回调匿名函数,委托广播时将会触发函数内部逻辑
	BroadcastDelegate.BindLambda([this](const FGameplayAbilitySpec& AbilitySpec)
	{
		...
	});
	//遍历技能并触发委托回调
	RPGAbilitySystemComponent->ForEachAbility(BroadcastDelegate);

我们在回调函数中,将针对于每个技能实例进行处理,获取技能的Tag标签,判断它是否属于技能,并获取技能的输入标签设置给技能数据,通过委托,广播出去。我们在技能的用户控件实例里面,就可以通过监听相关委托来实现修改技能图标。
我们在OverlayWidgetController里面新创建一个委托,用于在蓝图中对其进行监听,委托返回一个参数,对应的技能的数据

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityInfoSignature, const FRPGAbilityInfo, Info);

根据委托的类型创建一个参数,用于在蓝图中绑定监听

	UPROPERTY(BlueprintAssignable, Category="GAS|Messages")
	FAbilityInfoSignature AbilityInfoDelegate;

我们还需要实现两个函数,它们可以通过传入的技能实例,从技能实例里面获取到对应的技能标签和输入标签。这里我们直接创建两个静态函数

	static FGameplayTag GetAbilityTagFromSpec(const FGameplayAbilitySpec& AbilitySpec);
	static FGameplayTag GetInputTagFromSpec(const FGameplayAbilitySpec& AbilitySpec);

它们的实现是,我们技能标签直接从AbilityTags里面获取,由于它不只可以设置一个标签,我们需要遍历。

FGameplayTag URPGAbilitySystemComponent::GetAbilityTagFromSpec(const FGameplayAbilitySpec& AbilitySpec)
{
	if(AbilitySpec.Ability)
	{
		for(FGameplayTag Tag : AbilitySpec.Ability.Get()->AbilityTags) //获取设置的所有的技能标签并遍历
		{
			if(Tag.MatchesTag(FGameplayTag::RequestGameplayTag(FName("Abilities")))) //判断当前标签是否包含"Abilities"名称
			{
				return Tag;
			}
		}
	}
	return FGameplayTag();
}

FGameplayTag URPGAbilitySystemComponent::GetInputTagFromSpec(const FGameplayAbilitySpec& AbilitySpec)
{
	for(FGameplayTag Tag : AbilitySpec.DynamicAbilityTags) //从技能实例的动态标签容器中遍历所有标签
	{
		if(Tag.MatchesTag(FGameplayTag::RequestGameplayTag(FName("InputTag")))) //查找标签中是否设置以输入标签开头的标签
		{
			return Tag;
		}
	}

	return FGameplayTag();
}

MatchesTag的解释是A.1如果MatchesTag的A那么将返回true,相当于判断的它的标签下面的子级,我们的技能都是在"Abilities"下面
在这里插入图片描述
输入标签也是同理
在这里插入图片描述

输入标签的设置是我们在初始的时候设置在技能上的,我们可以通过蓝图设置它的输入
在这里插入图片描述
并在应用技能时,设置在技能实例的动态技能标签中,所以,我们要去技能标签中去获取判断,这种还可以实现如果玩家修改键位了,可以实现不同的键位,前提是你需要把之前默认的删除掉。
在这里插入图片描述
可以获取技能标签和输入标签,还有了蓝图可以绑定的回调,那么,我们就可以去实现回到的函数,首先获取技能标签,然后通过技能标签获取到技能对应的技能数据,并设置技能数据广播出去,完成整个逻辑。

//委托绑定回调匿名函数,委托广播时将会触发函数内部逻辑
	BroadcastDelegate.BindLambda([this](const FGameplayAbilitySpec& AbilitySpec)
	{
		//通过静态函数获取到技能实例的技能标签,并通过标签获取到技能数据
		FRPGAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(URPGAbilitySystemComponent::GetAbilityTagFromSpec(AbilitySpec));
		//获取到技能的输入标签
		Info.InputTag = URPGAbilitySystemComponent::GetInputTagFromSpec(AbilitySpec);
		//广播技能数据
		AbilityInfoDelegate.Broadcast(Info); 
	});

以下是初始化技能应用后的完整回调代码

void UOverlayWidgetController::OnInitializeStartupAbilities(URPGAbilitySystemComponent* RPGAbilitySystemComponent) const
{
	if(!RPGAbilitySystemComponent->bStartupAbilitiesGiven) return; //判断当前技能初始化是否完成,触发回调时都已经完成

	//创建单播委托
	FForEachAbility BroadcastDelegate;
	//委托绑定回调匿名函数,委托广播时将会触发函数内部逻辑
	BroadcastDelegate.BindLambda([this](const FGameplayAbilitySpec& AbilitySpec)
	{
		//通过静态函数获取到技能实例的技能标签,并通过标签获取到技能数据
		FRPGAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(URPGAbilitySystemComponent::GetAbilityTagFromSpec(AbilitySpec));
		//获取到技能的输入标签
		Info.InputTag = URPGAbilitySystemComponent::GetInputTagFromSpec(AbilitySpec);
		//广播技能数据
		AbilityInfoDelegate.Broadcast(Info); 
	});
	//遍历技能并触发委托回调
	RPGAbilitySystemComponent->ForEachAbility(BroadcastDelegate);
}

实现在技能UI上绑定委托回调

完成上面内容,我们可以编译代码打开UE,在UE里面对我们上一篇文章中制作的技能UI进行修改。
打开我们之前创建的WBP_SpellGlobe用户控件,我们需要添加一个标签,用于记录当前的UI需要显示哪个技能,因为我们输入的键位是固定的,需要在实例上面标识这个技能的出入标签。
在这里插入图片描述
接着我们添加逻辑,在控制器设置回调里面,去将控制器实例转换为目标类型,方便后续使用
在这里插入图片描述
然后绑定监听上面的委托回调,在目标委托广播后,将触发后续逻辑,返回一个技能相关数据,我们可以通过判断当前的输入标签和技能数据的输入标签是否一致,如果一致,使用技能数据的技能图标和背景材质更新当前的技能UI。
在这里插入图片描述
接着打开WBP_HealthManaSpells这个用户控件
在这里插入图片描述
我们首先需要在技能ui上面设置它的输入标签,按照对应的输入,设置对应的输入标签。
在这里插入图片描述
还需要一步,就是设置控件的控制器,这样就可以成功触发控制器设置回调
在这里插入图片描述
最后,我们在技能身上设置好对应的技能输入标签和技能标签
在这里插入图片描述
接着运行,查看是否能够在ui上面显示出来。
在这里插入图片描述
查看修改输入标签后是否也能够切换
在这里插入图片描述

处理多人玩法中的bug

如果我们开启两个玩家运行游戏,会发现第二个玩家的ui没有跟着更新。这个原因是因为技能初始化应用完成调用的广播是在服务器执行的,在客户端无法执行
在这里插入图片描述
我们查看源代码,可以看到在ASC里面,存储着当前激活的技能的容器,被修改后,会调用同步函数OnRep_ActivateAbilities
在这里插入图片描述
这个函数是一个虚函数,我们可以复写它,然后在里面调用,去初始化客户端的技能
在这里插入图片描述
我们在自定义的ASC中覆写它

virtual void OnRep_ActivateAbilities() override;

然后在函数内,判断当前是否已经初始化广播,如果没有,则调用广播

void URPGAbilitySystemComponent::OnRep_ActivateAbilities()
{
	Super::OnRep_ActivateAbilities();

	if(!bStartupAbilitiesGiven)
	{
		bStartupAbilitiesGiven = true;
		AbilityGivenDelegate.Broadcast(this);
	}
}

然后发现在客户端也能够顺利初始化技能ui
在这里插入图片描述

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

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

相关文章

树链剖分相关

树链剖分这玩意儿还挺重要的&#xff0c;是解决静态树问题的一个很好的工具~ 这里主要介绍一下做题时经常遇到的两个操作&#xff1a; 1.在线求LCA int LCA(int x,int y){while(top[x]!top[y])if(dep[top[x]]>dep[top[y]]) xfa[top[x]];else yfa[top[y]];return dep[x]&l…

新版FMEA培训未能达到预期效果怎么办?

在制造业的质量管理中&#xff0c;FMEA&#xff08;Failure Mode and Effects Analysis&#xff0c;失效模式与影响分析&#xff09;是一项至关重要的工具&#xff0c;它帮助企业识别和评估产品或过程中潜在的失效模式&#xff0c;以及这些失效模式可能导致的后果。然而&#x…

可视化作品集(11):节能环保能耗领域大展拳脚。

在大屏上可视化节能环保领域的能耗数据可以通过各种图表和数据展示方式&#xff0c;可以帮助观众直观地了解节能环保领域的能耗情况和公司在该领域的工作成果。 1. 实时能源消耗数据&#xff1a; 通过实时折线图或饼状图展示不同能源&#xff08;电力、天然气、水等&#xff…

FastAPI 学习之路(三十六)引入APIRouter

本次调整后的目录如下&#xff1a; 我们可以使用APIRouter来声明路径操作&#xff0c;我们先看下如何去使用。 我们根据选择划分为users和items来细分。 具体实现如下&#xff1a; ①先看items实现 from fastapi import APIRouter from fastapi import Depends from models.…

【密码学】公钥密码的基本概念

在先前我写的密码学体制文章中谈到&#xff0c;现代密码学分为两大体制&#xff0c;介绍了一些有关对称密码体制诸如流密码和分组密码的内容。本文的主要内容则切换到公钥密码体制&#xff08;又称非对称密码体制&#xff09;&#xff0c;简述了公钥密码体制的基本思想和应用方…

SPI通信协议和W25Q64

前言&#xff1a; STM32中的通信接口&#xff1a; UART 单总线 IIC SPI CAN 1. SPI FLASH W25Q64的关系 SPI:一种通信接口&#xff0c;可以用于和搭载SPI接口的设备通信 FLASH:是一种掉电不丢失的存储 -- 手机8256G的256 单片机 64K512K的512 芯片内部flash&…

AutoMQ 与蚂蚁数科达成战略合作

近期&#xff0c;AutoMQ 与蚂蚁数科正式签署战略合作协议&#xff0c;将和蚂蚁数科云原生 PaaS 平台 SOFAStack 在产品研发、生态集成、市场合作、技术社区影响力等多方面开展深度合作。 AutoMQ 是业内领先的消息和流存储服务提供商&#xff0c;基于云原生基础设施重新设计了 …

windows防火墙端口设置

PS&#xff1a;本文实例为Windows Server 2019&#xff0c;其他Windows版本大同小异。 1、首先打开windows防火墙&#xff0c;点击“高级设置” 2、 高级设置界面 3、假设需要开放一个端口为3306应该怎么做 光标对准“入站规则”右键新建规则&#xff0c;选择“端口” 协议这…

CSDN回顾与前行:我的创作之旅——2048天的技术成长与感悟

CSDN回顾与前行&#xff1a;我的创作之旅——2048天的技术成长与感悟 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 前言 时光荏苒&#xff0c;岁月如梭。转眼间&#xff0c;从我在CSDN上写下第一篇技术博客《2-6 带头结点的链式表操作集…

tensorflow之欠拟合与过拟合,正则化缓解

过拟合泛化性弱 欠拟合解决方法&#xff1a; 增加输入特征项 增加网络参数 减少正则化参数 过拟合的解决方法&#xff1a; 数据清洗 增大训练集 采用正则化 增大正则化参数 正则化缓解过拟合 正则化在损失函数中引入模型复杂度指标&#xff0c;利用给w增加权重&#xff0c;…

Python 轻松生成多种条形码、二维码 (Code 128、EAN-13、QR code等)

条形码和二维码是现代信息交换和数据存储的重要工具&#xff0c;它们将信息以图形的形式编码&#xff0c;便于机器识别和数据处理&#xff0c;被广泛应用于物流、零售、医疗、教育等各领域。 本文将介绍如何使用Python快速生成各种常见的条形码如Code 128、EAN-13&#xff0c;…

了解PPO算法(Proximal Policy Optimization)

Proximal Policy Optimization (PPO) 是一种强化学习算法&#xff0c;由 OpenAI 提出&#xff0c;旨在解决传统策略梯度方法中策略更新过大的问题。PPO 通过引入限制策略更新范围的机制&#xff0c;在保证收敛性的同时提高了算法的稳定性和效率。 PPO算法原理 PPO 算法的核心…

Python程序封装成Windows服务实践

1. WinSW 工具概述 WinSW&#xff08;Windows Service Wrapper&#xff09;是一个轻量级的、开源的工具&#xff0c;用于将任何可执行文件&#xff08;包括exe、jar、脚本文件等&#xff09;包装成一个Windows服务。这意味着&#xff0c;原本设计为命令行应用或需要手动启动的…

如何整合生成的人工智能?(GenAI)为你未来的工作增加动力

生成人工智能(GenAI)它发展迅速&#xff0c;以前所未有的速度取得了突破。人工智能将继续改变各行各业&#xff0c;预计2023年至2030年的年增长率将达到37.3%。由于一种新的知识工作者现在面临被取代的风险&#xff0c;生成式人工智能的惊人崛起进一步加剧了这种紧迫性。据《未…

高并发内存池联调问题

断言报错1 在这里插入图片描述 排查原因 实际 actualNum 值并没有大于一 断点报错。 经过排查&#xff0c;此处assert&#xff08;actualNum > 0) 判断条件应该是大于零&#xff0c;否则或许if判断条件无法执行。 跑通结果: 2

大数据之Hadoop平台的搭建

实验环境 三台虚拟机 master slave1 slave2 服务器集群单节点&#xff0c;机器最低配置&#xff1a;双核 CPU、8GB 内存、100G 硬盘运行环境CentOS 7.4服务和组件服务和组件根据实验需求安装 1实验过程 1.1实验任务一&#xff1a;配置 Linux 系统基础环境 1.1.1步骤一&a…

漂亮的不像话的网站首屏,直接勾起了用户浏览欲望。

漂亮大气的网站首屏页面可以激发用户的浏览欲望&#xff0c;主要通过以下几个方面的设计和呈现来实现&#xff1a; 引人注目的视觉效果&#xff1a;使用高质量的图片、精心设计的图形和动画效果来吸引用户的眼球。这些视觉元素应当与网站的主题和品牌形象相符&#xff0c;并能够…

springboot“小鱼在乎”日程计划系统-计算机毕业设计源码51307

摘要 本文介绍了一种基于微信小程序和Spring Boot后端服务的“小鱼在乎”日程计划系统。该系统结合了前端微信小程序的便捷交互与后端Spring Boot框架的稳健性能&#xff0c;为用户提供了一款功能全面、体验出色的日程管理工具。 “小鱼在乎”日程计划系统涵盖了多种功能&#…

提升困难生学工支持:智慧校园的新功能介绍

智慧校园的学工管理系统内嵌的困难生信息管理功能&#xff0c;是一个综合性的服务平台&#xff0c;专注于精准识别校园内的经济困难学生&#xff0c;并给予他们必要的帮助与关怀&#xff0c;确保每位学生都能在公平的环境中追求学业和个人成长。这一功能通过一系列信息化手段&a…

Linux Web服务器

文章目录 一、web服务1.1 http1.2 Web1.3 web中间件 二、 Apache服务的搭建与配置2.1 服务安装基本思路三、 Nginx 配置Web服务 一、web服务 以赛促学的内容:因不清楚出题使用何种服务,特将两种服务归纳总结. HTTP是数据传输的规则&#xff0c;Web是基于HTTP协议的服务。当今…