UE5学习笔记23-给角色添加血量,添加收到伤害的功能

news2024/12/25 23:56:49

零、一些游戏框架知识

        1.UE5中包含游戏模式类(Game Mode)、游戏状态类(Game State)、玩家状态类(Player State)、玩家控制器类(Player Controller)、所有的可以被控制的实体或角色类(Pawn)、窗口类(HUD/Widget)

        Game Mode:存在在服务器上,当我们在客户端访问该类时获得的指针回事一个空指针

        Game State:存在在服务器上和所有的客户端上,可以将服务器上的数据复制到游戏状态类的客户端中

        Player State:存在在服务器上和所有客户端上

        Player Controller:存在在服务器上和自己的客户端上

        Pawn:存在在服务器上和所有客户端上

        HUD/Widget:存在在自己的客户端上

        2.Player Controller类可以访问HUD类

        3.服务器上存在Game Mode、Game State、所有的Player State、所有的Player Controller、所有的Pawn、

        4.Player Controller 可以访问当前客户端的Player State

        5.玩家状态的网络更新比角色更新速度慢

一、创建血条界面

        1.创建界面蓝图

        2.选择UserWidget

        3.界面中的控件如图

        4.创建UserWidget的C++类

        5.将之前创建的窗口的蓝图类的父类设置成在4中创建的C++类的类名(如图左下角父类设置)

        6.C++类中的代码如下

        头文件(注意不要写错变量名字和界面中的名字一定要相同)

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CharacterOverLay.generated.h"

/**
 * 
 */
UCLASS()
class BLASTER_API UCharacterOverLay : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UPROPERTY(meta = (Bindwidget))
	class UProgressBar* HealthBar;

	UPROPERTY(meta = (Bindwidget))
	class UTextBlock* HealthText;

	UPROPERTY(meta = (Bindwidget))
	UTextBlock* ScoreAmount;

	UPROPERTY(meta = (Bindwidget))
	UTextBlock* DefeatsAmount;
};

         源文件

创建之后不用管它源文件中没有写代码

        7.添加在界面显示的功能,我在之前绘制界面准心的类中重写了BeginPlay函数

        头文件(不要忘记在界面中设置变量CharacterOverlayClass的值)

public:
    UPROPERTY(EditAnywhere, Category = "Play States")
	TSubclassOf<class UUserWidget> CharacterOverlayClass;

	class UCharacterOverLay* CharacterOverlay;

protected:
	virtual void BeginPlay() override;
	void AddCharacterOverlay();

        源文件

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

	AddCharacterOverlay();
}

void AABasterHUD::AddCharacterOverlay()
{
	APlayerController* PlayController = GetOwningPlayerController();

	if (PlayController && CharacterOverlayClass)
	{
		CharacterOverlay = CreateWidget<UCharacterOverLay>(PlayController, CharacterOverlayClass);
		CharacterOverlay->AddToViewport();
	}
}

 二、更新血条状态跟新得分分数

        1.通过PlayerController可以访问HUD控件类,所以在PlayerController类中代码如下

        头文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "BlasterPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class BLASTER_API ABlasterPlayerController : public APlayerController
{
	GENERATED_BODY()
public:
	void SetHUDHealth(float Health , float MaxHealth);
	void SetHUDScore(float Score);
	void SetHUDDefeats(int32 Defeats);
	void OnPossess(APawn* IaPawn) override;

protected:
	virtual void BeginPlay() override;

private:
	UPROPERTY()
	class AABasterHUD* BlasterHUD;
};

        源文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "BlasterPlayerController.h"
#include "Blaster/HUD/ABasterHUD.h"
#include "Blaster/HUD/CharacterOverLay.h"
#include "Components/ProgressBar.h"
#include "Components/TextBlock.h"
#include "Blaster/Character/BlasterCharacter.h"

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

	BlasterHUD = Cast<AABasterHUD>(GetHUD());
}

void ABlasterPlayerController::OnPossess(APawn* IaPawn)
{
	Super::OnPossess(IaPawn);

	ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(IaPawn);
	if (BlasterCharacter)
	{
		SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth());
	}
}

void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth)
{
	BlasterHUD = BlasterHUD == nullptr ? Cast<AABasterHUD>(GetHUD()) : BlasterHUD;

	bool bHUDValid = BlasterHUD &&
		BlasterHUD->CharacterOverlay &&
		BlasterHUD->CharacterOverlay->HealthBar &&
		BlasterHUD->CharacterOverlay->HealthText;
	if (bHUDValid)
	{
		const float HealthPercent = Health / MaxHealth;
		BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent);
		FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth)); // CeilToInt向上取整
		BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText));
	}
}

