87. UE5 RPG 实现技能面板技能的升级降级功能

news2024/12/23 13:20:50

在上一篇文章里,我们实现技能面板里的技能按钮配置数据,在角色对应的等级后,会解锁对应的技能,并实现了监听玩家角色所拥有的技能点数。
在这一篇里,我们将实现,通过玩家所拥有的技能点数,对技能进行升级

增加升级按钮

我们在技能按钮里增加两个按钮,用于实现技能等级的增加和减少功能
在这里插入图片描述

增加技能的选中功能

首先,我们在技能按钮中增加两个函数,分别是选中后显示选中动画,并将动画对应节点显示出来
在这里插入图片描述

然后就是取消对技能按钮的焦点,我们将升级按钮隐藏,并将焦点节点隐藏
在这里插入图片描述
然后我们在按钮的用户控件里增加一个事件分发器,用于在技能树控件里面监听回调
在这里插入图片描述
我们给技能按钮增加一个点击事件,并增加一个变量防止频繁点击,并调用事件分发器
在这里插入图片描述
这样,就可以在按钮被点击时,整个技能树可以根据其需求修改

实现技能按钮点击,取消其它技能按钮的焦点状态

现在,我们实现了按钮点击的状态,接下来,我们要实现,当前按钮点击时,只焦点当前按钮,并显示当前按钮的加点和减技能的按钮,其它按钮都取消掉对应的效果。

由于,我们技能分为主动技能和被动技能两个技能树,所以我们需要在两个技能树里面增加两个函数,用于清除树里的所有技能按钮到默认状态
在这里插入图片描述
并在树里增加一个事件分发器,用于通知上层处理多个树之间的交互
在这里插入图片描述

接着,我们在技能树里,对按钮的事件分发器进行监听,在树里的某个按钮被点击时,我们将树的所有状态恢复到默认,并调用事件分发器,发送通知
在这里插入图片描述
接着,我们在WBP_SpellMenu里,绑定两个树的事件分发器,这样,就实现了,在有一个树的按钮被点击时,所有树的按钮都可以被清除到默认状态
在这里插入图片描述
接下来运行测试效果
在这里插入图片描述
我们后续还有很多工作需要完成,首先显而易见的是被锁住的技能按钮无法激活焦点状态。然后就是技能的升级和降级按钮,需要在可按的时候显示出来,或者显示无法点击状态。

对技能按钮附加按钮状态更新

我们有了技能的升级按钮和降级按钮,后续,我们将通过这两个按钮实现对技能的等级修改。所以,我们需要一个委托用来更新按钮的状态,在技能等级低到无法降级时,我们降级按钮也无法实现点击,如果技能等级满级,或者没有可分配的技能点数时,将无法实现技能的升级。
接下来,我们先实现委托,并在委托中也返回技能是否可以装配变量。
首先,我们在SpellMenuWidgetController.h中,增加一个委托声明

DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FSpellGlobeSelectedSignature, bool, bSpendPointsEnabled, bool, bEquipEnabled, bool, bDemotionPointsEnabled);

通过声明类型创建一个变量

	UPROPERTY(BlueprintAssignable)
	FSpellGlobeSelectedSignature SpellGlobeSelectedSignature; //选中技能按钮后,升级和装备按钮的变动回调

然后增加一个函数,在技能按钮被点击时,调用,并传入技能按钮上设置的标签,返回当前的技能状态标签,通过标签,我们可以设置上锁的技能按钮,不会播放焦点的动画

	UFUNCTION(BlueprintCallable)
	FGameplayTag SpellGlobeSelected(const FGameplayTag& AbilityTag); //技能按钮选中调用函数,处理升级按钮和装配

接着,我们创建一个私有函数,这个函数,通过技能实例的状态标签和玩家角色所拥有的可分配技能数,返回对应的按钮状态和技能可装配情况

private:

	//通过技能状态标签和可分配技能点数来获取技能是否可以装配和技能是否可以升级
	static void ShouldEnableButtons(const FGameplayTag& AbilityStatus, bool HasSpellPoints, bool& bShouldEnableSpellPoints, bool& bShouldEnableEquip, bool& bShouldDemotionPoints);

在SpellGlobeSelected实现这里,我们首先判断技能按钮上的标签,然后获取技能实例和可分配的技能点数,通过ShouldEnableButtons获取到当前技能的状态,并通过委托广播出去。