void ABlasterPlayerController::SetHUDScore(float Score)
{
	BlasterHUD = BlasterHUD == nullptr ? Cast<AABasterHUD>(GetHUD()) : BlasterHUD;
	bool bHUDValid = BlasterHUD &&
		BlasterHUD->CharacterOverlay &&
		BlasterHUD->CharacterOverlay->ScoreAmount;
	if (bHUDValid)
	{
		FString ScoreText = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score)); // FloorToInt 向下取整
		BlasterHUD->CharacterOverlay->ScoreAmount->SetText(FText::FromString(ScoreText));
	}
}

void ABlasterPlayerController::SetHUDDefeats(int32 Defeats)
{
	BlasterHUD = BlasterHUD == nullptr ? Cast<AABasterHUD>(GetHUD()) : BlasterHUD;
	bool bHUDValid = BlasterHUD &&
		BlasterHUD->CharacterOverlay &&
		BlasterHUD->CharacterOverlay->DefeatsAmount;
	if (bHUDValid)
	{
		FString DefeatsText = FString::Printf(TEXT("%d"), Defeats); // FloorToInt 向下取整
		BlasterHUD->CharacterOverlay->DefeatsAmount->SetText(FText::FromString(DefeatsText));
	}
}

        2.我想在角色类中设置血量

        角色类头文件

	/**
	*	玩家健康状态
	*/

	UPROPERTY(EditAnywhere, Category = "Platyer Stats")
	float MaxHealth = 100.f;//玩家的最大血量

	UPROPERTY(ReplicatedUsing = OnRep_Health, VisibleAnywhere, Category = "Platyer Stats")
	float Health = 100.f;//玩家当前血量

	UFUNCTION()
	void OnRep_Health();//当人物当前血量改变时执行函数

	class ABlasterPlayerController* BlasterPlayerController;

/* 更新界面血量函数 */
void UpdateHUDHealth();
/* 更新界面血量函数 */
/* 等待玩家状态存在后更新界面HUD */
void PollInit();
/* 等待玩家状态存在后更新界面HUD */

        角色类源文件


void ABlasterCharacter::UpdateHUDHealth()
{
	BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
	if (BlasterPlayerController)
	{
		BlasterPlayerController->SetHUDHealth(Health, MaxHealth);
	}
}

void ABlasterCharacter::PollInit()
{
	if (BlasterPlayerState == nullptr)
	{
		BlasterPlayerState = GetPlayerState<ABlasterPlayerState>();
		if (BlasterPlayerState)
		{
			BlasterPlayerState->AddToScore(0.f);
			BlasterPlayerState->AddToDefeats(0);
		}
	}
}


void ABlasterCharacter::OnRep_Health()
{
	UpdateHUDHealth();
}

void ABlasterCharacter::UpdateHUDHealth()
{
	BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
	if (BlasterPlayerController)
	{
		BlasterPlayerController->SetHUDHealth(Health, MaxHealth);
	}
}

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

	UpdateHUDHealth();
}

实现PlayerState类

        头文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "BlasterPlayerState.generated.h"

/**
 * 
 */
UCLASS()
class BLASTER_API ABlasterPlayerState : public APlayerState
{
	GENERATED_BODY()
public:
	virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const override;
	/**
	*	复制通知
	*/
	virtual void OnRep_Score() override;
	UFUNCTION()
	virtual void OnRep_Defeats();
	void AddToScore(float ScoreAmount);

	void AddToDefeats(int32 DefeatsAmount);
private:
	class ABlasterCharacter* Character;
	class ABlasterPlayerController* Controller;

	UPROPERTY(ReplicatedUsing = OnRep_Defeats)
	int32 Defeats;

	
};

        源文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "BlasterPlayerState.h"
#include "Blaster/Character/BlasterCharacter.h"
#include "Blaster/PlayerController/BlasterPlayerController.h"
#include "Net/UnrealNetwork.h"

void ABlasterPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(ABlasterPlayerState, Defeats);
}

void ABlasterPlayerState::OnRep_Score()
{
	Super::OnRep_Score();

	Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
	if (Character)
	{ 
		Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
		if (Controller)
		{
			Controller->SetHUDScore(Score);
		}
	}
}