FGameplayTag USpellMenuWidgetController::SpellGlobeSelected(const FGameplayTag& AbilityTag)
{
	const FRPGGameplayTags GameplayTags = FRPGGameplayTags::Get();
	const int32 SpellPoints = GetRPGPS()->GetSpellPoints(); //获取技能点数
	FGameplayTag AbilityStatus;

	const bool bTagValid = AbilityTag.IsValid(); //判断传入的标签是否存在
	const bool bTagNone = AbilityTag.MatchesTag(GameplayTags.Abilities_None); //判断传入的是否为空技能标签
	const FGameplayAbilitySpec* AbilitySpec = GetRPGASC()->GetSpecFromAbilityTag(AbilityTag); //通过技能标签获取技能
	const bool bSpecValid = AbilitySpec != nullptr; //判断技能实例是否存在
	
	if(!bTagValid || bTagNone || !bSpecValid)
	{
		//传入标签不存在,或传入的为空技能标签,或者技能实例不存在时,设置为技能按钮显示上锁状态
		AbilityStatus = GameplayTags.Abilities_Status_Locked;
	}
	else
	{
		//从技能实例获取技能的状态标签
		AbilityStatus = GetRPGASC()->GetStatusTagFromSpec(*AbilitySpec);
	}

	bool bEnableSpendPoints = false; //技能是否可以升级
	bool bEnableEquip = false; //技能是否可以装配
	bool bEnableDemotion = false; //技能是否可以降级

	ShouldEnableButtons(AbilityStatus, SpellPoints > 0, bEnableSpendPoints, bEnableEquip, bEnableDemotion); //获取结果

	SpellGlobeSelectedSignature.Broadcast(bEnableSpendPoints, bEnableEquip, bEnableDemotion); //广播状态

	return AbilityStatus;
}

ShouldEnableButtons的实现,就是根据状态和是否拥有可分配的技能点数,来设置对应的状态

void USpellMenuWidgetController::ShouldEnableButtons(const FGameplayTag& AbilityStatus, bool HasSpellPoints, bool& bShouldEnableSpellPoints, bool& bShouldEnableEquip, bool& bShouldDemotionPoints)
{
	const FRPGGameplayTags GameplayTags = FRPGGameplayTags::Get();

	if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Equipped))
	{
		bShouldEnableSpellPoints = HasSpellPoints;
		bShouldEnableEquip = true;
		bShouldDemotionPoints = true;
	}
	else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Eligible))
	{
		bShouldEnableSpellPoints = HasSpellPoints;
		bShouldEnableEquip = false;
		bShouldDemotionPoints = false;
	}
	else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Unlocked))
	{
		bShouldEnableSpellPoints = HasSpellPoints;
		bShouldEnableEquip = true;
		bShouldDemotionPoints = true;
	}
	else if (AbilityStatus.MatchesTagExact(GameplayTags.Abilities_Status_Locked))
	{
		bShouldEnableSpellPoints = false;
		bShouldEnableEquip = false;
		bShouldDemotionPoints = false;
	}
}

函数实现后,我们在蓝图增加一个函数,讲委托获取的变量设置给对应的按钮,讲是否可装配的变量存储下来,方便后续使用
在这里插入图片描述
然后绑定委托
在这里插入图片描述
接下来,我们修改蓝图的Select函数,首先设置其选中,然后调用我们设置的SpellGlobeSelected函数获取当前技能的状态,如果是已经上锁的技能按钮,不需要显示±按钮。
在这里插入图片描述
接下来就是测试效果
在这里插入图片描述

技能升降级按钮的动态修改

我们实现了点击按钮触发技能按钮的升降级状态的更新,还未实现在技能在可分配技能点变动和技能状态变动时,对升降级按钮的更新。
为了实现这个功能,我们增加一个结构体
在技能面板控制器类,添加结构体,用于存储当前选中的技能标签和状态标签

//在技能面板选中的技能的标签结构体
struct FSelectedAbility
{
	FGameplayTag Ability = FGameplayTag(); //技能标签
	FGameplayTag Status = FGameplayTag(); //技能状态标签
};

在类里添加一个参数,并对值进行初始化

	//设置选中技能默认值
	FSelectedAbility SelectedAbility = {FRPGGameplayTags::Get().Abilities_None, FRPGGameplayTags::Get().Abilities_Status_Locked};

接着创建一个可分配技能点数的参数,用于存储可分配点数

	//保存当前技能可分配点数
	int32 CurrentSpellPoints = 0;

接着增加一个用于广播的函数,因为我们需要在多个地方调用

	//广播当前技能按钮升降级按钮状态和可装配状态
	void BroadcastSpellGlobeSelected() const;

函数实现就是之前的实现,只是值的获取改为了自身

void USpellMenuWidgetController::BroadcastSpellGlobeSelected() const
{
	bool bEnableSpendPoints = false; //技能是否可以升级
	bool bEnableEquip = false; //技能是否可以装配
	bool bEnableDemotion = false; //技能是否可以降级

	ShouldEnableButtons(SelectedAbility.Status, CurrentSpellPoints > 0, bEnableSpendPoints, bEnableEquip, bEnableDemotion); //获取结果

	SpellGlobeSelectedSignature.Broadcast(bEnableSpendPoints, bEnableEquip, bEnableDemotion); //广播状态
}

并将SpellGlobeSelected函数修改为调用此函数广播

	//选中时,更新控制器缓存数据
	SelectedAbility.Ability = AbilityTag;
	SelectedAbility.Status = AbilityStatus;
	CurrentSpellPoints = SpellPoints;

	BroadcastSpellGlobeSelected(); //广播升降级按钮状态

接着,在绑定数据监听广播里,在技能状态和可分配点数变动时,广播升降级按钮状态广播

void USpellMenuWidgetController::BindCallbacksToDependencies()
{
	//绑定技能状态修改后的委托回调
	GetRPGASC()->AbilityStatusChanged.AddLambda([this](const FGameplayTag& AbilityTag, const FGameplayTag& StatusTag)
	{
		//技能状态修改,修改技能的升降级按钮的状态
		if(SelectedAbility.Ability.MatchesTagExact(AbilityTag))
		{
			SelectedAbility.Status = StatusTag;

			BroadcastSpellGlobeSelected(); //广播升降级按钮状态
		}

		//广播技能数据更新,用于更新技能按钮显示状态
		if(AbilityInfo)
		{
			FRPGAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(AbilityTag); //获取到技能数据
			Info.StatusTag = StatusTag;
			AbilityInfoDelegate.Broadcast(Info);
		}
	});

	//绑定技能点变动回调
	GetRPGPS()->OnSpellPointsChangedDelegate.AddLambda([this](const int32 SpellPoints)
	{
		SpellPointChanged.Broadcast(SpellPoints); //广播拥有的技能点

		CurrentSpellPoints = SpellPoints;

		BroadcastSpellGlobeSelected(); //广播升降级按钮状态
	});
}

实现技能的升级降级功能

接下来,我们要实现技能的升降级的功能。我们在技能面板控制器增加两个函数,一个用于升级按钮调用函数,另一个用于降级按钮调用函数。

UFUNCTION(BlueprintCallable)
void SpendPointButtonPressed(const FGameplayTag& AbilityTag); //升级按钮调用函数

UFUNCTION(BlueprintCallable)
void DemotionPointButtonPressed(const FGameplayTag& AbilityTag); //降级按钮调用函数

void USpellMenuWidgetController::SpendPointButtonPressed(const FGameplayTag& AbilityTag)
{
	if(GetRPGASC())
	{
		GetRPGASC()->ServerSpendSpellPoint(AbilityTag); //调用ASC等级提升函数
	}
}

void USpellMenuWidgetController::DemotionPointButtonPressed(const FGameplayTag& AbilityTag)
{
	if(GetRPGASC())
	{
		GetRPGASC()->ServerDemotionSpellPoint(AbilityTag); //调用ASC降低技能等级
	}
}

然后在自定义ASC中实现两个处理函数,这两个函数只在服务器端执行,然后将修改结果同步到客户端

UFUNCTION(Server, Reliable)
void ServerSpendSpellPoint(const FGameplayTag& AbilityTag); //只在服务器端运行,消耗技能点函数提升技能等级

UFUNCTION(Server, Reliable)
void ServerDemotionSpellPoint(const FGameplayTag& AbilityTag); //只在服务器端运行,降低技能返回技能点