void ABlasterPlayerState::AddToScore(float ScoreAmount)
{
	SetScore(GetScore() + ScoreAmount);
	Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
	if (Character)
	{
		Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
		if (Controller)
		{
			Controller->SetHUDScore(Score);
		}
	}
}

void ABlasterPlayerState::OnRep_Defeats()
{
	Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
	if (Character)
	{
		Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
		if (Controller)
		{
			Controller->SetHUDDefeats(Defeats);
		}
	}
}

void ABlasterPlayerState::AddToDefeats(int32 DefeatsAmount)
{
	Defeats += DefeatsAmount;
	Character = Character == nullptr ? Cast<ABlasterCharacter>(GetPawn()) : Character;
	if (Character)
	{
		Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
		if (Controller)
		{
			Controller->SetHUDDefeats(Defeats);
		}
	}
}

三、添加角色收到伤害功能

        1.根据子弹类创建新的C++类,命名为ProjectileBullet

        2. 在子弹类中我定义了OnHit()函数去处理当子弹碰到物体时的逻辑,同时OnHit是一个Virtual的函数

        头文件

protected:
	
	virtual void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) override;

        源文件

void AProjectileBullet::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	/** 
	* float ApplyDamage(
	*	AActor* DamagedActor,   // 受伤的对象
	*	float BaseDamage,       // 施加的基础伤害值
	*	AController* EventInstigator, // 伤害事件的控制者,通常是攻击者的控制器
	*	AActor* DamageCauser,   // 造成伤害的对象,例如武器或攻击者
	*	TSubclassOf<UDamageType> DamageTypeClass // 指定伤害的类型,继承自 UDamageType
	*	);
	*/
	ACharacter* OwnerCharacter = Cast<ACharacter>(GetOwner());
	if (OwnerCharacter)
	{
		AController* OwnerController = OwnerCharacter->Controller;
		if (OwnerController)
		{
			UGameplayStatics::ApplyDamage(OtherActor, Damage, OwnerController,this,UDamageType::StaticClass());
		}
	}

	Super::OnHit(HitComponent, OtherActor, OtherComp, NormalImpulse, Hit);
}

        3.在子弹类中添加子弹伤害的变量

public:	
	UPROPERTY(EditAnywhere)
	float Damage = 20.f;//武器伤害

        4.在角色类中添加收到伤害的功能

        头文件

/* 接收伤害的回调函数 */
UFUNCTION()
void ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, class AController* InstigatorController, AActor* DamageCauser);
/* 接收伤害的回调函数 */

        源文件 (BeginPlay中绑定受到伤害的代理)

// Called when the game starts or when spawned
void ABlasterCharacter::BeginPlay()
{
	Super::BeginPlay();

	if (HasAuthority())
	{
		OnTakeAnyDamage.AddDynamic(this,&ABlasterCharacter::ReceiveDamage);
	}
}

void ABlasterCharacter::ReceiveDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, AActor* DamageCauser)
{
	Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);
	UpdateHUDHealth();
	PlayHitRecatMontage();

	if (Health == 0.f)
	{
		ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode<ABlasterGameMode>();
		if(BlasterGameMode)
		{
			BlasterPlayerController = BlasterPlayerController == nullptr ? Cast<ABlasterPlayerController>(Controller) : BlasterPlayerController;
			ABlasterPlayerController* AttackerController = Cast<ABlasterPlayerController>(InstigatorController);
			BlasterGameMode->PlayterEliminated(this,BlasterPlayerController, AttackerController);
		}
	}
}

四、给角色添加分数的游戏规则

        1.创建新的C++类

        2.代码实现

        头文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"
#include "BlasterGameMode.generated.h"

/**
 * 
 */
UCLASS()
class BLASTER_API ABlasterGameMode : public AGameMode
{
	GENERATED_BODY()
public:
	virtual void PlayterEliminated(class ABlasterCharacter* ElimmedCharacter, class ABlasterPlayerController* VictimController, ABlasterPlayerController* AttackerController);
	virtual void RequestRespawn(ACharacter* ElimedCharacter, AController* ElimedController);
};

         源文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "BlasterGameMode.h"
#include "Blaster/Character/BlasterCharacter.h"
#include "Blaster/PlayerController/BlasterPlayerController.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/PlayerStart.h"
#include "Blaster/PlayerState/BlasterPlayerState.h"