在提升技能等级的函数里,我们首先判断技能实例是否存在防止出错,然后减少可分配技能点,根据技能的状态标签进行处理
如果技能状态是可解锁,那么,提升等级后,技能状态标签将修改为未解锁状态
将技能等级提升一级,并将技能状态设置为立即同步到客户端

void URPGAbilitySystemComponent::ServerSpendSpellPoint_Implementation(const FGameplayTag& AbilityTag)
{
	//获取到技能实例
	if( FGameplayAbilitySpec* AbilitySpec = GetSpecFromAbilityTag(AbilityTag))
	{
		//减少一个可分配的技能点
		if(GetAvatarActor()->Implements<UPlayerInterface>())
		{
			IPlayerInterface::Execute_AddToSpellPoints(GetAvatarActor(), -1);
		}
		//获取状态标签
		FRPGGameplayTags GameplayTags = FRPGGameplayTags::Get();
		FGameplayTag StatusTag = GetStatusTagFromSpec(*AbilitySpec);
		//根据状态标签处理
		if(StatusTag.MatchesTagExact(GameplayTags.Abilities_Status_Eligible))
		{
			//技能升级,如果是可解锁状态,将状态标签从可解锁,切换为已解锁
			AbilitySpec->DynamicAbilityTags.RemoveTag(GameplayTags.Abilities_Status_Eligible);
			AbilitySpec->DynamicAbilityTags.AddTag(GameplayTags.Abilities_Status_Unlocked);
			StatusTag = GameplayTags.Abilities_Status_Unlocked;
			//提升技能等级
			AbilitySpec->Level += 1;
		}
		else if(StatusTag.MatchesTagExact(GameplayTags.Abilities_Status_Equipped) || StatusTag.MatchesTagExact(GameplayTags.Abilities_Status_Unlocked))
		{
			AbilitySpec->Level += 1;
		}
		ClientUpdateAbilityStatus(AbilityTag, StatusTag, AbilitySpec->Level); //广播技能状态修改
		MarkAbilitySpecDirty(*AbilitySpec); //设置当前技能立即复制到每个客户端
	}
}

而在降级函数里,我们是增加一点可分配点数,并减少技能的等级

void URPGAbilitySystemComponent::ServerDemotionSpellPoint_Implementation(const FGameplayTag& AbilityTag)
{
	//获取到技能实例
	if( FGameplayAbilitySpec* AbilitySpec = GetSpecFromAbilityTag(AbilityTag))
	{
		//增加一个可分配的技能点
		if(GetAvatarActor()->Implements<UPlayerInterface>())
		{
			IPlayerInterface::Execute_AddToSpellPoints(GetAvatarActor(), 1);
		}
		//获取状态标签
		FRPGGameplayTags GameplayTags = FRPGGameplayTags::Get();
		FGameplayTag StatusTag = GetStatusTagFromSpec(*AbilitySpec);
		
		if(StatusTag.MatchesTagExact(GameplayTags.Abilities_Status_Equipped) || StatusTag.MatchesTagExact(GameplayTags.Abilities_Status_Unlocked))
		{
			AbilitySpec->Level -= 1;
			if(AbilitySpec->Level < 1)
			{
				//技能小于1级,当前技能将无法装配,直接设置为可解锁状态
				AbilitySpec->DynamicAbilityTags.RemoveTag(GameplayTags.Abilities_Status_Equipped);
				AbilitySpec->DynamicAbilityTags.RemoveTag(GameplayTags.Abilities_Status_Unlocked);
				AbilitySpec->DynamicAbilityTags.AddTag(GameplayTags.Abilities_Status_Eligible);
				StatusTag = GameplayTags.Abilities_Status_Eligible;
			}
		}
		
		ClientUpdateAbilityStatus(AbilityTag, StatusTag, AbilitySpec->Level); //广播技能状态修改
		MarkAbilitySpecDirty(*AbilitySpec); //设置当前技能立即复制到每个客户端
	}
}

而在里面的广播函数,是我们新增的函数,用于只在客户端广播的函数

	UFUNCTION(Client, Reliable)
	void ClientUpdateAbilityStatus(const FGameplayTag& AbilityTag, const FGameplayTag& StatusTag, int32 AbilityLevel); //技能状态更新后回调

我们对其进行了修改,增加了技能等级的广播

void URPGAbilitySystemComponent::ClientUpdateAbilityStatus_Implementation(const FGameplayTag& AbilityTag, const FGameplayTag& StatusTag, const int32 AbilityLevel)
{
	AbilityStatusChanged.Broadcast(AbilityTag, StatusTag, AbilityLevel);
}

接着我们在技能按钮上增加一个显示等级的文本框
在这里插入图片描述
设置选中时显示技能等级,未选中时,不再显示
在这里插入图片描述
在结构体增加了技能等级的缓存

//在技能面板选中的技能的标签结构体
struct FSelectedAbility
{
	FGameplayTag Ability = FGameplayTag(); //技能标签
	FGameplayTag Status = FGameplayTag(); //技能状态标签
	int32 Level = 0; //技能等级
};

在回调里面设置设置等级
在这里插入图片描述
在这里插入图片描述
在控制器广播回调这里,我们也增加了一个对等级的广播
在这里插入图片描述
并在UI这里监听委托回函函数里修改技能等级
在这里插入图片描述
在这里插入图片描述
然后我们绑定技能按钮升降级按钮点击回调,调用控制器函数
在这里插入图片描述
接着测试
在这里插入图片描述

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

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

相关文章

AI入门指南(二):算法、训练、模型、大模型是什么?

文章目录 一、前言二、算法是什么&#xff1f;概念实际应用 三、训练是什么&#xff1f;概念实际应用 四、模型是什么&#xff1f;概念实际应用小结 五、大模型是什么&#xff1f;概念模型和小模型有什么区别&#xff1f;大模型分类实际应用 六、总结七、参考资料 一、前言 人…

宠物空气净化器对浮毛有效果吗?宠物空气净化器十大排名使用体验

宠物空气净化器对浮毛有效果吗&#xff1f;宠物空气净化器能够通过过滤和吸附作用&#xff0c;减少室内空气中的浮毛。不过&#xff0c;随着宠物空气净化器市场的火爆&#xff0c;许多商家企图从中分一杯羹&#xff0c;为了快速的进入市场缺少产品的研发&#xff0c;导致市面上…

海南云亿商务咨询有限公司怎么样正规吗?

在这个日新月异的数字时代&#xff0c;电商行业正以前所未有的速度蓬勃发展&#xff0c;而抖音作为短视频与社交电商的完美融合体&#xff0c;更是开辟了一片充满无限可能的电商新蓝海。在这片浪潮中&#xff0c;海南云亿商务咨询有限公司凭借敏锐的市场洞察力和专业的服务能力…

docker部署datahub

快速安装&#xff0c;有网环境用&#xff0c;但是我没有用 pip3 install datahub datahub docker quickstart一、安装并启动datahub #python安装客户端 pip3 install datahub #导入镜像 (base) [rootb28-16p4p170-lijia lijia]# ls *.tar cp-kafka.tar datahub-ac…

【ARM】ARM Cortex 处理器详细讲解

目录 ARM Cortex处理器详细讲解1. Cortex-A系列1.1 概述1.2 架构和版本**ARMv7-A****ARMv8-A****ARMv9-A** 1.3 关键特性1.4 应用场景 2. Cortex-M系列2.1 概述2.2 架构和版本**ARMv6-M****ARMv7-M****ARMv8-M** 2.3 关键特性2.4 应用场景 3. Cortex-R系列3.1 概述3.2 架构和版…

SVM支持向量机(Support Vectors Mechine)

SVM支持向量机&#xff08;Support Vector Mechine&#xff09; SVM是一种监督学习算法&#xff0c;常用于解决二分类问题&#xff08;也可以解决多分类问题&#xff09;&#xff0c;它可以处理线性可分的数据&#xff0c;同时也可以处理线性不可分的数据&#xff0c;广泛应用…

力扣Hot100-230二叉搜索树中第K小的元素

&#xff08;一&#xff09;题目 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;…

人工智能系统测试的流程与生命周期

今天我们一起来看一下&#xff0c;人工智能系统究竟应该用什么样的流程和方法去进行测试呢&#xff1f; 首先我们一起来看一下&#xff0c;一个企业的人工智能产品部署和发布的一个流程&#xff0c;首先企业会从历史数据库中&#xff0c;利用数据去训练出一个初始的模型&#x…