void ABlasterGameMode::PlayterEliminated(ABlasterCharacter* ElimmedCharacter, ABlasterPlayerController* VictimController, ABlasterPlayerController* AttackerController)
{
	ABlasterPlayerState* AttackerPlayerState = AttackerController ? Cast<ABlasterPlayerState>(AttackerController->PlayerState) : nullptr;
	ABlasterPlayerState* VictimPlayerState = VictimController ? Cast<ABlasterPlayerState>(VictimController->PlayerState) : nullptr;

	if (AttackerPlayerState && AttackerPlayerState != VictimPlayerState)
	{
		AttackerPlayerState->AddToScore(1.f);
	}

	if (VictimPlayerState)
	{
		VictimPlayerState->AddToDefeats(1);
	}

	if (ElimmedCharacter)
	{
		ElimmedCharacter->Elim();
	}
}

void ABlasterGameMode::RequestRespawn(ACharacter* ElimedCharacter, AController* ElimedController)
{
	if (ElimedCharacter)
	{
		ElimedCharacter->Reset();
		ElimedCharacter->Destroy();
	}
	if (ElimedController)
	{
		TArray<AActor*> PlayerStart;
		UGameplayStatics::GetAllActorsOfClass(this, APlayerStart::StaticClass(), PlayerStart);
		int32 Selection = FMath::RandRange(0, PlayerStart.Num() - 1);
		RestartPlayerAtPlayerStart(ElimedController, PlayerStart[Selection]);
	}
}

        3.若角色从新生成失败更改如下配置

        4.代码中的PlayerStart是场景中的玩家出生点,多放几个试试

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

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

相关文章

扣绩效工资,违反劳动法吗?

将工资拆分成绩效工资和岗位工资是很多公司管理员工的一种常见方式。 其中绩效工资跟KPI强挂钩&#xff0c;如果当月没有达到公司绩效标准&#xff0c;那么公司就会扣绩效工资。 那扣绩效工资违反劳动法吗&#xff1f;HR应该如何进行绩效薪酬考核和发放&#xff1f; 扣绩效工…

【网络安全】Cookie与ID未强绑定导致账户接管

未经许可,不得转载。 文章目录 前言正文前言 DigiLocker 是一项在线服务,旨在为公民提供一个安全的数字平台,用于存储和访问重要的文档,如 Aadhaar 卡、PAN 卡和成绩单等。DigiLocker 通过多因素身份验证(MFA)来保护用户账户安全,通常包括 6 位数的安全 PIN 和一次性密…

大论文记录

基础知识回顾 1.强化学习&#xff08;Agent、Environment) 在 RL 中&#xff0c;代理通过不断与环境交互、以试错的方式进行学习&#xff0c;在不确定性下做出顺序决策&#xff0c;并在探索&#xff08;新领域&#xff09;和开发&#xff08;使用从经验中学到的知识&#xff…

五、Java 注释

一、Java 注释 在计算机语言中&#xff0c;注释是计算机语言的一个重要组成部分&#xff0c;用于在源代码中解释代码的作用&#xff0c;可以增强程序的可读性&#xff0c;可维护性。Java 注释是一种在 Java 程序中用于提供代码功能说明的文本。注释不会被编译器包含在最终的可…

数据清洗第3篇章 - 数据异常处理

数据清洗是数据分析过程中至关重要的一步&#xff0c;它确保数据的准确性、一致性和完整性。这不仅有助于提高分析结果的可靠性和有效性&#xff0c;还能为算法建模决策提供高质量的数据基础。在进行数据分析和建模的过程中&#xff0c;大量的时间花在数据准备上&#xff1a;加…

WebRTC Connection Negotiate解决

最近有个项目 &#xff0c;部署之后一直显示&#xff0c;查了一些资料还是没有解决&#xff0c;无奈只有自己研究解决&#xff1f; 什么是内网穿透&#xff1f; 我们访问我们自己的官网产品页面&#xff0c;我们的服务器是一个单独的个体&#xff0c;有独立的公网ip&#xf…

【Canvas与徽章】金圈蓝底国庆75周年徽章

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金边黑盾75周年</title><style type"text/css"&g…

关于深度学习torch的环境配置问题

已经下好了torch在虚拟环境中&#xff0c;结果在ipynb文件中无法运行 后来在终端直接用python语句编译 发现没有问题 在编辑测试py文件 发现runcode有问题 原来是插件默认base环境 具体操作参考VS Code插件Code Runner使用python虚拟环境_coderunner怎么在虚拟环境中使用-CSD…

“2024光明多多垂直农业挑战赛”决赛启动成功举办