【C++深度探索】红黑树实现Set与Map的封装

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目录…

Comfyui线稿转绘工作流 一键掉进彩色世界

前言 在数字艺术的世界里&#xff0c;线稿转绘无疑是将创意从简单的线条变成生动图画的关键一步。而在众多工具中&#xff0c;ComfyUI的线稿转绘工作流以其便捷和高效&#xff0c;赢得了众多艺术家的青睐。 本文将详细介绍ComfyUI线稿转绘工作流的应用场景和优势&#xff0c;…

C语言典型例题29

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题2.6 设圆半径r1.5&#xff0c;圆柱高h3&#xff0c;求圆周长、圆面积、圆球表面积、圆球体积、圆柱体积。 scanf输入结果&#xff0c;输出计算结果&#xff0c;输出时要有文字说明&#xff0c;取小数点后两位数…

优质电器/机械岗位推荐:经验不限大厂直招,薪资最高30K!

本周优质电器/机械岗位推荐&#xff0c;涵盖C、自动化、开发、安卓开发、项目管理等岗位&#xff0c;经验不限&#xff0c;更有大厂直招岗位&#xff0c;薪资最高30K&#xff01;&#xff01; 抓紧投递&#xff0c;早投早入职&#xff01; &#x1f447;点击职位名称查看详情…

数据结构(java实现)——优先级队列,堆

文章目录 优先级队列堆堆的概念堆的模拟实现创建堆入堆判满删除判空获取栈顶元素 创建堆两种方式的时间复杂度堆排序java提供的PriorityQueue类基本的属性关于PriorityQueue类的三个构造方法关于PriorityQueue类中&#xff0c;入堆方法是怎样实现的&#xff1f;PriorityQueue注…

基于GA-PSO-SVM算法的混沌背景下微弱信号检测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 支持向量机&#xff08;SVM&#xff09; 4.2 GA-PSO-SVM算法 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) svm参数取值对检测性能的影响&#xff1a; SVM,PSO,…

华为Mate 60系列推送最新132版本有惊喜!你收到了吗?

华为Mate 60系列又悄悄搞事情&#xff0c;带了个大惊喜——手机获推HarmonyOS 4.2.0.132&#xff0c;一起来看看优化了什么&#xff1f; 首先更新的就是相机效果&#xff0c;从色彩精准度与拍照预览一致性上更加精益求精&#xff0c;上大分&#xff01; 色彩呈现更准确&#x…

基于Java中的SSM框架实现校园图书在线阅读系统项目【项目源码+论文说明】

基于Java中的SSM框架实现校园图书在线阅读系统演示 摘要 随着计算机的广泛应用和推广&#xff0c;越来越多的传统人工管理模式逐渐被线上化平台系统所替代&#xff0c;高校作为知识的学府在计算机的应用上非常广泛&#xff0c;同时随着近年来高校信息化建设的不断提升&#xf…

PDF编辑不求人!这三款免费版编辑器助你轻松搞定!

作为一名办公室文员&#xff0c;每天和PDF文件打交道那是家常便饭。打印合同、整理报告、编辑资料&#xff0c;PDF文件简直就是我的工作小伙伴。不过&#xff0c;说起编辑PDF&#xff0c;那可真是个技术活。以前&#xff0c;我总是为这事儿头疼&#xff0c;直到遇见了几款pdf编…

JVM知识总结(内存结构)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 内存模型 内存结构 堆&#xff1a; 存放对象实例, 几乎所有的对象…

Candance Allegro 入门教程笔记:如何绘制原理图和原理图库?

文章目录 一、用 Capture CIS 17.4 绘制原理图库 一、用 Capture CIS 17.4 绘制原理图库 1、安装完Candance Allegro 17.4后&#xff0c;我们所需的原理图工具以及PCB工具如下图所示&#xff1a;【Capture CIS 17.4】和【PCB Editor 17.4】 2、打开原理图工具&#xff1a;Captu…

React性能之--如何避免组件重复渲染?

在react中&#xff0c;我们会发现存在组件会重复渲染&#xff0c;虽然说如果项目不大的话&#xff0c;这点影响不大&#xff0c;但是我们还是尽量避免组件渲染比较好&#xff0c;养成好习惯&#xff0c;尽可能让不管是大小项目&#xff0c;都让性能尽可能优化 。那我们如何避免…