由光明食品集团所属上花集团的光明花博邨基地&#xff0c;与拼多多携手&#xff0c;联合中国农业大学、浙江大学等共同举办的“2024光明多多垂直农业挑战赛暨第四届多多农研科技大赛”于9月20-21日正式启动决赛。来自上海交大、中国农大、上海农科院、国家农业智能装备工程技术…

资源《Arduino 扩展板4-单游戏摇杆》说明。

资源链接&#xff1a; Arduino 扩展板4-单游戏摇杆 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;AD工程、原理图、PCB。 3.内容展示 4.简述 该文件为PCB工程&#xff0c;采用AD做的。 该文件打板后配合Arduino使用&#xff0c;属于Arduino的扩展板。 该文件…

STM32 GPIO - 笔记

输出: - 推挽 - 输出高低电平都由芯片决定 - 开漏 - 输出低电平有芯片输出,输出高电平由外部电路决定 输入: - 浮空 - 输入电平不确定 - 上拉 - 输入电平拉高 - 下拉 - 输入电平拉低

【网路通信基础与实践番外二】TCP协议的流量控制和拥塞控制以及二者区别和例题

TCP协议是端对端的协议&#xff0c;因此在数据进行传输的过程受发送方&#xff0c;数据通道&#xff0c;接收方三方状态的影响。我们用水龙头来比喻数据发送方&#xff0c;水管来比喻数据通道&#xff0c;水桶来表示数据接收方。 图(a)表示水桶太小&#xff0c;来不及接受注入…

SpringBoot使用@Slf4j注解实现日志输出

Slf4j 是 Lombok 库中的一个注解&#xff0c;它极大地简化了日志记录的代码。通过使用这个注解&#xff0c;Lombok 会自动在你的类中注入一个静态的日志对象。通过在类上添加 Slf4j 注解后&#xff0c;可以直接在方法中使用 log.info() 等方法进行日志打印。 1、安装相关依赖 …

基于RBAC的通用权限管理系统的详细分析与实现(理念篇——权限对象、权限项、功能权限、数据权限、权限组、权限设计)

一、权限&#xff08;Permission&#xff09; 在与人沟通的过程中&#xff0c;我们很多次提到了权限&#xff0c;但是权限具体的含义每个人理解的含义都不明确&#xff0c;这样很容易造成双方信息不对称&#xff0c;有的人就只是把权限理解成某个页面的是否可访问&#xff0c;…

超级干货:Air780EP AT开发之FTP应用

是时候讲一讲Air780EP模组FTP应用的多个AT命令示例&#xff0c;因为很多小伙伴已经提出要求了。 Air780EP是低功耗4G模组之一&#xff0c;支持全系列的AT指令以及LuatOS脚本二次开发。 一、准备工作 1.1 硬件准备 合宙EVB_Air780EP开发板一套&#xff0c;包括天线、SIM卡&am…

TXT文本文档内容整理归档,一键批量操作管理避免出错

在当今的信息化时代&#xff0c;文档管理成为了企业日常运营中不可或缺的一部分。其内容的合并管理更是显得尤为重要。避免在合并过程中出现格式混乱或内容丢失的情况&#xff0c;本文将探讨如何实现TXT文档内容的合并管理。 1.运行软件切换到“文本批量操作”功能版块上 2.在…

基于单片机汽车尾灯控制系统

**单片机设计介绍&#xff0c;基于单片机汽车尾灯控制系统设计 文章目录 前言概要设计思路 软件设计效果图 程序文章目录 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、…

超轻巧modbus调试助手使用说明

一、使用说明 1.1 数据格式 和其他的modbus采集工具一样&#xff0c;本组件也支持各种数据格式&#xff0c;其实就是高字节低字节的顺序。一般是2字节表示一个数据&#xff0c;后面又有4字节表示一个数据&#xff0c;目前好像还有8字节表示一个数据的设备。不同厂家的设备对应…

[Linux]Shell基本

入门 变量 运算符 语句 循环 控制台输入 函数

薄膜凸起和开裂是同一种应力导致的吗?

知识星球里的学员问&#xff1a;我们产线上薄膜出了质量问题&#xff0c;都一概归结为应力过大。麻烦讲讲应力的种类&#xff0c;以及不同种类的应力会造成哪些薄膜问题&#xff1f; 内应力的种类&#xff1f; 内应力的分类很多&#xff0c;如果我们按作用的效果来分&#xff…