当前位置: 首页 > news >正文

虚幻C++ day5

角色状态的常见机制

创建角色状态设置到UI上

  • 在MainPlayer.h中新建血量,最大血量,耐力,最大耐力,金币变量,作为角色的状态
	//主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe Stats")float Health;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe Stats")float MaxHealth;UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe Stats")float Stamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe Stats")float  MaxStamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe Stats")int Coins;
//初始化角色状态
MaxHealth = 100.f;
Health = MaxHealth;
MaxStamina = 200.f;
Stamina = MaxStamina;
Coins = 0;
  • 然后我们需要去血量与耐力的UI蓝图中去实时更新present(这个是采用的比例)
  • 思路:因为这些UI都是用在MainPlayer中,我们在蓝图中获取MianPlayer的引用,然后实例化,这样我们每次用到这个UI的时候都会去实例化MainPlayer,然后present绑定个函数用来实时同步present值(状态值除以最大状态值)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Stamina UI也是如此,运行结果
    在这里插入图片描述

添加状态更新函数

  • 添加三个函数,用来改变血量、耐力、金币的值

MainPlayer.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MainPlayer.generated.h"UCLASS()
class UEGAME_API AMainPlayer : public ACharacter
{GENERATED_BODY()public:// Sets default values for this character's propertiesAMainPlayer();//新建一个SpringArmUPROPERTY(visibleAnywhere,BlueprintReadOnly)class USpringArmComponent* SpringArm;//新建一个CameraUPROPERTY(visibleAnywhere, BlueprintReadOnly)class UCameraComponent* FollowCamera;float BaseTurnRate;		//使用键盘X转向的速率float BaseLookUpRate;	//使用键盘Y转向的速率//主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Health;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float MaxHealth;UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Stamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float  MaxStamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")int Coins;protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:	// Called every framevirtual void Tick(float DeltaTime) override;// Called to bind functionality to inputvirtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;//重新Character类中的Jump方法void Jump() override;void MoveForward(float value);void MoveRight(float value);void Turn(float Value);void LookUp(float Value);void TurnRate(float Rate);void LookUpRate(float Rate);//改变状态void AddHealth(float value);void AddStamina(float value);void AddCoin(float value);
};

MainPlayer.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "MainPlayer.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/CharacterMovementComponent.h"// Sets default values
AMainPlayer::AMainPlayer()
{// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));SpringArm->SetupAttachment(GetRootComponent());//设置SPringArm无碰撞臂长SpringArm->TargetArmLength = 600.f;SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));FollowCamera->SetupAttachment(SpringArm, NAME_None);FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假//设置胶囊体的默认宽高GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);//对Character的Pawn进行硬编码bUseControllerRotationPitch = false;bUseControllerRotationYaw = false;bUseControllerRotationRoll = false;//硬编码orient Rotation to Movement,给个默认转向速率GetCharacterMovement()->bOrientRotationToMovement = true;GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);//设置跳跃初始值与在空中的坠落时横向运动控制量GetCharacterMovement()->JumpZVelocity = 600.f;GetCharacterMovement()->AirControl = 0.15f;//给键盘控制转向的速率变量赋初值BaseTurnRate = 21.f;BaseLookUpRate = 21.f;//初始化角色状态MaxHealth = 100.f;Health = MaxHealth;MaxStamina = 200.f;Stamina = MaxStamina;Coins = 0;
}// Called when the game starts or when spawned
void AMainPlayer::BeginPlay()
{Super::BeginPlay();}// Called every frame
void AMainPlayer::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}// Called to bind functionality to input
void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{Super::SetupPlayerInputComponent(PlayerInputComponent);//检查PlayerInputComponent指针,check函数只能在这使用check(PlayerInputComponent);//绑定跳跃轴映射事件PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMainPlayer::Jump);//按下空格PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);//抬起空格//绑定移动轴映射事件PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);PlayerInputComponent->BindAxis("MoveRight", this, &AMainPlayer::MoveRight);//绑定Controller控制器去管理视角旋转PlayerInputComponent->BindAxis("Turn", this, &AMainPlayer::Turn);PlayerInputComponent->BindAxis("LookUp", this, &AMainPlayer::LookUp);//绑定键盘鼠标轴映射事件PlayerInputComponent->BindAxis("TurnRate", this, &AMainPlayer::TurnRate);PlayerInputComponent->BindAxis("LookUpRate", this, &AMainPlayer::LookUpRate);}void AMainPlayer::Jump()
{//继承父类的方法Super::Jump();
}void AMainPlayer::MoveForward(float value)
{if (Controller != nullptr && value != 0.f){//获取到Control旋转FRotator Rotation = Controller->GetControlRotation();//转向只关注水平Yaw方向,因此置0防止影响FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::X);AddMovementInput(Direction, value);}}void AMainPlayer::MoveRight(float value)
{if (Controller != nullptr && value != 0.f){//获取到Controller旋转FRotator Rotation = Controller->GetControlRotation();//转向只关注水平Yaw方向,因此置0防止影响FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::Y);AddMovementInput(Direction, value);}
}void AMainPlayer::Turn(float Value)
{if (Value != 0.f){AddControllerYawInput(Value);}}void AMainPlayer::LookUp(float Value)
{//UE_LOG(LogTemp, Warning, TEXT("%f"), GetControlRotation().Pitch);// //控制视角if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f){return;}else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f){return;}AddControllerPitchInput(Value);
}void AMainPlayer::TurnRate(float Rate)
{//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题float Value = Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds();if (Value != 0.f){AddControllerYawInput(Value);}
}void AMainPlayer::LookUpRate(float Rate)
{//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题float Value = Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds();//控制视角if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f){return;}else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f){return;}AddControllerPitchInput(Value);}void AMainPlayer::AddHealth(float value)
{Health = FMath::Clamp(Health + value, 0.f, MaxHealth);
}void AMainPlayer::AddStamina(float value)
{Stamina = FMath::Clamp(Stamina + value, 0.f, MaxStamina);
}void AMainPlayer::AddCoin(float value)
{Coins += value;
}

创建可交互物体的基类

  • 需求:这个可交互物体,应该可以播放粒子特效,所以我们需要粒子系统,然后有静态网格表示这个物体,作为基类,我们可以把所有的要求都写入里面,然后到时候创建子类继承来重写需求
  • 定义一个球形的触发器组件,静态网格,粒子组件与粒子系统,声音资源,进行多播委托事件,虚写多播委托函数,方便到时候子类继承重写
  • 可以自定义一下这个物体的旋转和碰撞类别
  • #include "Components/SphereComponent.h":球形碰撞器的头文件
  • #include "Particles/ParticleSystemComponent.h":粒子系统的头文件

InteroperableItem.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InteroperableItem.generated.h"UCLASS()
class UEGAME_API AInteroperableItem : public AActor
{GENERATED_BODY()public:	// Sets default values for this actor's propertiesAInteroperableItem();//球形触发器UPROPERTY(VisibleAnywhere, BlueprintReadWrite)class USphereComponent* TriggerVolume;UPROPERTY(VisibleAnywhere, BlueprintReadWrite)class UStaticMeshComponent* DisplayMesh;//粒子组件UPROPERTY(VisibleAnywhere, BlueprintReadWrite)class UParticleSystemComponent* ParticleEffectsComponent;//粒子资源UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interoperable Item|Particles")class UParticleSystem* Particle;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interoperable Item|Sounds")class USoundCue* Sound;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interoperable Item|Properties")bool bRotate;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interoperable Item|Properties")float RotationRate;  
protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:	// Called every framevirtual void Tick(float DeltaTime) override;//自定义AddDynamic绑定的触发器函数UFUNCTION()virtual void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);UFUNCTION()virtual void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);};

InteroperableItem.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "InteroperableItem.h"
#include "Components/SphereComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Particles/ParticleSystemComponent.h"
// Sets default values
AInteroperableItem::AInteroperableItem()
{// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;TriggerVolume = CreateDefaultSubobject<USphereComponent>(TEXT("TriggerVolume"));RootComponent = TriggerVolume;//设置TriggerVolume碰撞的硬编码TriggerVolume->SetCollisionEnabled(ECollisionEnabled::QueryOnly);//设置碰撞类型TriggerVolume->SetCollisionObjectType(ECollisionChannel::ECC_WorldStatic);//设置对象移动时其应视为某种物体TriggerVolume->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);//设置所有的碰撞响应为忽略TriggerVolume->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);//设置Pawn碰撞响应为重叠DisplayMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DisplayMesh"));DisplayMesh->SetupAttachment(GetRootComponent());ParticleEffectsComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleEffects"));ParticleEffectsComponent->SetupAttachment(GetRootComponent());bRotate = true;RotationRate = 45.f;
}// Called when the game starts or when spawned
void AInteroperableItem::BeginPlay()
{Super::BeginPlay();TriggerVolume->OnComponentBeginOverlap.AddDynamic(this, &AInteroperableItem::OnOverlapBegin);TriggerVolume->OnComponentEndOverlap.AddDynamic(this, &AInteroperableItem::OnOverlapEnd);}// Called every frame
void AInteroperableItem::Tick(float DeltaTime)
{Super::Tick(DeltaTime);if (bRotate){FRotator rotator = GetActorRotation();rotator.Yaw += RotationRate * DeltaTime;SetActorRotation(rotator);}
}void AInteroperableItem::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
}void AInteroperableItem::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
}

创建可交互基类的子类爆炸物

  • 创建一个继承自Interoperable类的子类Explosive
  • 新建一个伤害值,重写OnOverlapBegin与OnOverlapEnd事件函数,在OnOverlapBegin中判断角色是否触发到炸弹,然后生成发射器播放粒子效果与声音,之后销毁
AExplosiveItem::AExplosiveItem()
{Damage = 20.f;
}
void AExplosiveItem::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{Super::OnOverlapBegin(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);if (OtherActor){AMainPlayer* Player = Cast<AMainPlayer>(OtherActor);if (Player){//防御性编程if (Particle){//生成发射器UGameplayStatics::SpawnEmitterAtLocation(this, Particle, GetActorLocation(), FRotator(0.f), true);}if (Sound){UGameplayStatics::PlaySound2D(this, Sound);}//销毁Destroy();}}
}
  • 运行结果
    在这里插入图片描述
    在这里插入图片描述

爆炸物对玩家的伤害施加

  • 我们采用UE中内置的直接伤害附加的功能,在Explosive类中调用UGameplayStatics::ApplyDamage()函数传递伤害值,在MainPlayer类中重写TakeDamage方法,进行接收伤害并对玩家施加
  • UGameplayStatics::ApplyDamage():源码函数分析
  • 该函数接收五个参数:
    • DamagedActor: 受损的 actor。
    • BaseDamage: 基础损害值。
    • EventInstigator: 事件发起者,通常是施加损害的对象。
    • DamageCauser: 直接导致损害的 actor。
    • DamageTypeClass: 损害类型的类。
    • 该函数首先检查 DamagedActor是否存在以及 BaseDamage是否不为零。如果是这样,则继续执行;否则,返回零表示未造成任何损害。 接下来,设置损害事件 (FDamageEvent)并传入有效的损害类型类 (TSubclassOf 类型)。如果提供了 DamageTypeClass参数,则使用该类;否则,默认使用 UDamageType类。 最后,调用 DamagedActor 的 TakeDamage方法,将基础损害值(BaseDamage) 和损害事件 (DamageEvent)传入,并返回造成的总损害。 整个函数最终实现的功能是将基础损害值施加到指定的受损actor上,并返回造成的总损害。
float UGameplayStatics::ApplyDamage(AActor* DamagedActor, float BaseDamage, AController* EventInstigator, AActor* DamageCauser, TSubclassOf<UDamageType> DamageTypeClass)
{if ( DamagedActor && (BaseDamage != 0.f) ){// make sure we have a good damage typeTSubclassOf<UDamageType> const ValidDamageTypeClass = DamageTypeClass ? DamageTypeClass : TSubclassOf<UDamageType>(UDamageType::StaticClass());FDamageEvent DamageEvent(ValidDamageTypeClass);return DamagedActor->TakeDamage(BaseDamage, DamageEvent, EventInstigator, DamageCauser);}return 0.f;
}
  • TakeDamage():源码分析
  • 该方法接收四个参数:
    • Damage: 损害值。
    • DamageEvent: 损害事件。
    • EventInstigator: 事件发起者。
    • DamageCauser: 直接导致损害的 actor。
    • 方法首先调用 ShouldTakeDamage 成员方法以确定 pawn 是否应该受到损害。如果返回 false,则方法直接返回零表示未造成任何损害。 然后,方法调用基类 Super::TakeDamage 方法来处理损害,并将传入的所有参数都传递给它。在此过程中,损害值会被修改以反映抗性等因素的影响。 最后,方法响应所受损害。如果 event instigator存在并且与 pawn的控制器不同,则更新最后一个击中者为event instigator。此外,无论是否存在event instigator 或 event instigator是否与pawn控制器相同,都会进行进一步处理,以确保 pawn在遭受损害后能够做出相应的反应(如播放动画或发出声音)。
float APawn::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{if (!ShouldTakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser)){return 0.f;}// do not modify damage parameters after thisconst float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);// respond to the damageif (ActualDamage != 0.f){if ( EventInstigator && EventInstigator != Controller ){LastHitBy = EventInstigator;}}return ActualDamage;
}
  • Explosive.cpp
void AExplosiveItem::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{Super::OnOverlapBegin(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);if (OtherActor){AMainPlayer* Player = Cast<AMainPlayer>(OtherActor);if (Player){//防御性编程if (Particle){//生成发射器UGameplayStatics::SpawnEmitterAtLocation(this, Particle, GetActorLocation(), FRotator(0.f), true);}if (Sound){UGameplayStatics::PlaySound2D(this, Sound);}//传递伤害值UGameplayStatics::ApplyDamage(OtherActor, Damage, nullptr, this, DamageTypeClass);//销毁Destroy();}}
}
  • MainPlayer.h
//重写TakeDamage方法
float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
  • MainPlayer.cpp
float AMainPlayer::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{if (Health - Damage <= 0.f){Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);//TODO Die();}else{Health -= Damage;}return Health;
}
  • 在蓝图中选择伤害类型为直接伤害
    在这里插入图片描述

创建可拾取道具的基类(基础自InteroperableItem)

  • 基本与Explosive子类差不多,只不过可拾取的基类目前只需要碰撞检测与一个提供拾取的共有接口OnPick(蓝图化),这样到时候需求就可以去蓝图中可视化操作

PickItem.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GamePlay/InteroperableItem.h"
#include "PickItem.generated.h"/*** */
UCLASS()
class UEGAME_API APickItem : public AInteroperableItem
{GENERATED_BODY()public:APickItem();
public:void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) override;void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) override;UFUNCTION(BlueprintImplementEvent, Category = "Pick")void OnPick(class AMainPlayer* Palyer);
};

PickItem.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "PickItem.h"
#include "Kismet/GamePlayStatics.h"
#include "Characters/Player/MainPlayer.h"
#include "Sound/SoundCue.h"
APickItem::APickItem()
{}void APickItem::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{Super::OnOverlapBegin(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);if (OtherActor){AMainPlayer* Player = Cast<AMainPlayer>(OtherActor);if (Player){if (Particle){UGameplayStatics::SpawnEmitterAtLocation(this, Particle, GetActorLocation(), FRotator(0.f), true);}if (Sound){UGameplayStatics::PlaySound2D(this, Sound);}OnPick(Player);//交给蓝图可视化去处理Destroy();}}
}void APickItem::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{}

创建可拾取道具基类的子类(Blueprint)

  • 创建PickItem蓝图进行MainPlayer的函数调用即可
  • 注意将之前MainPlayer中AddHealth这些函数加上反射
  • MainPlayer.h中的
	//改变状态UFUNCTION(BlueprintCallable,Category="Player|State")void AddHealth(float value);UFUNCTION(BlueprintCallable, Category = "Player|State")void AddStamina(float value);UFUNCTION(BlueprintCallable, Category = "Player|State")void AddCoin(float value);
  • 蓝图调用C++编写好的逻辑即可,UI会实时检测更新
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

冲刺行为需求

  • 思路1:当耐力值到达一个精疲力尽的状态时,就停止冲刺,所以我们需要在混合空间1D里面将Axis Setting最大速度值从600上升到900,添加9个关键帧将冲刺添加上去
    在这里插入图片描述
  • 思路2:新建四个变量来标识状态,耐力消耗速率,耐力的精疲力尽的状态,奔跑速度与冲刺速度
   //主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Health;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float MaxHealth;UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Stamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float MaxStamina;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Playe State")float StaminaConsumeRate;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Playe State", meta = (ClampMin = 0, ClampMax = 1))float ExhaustedStamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")int Coins;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player State")float RunningSpeed;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player State")float SprintSpeed;
	//初始化角色状态MaxHealth = 100.f;Health = MaxHealth;MaxStamina = 200.f;Stamina = MaxStamina;StaminaConsumeRate = 20.f;ExhaustedStamina = 0.167f;Coins = 0;RunningSpeed = 600.f;SprintSpeed = 900.f;

创建枚举类型进行标识

  • 创建枚举用来标识角色的状态
  • 枚举的声明规则
  • UENUM(BlueprintType):幻引擎中的一个宏,用于定义带有蓝图支持的枚举类型,使用此宏定义枚举时,它将在蓝图中可用
  • UMETA(DisplayName = "Normal"):是一个宏,用于设置枚举值的显示名称为 “Normal”。这是为了使枚举值在蓝图或编辑器界面中更加可读和直观。
UENUM(BlueprintType)
enum class 类名 : 变量类型
{变量 UMETA(DisplayName = "你调用时想要显示的名字"),....变量 UMETA(DisplayName = "你调用时想要显示的名字")
}
  • MainPlayer.h
//声明移动状态枚举
UENUM(BlueprintType)
enum class EPlayerMovementStatus :uint8
{EPMS_Normal UMETA(DisplayName = "Normal"),EPMS_Sprinting UMETA(DisplayName = "Sprinting"),EPMS_Dead UMETA(DisplayName = "Dead")
};UENUM(BlueprintType)
enum class EPlayerStaminaStatus :uint8
{EPSS_Normal UMETA(DisplayName = "Normal"),EPSS_Exhausted UMETA(DisplayName = "Exhausted"),EPSS_ExhaustedRecovering UMETA(DisplayName = "ExhaustedRecovering")
};// ```````````````````省略之前的
UPROPERTY(VisibleAnywhere,BlueprintReadWrite,Category="Player State")
EPlayerMovementStatus MovementStatus;
UPROPERTY(VisibleAnywhere,BlueprintReadWrite,Category="Player State")
EPlayerStaminaStatus StaminaStatus;
  • MainPlayer.cpp
	//初始化角色状态
// ```````````````````省略之前的MovementStatus = EPlayerMovementStatus::EPMS_Normal;StaminaStatus = EPlayerStaminaStatus::EPSS_Normal;

使用标识位检测shift状态

  • 新建一个bool变量来监测shift是否按下的状态,新建两个函数用来绑定shift事件映射状态用来判断是否按下shift状态。
  • MainPlayer.h
	bool bLeftShiftDown;
//短小精悍
FORCEINLINE void LeftShiftDown() { bLeftShiftDown = true; }
FORCEINLINE void LeftShiftUp() { bLeftShiftDown = false; }
  • MainPlayer.cpp
	//绑定跳跃轴映射事件PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMainPlayer::Jump);//按下空格PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);//抬起空格PlayerInputComponent->BindAction("Sprint", IE_Pressed, this, &AMainPlayer::LeftShiftDown);//按下shiftPlayerInputComponent->BindAction("Sprint", IE_Released, this, &AMainPlayer::LeftShiftUp);//抬起shift

冲刺逻辑编写

  • 思路划分:
    • 一、首先我们新建一个设置移动枚举状态的函数处理冲刺与不冲刺的时候character的速度,用于到时候逻辑编写时的状态更换
    • 二、然后我们在Tick中来设计耐力枚举切换的逻辑
    • 三、在EPSS_Normal中判断是否按下shift键,然后判断是否进入了精疲力尽区,逻辑(总耐力 -耐力消耗值 *DeltaTime<=最大耐力值 *耐力消耗速率),这个逻辑就是每帧判断当前的耐力是否到达的精疲力尽区,到达了精疲力尽区首先改变StaminaStatus状态为Exhausted没有进入精疲力尽区Stamina要减去每帧的耐力消耗值,这是必定的,然后移动状态转为Sprint,判断没有进入精疲力尽区,那就恢复Stamina值(可以与耐力消耗值一样),然后把移动状态恢复成Normal状态
    • 四、在EPSS_Exhausted中判断是否还按着shift键,然后判断是否耐力已经到0了如果耐力已经为0,那么我们需要内部编码把shift抬起,此时StaminaStatus状态转换为ExhaustedRecovering状态。然后设置移动状态为Normal如果耐力没有为0,就直接减去当前帧消耗的耐力,没有按着shift键,那就直接将StaminaStatus状态转换为ExhaustedRecovering状态,恢复Stamina值,然后把移动状态恢复成Normal状态
    • 五、在EPSS_ExhaustedRecovering中判断当Stamina值已经大于精疲力尽区时,逻辑((总耐力 +耐力消耗值 *DeltaTime>=最大耐力值 *耐力消耗速率),将StaminaStatus设置为Normal状态,然后Stamina要加上每帧的耐力消耗值,这是必定的,然后抬起shift与移动状态设置为Normal。
      在这里插入图片描述
//一、首先我们新建一个设置```移动枚举状态的函数```处理冲刺与不冲刺的时候```character```的速度,用于到时候逻辑编写时的状态更换
void SetMovementStatus(EPlayerMovementStatus Status);
void AMainPlayer::SetMovementStatus(EPlayerMovementStatus Status)
{MovementStatus = Status;//切换状态的时候改变移动速度switch (MovementStatus){case EPlayerMovementStatus::EPMS_Sprinting:GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;break;default:GetCharacterMovement()->MaxWalkSpeed = RunningSpeed;break;}
}
//二、然后我们在```Tick```中来设计耐力枚举切换的逻辑
// Called every frame
void AMainPlayer::Tick(float DeltaTime)
{Super::Tick(DeltaTime);switch (StaminaStatus){case EPlayerStaminaStatus::EPSS_Normal://当Shift按下if (bLeftShiftDown){if (Stamina - StaminaConsumeRate * DeltaTime <= MaxStamina * ExhaustedStamina){StaminaStatus = EPlayerStaminaStatus::EPSS_Exhausted;}//无论是不是精疲力尽状态都要减去当前帧冲刺消耗的耐力Stamina -= StaminaConsumeRate * DeltaTime;SetMovementStatus(EPlayerMovementStatus::EPMS_Sprinting);}else{//当Shift没有按下,恢复耐力Stamina = FMath::Clamp(Stamina + StaminaConsumeRate * DeltaTime, 0.f, MaxStamina);SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}break;case EPlayerStaminaStatus::EPSS_Exhausted:if (bLeftShiftDown){//如果耐力已经为0if (Stamina - StaminaConsumeRate * DeltaTime <= 0.f){//么我们需要内部编码把shift抬起,此时StaminaStatus状态转换为ExhaustedRecovering状态,然后设置移动状态为NormalLeftShiftUp();StaminaStatus = EPlayerStaminaStatus::EPSS_ExhaustedRecovering;	SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}else{Stamina -= StaminaConsumeRate * DeltaTime;}}else{StaminaStatus = EPlayerStaminaStatus::EPSS_ExhaustedRecovering;Stamina = FMath::Clamp(Stamina + StaminaConsumeRate * DeltaTime, 0.f, MaxStamina);SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}break;case EPlayerStaminaStatus::EPSS_ExhaustedRecovering://当恢复大于疲劳区时,StaminaStatus状态为Normalif (Stamina + StaminaConsumeRate * DeltaTime >= MaxStamina * ExhaustedStamina){StaminaStatus = EPlayerStaminaStatus::EPSS_Normal;}//这状态值肯定是加定了Stamina += StaminaConsumeRate * DeltaTime;//抬起shiftLeftShiftUp();SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);break;default:break;}
}

耐力消耗殆尽的变色UI

  • 添加一个Appearance的绑定,在蓝图中将编写的Enum进行判断状态然后切换相应颜色
    在这里插入图片描述
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

冲刺转弯时角色抖动问题

  • 我们调整一下动画蓝图即可,设置一个区间,比如在0-100走路,500-600奔跑,700-900冲刺,这样设置区别可以避免插值
    在这里插入图片描述

MainPlayer.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MainPlayer.generated.h"//声明移动状态枚举
UENUM(BlueprintType)
enum class EPlayerMovementStatus :uint8
{EPMS_Normal UMETA(DisplayName = "Normal"),EPMS_Sprinting UMETA(DisplayName = "Sprinting"),EPMS_Dead UMETA(DisplayName = "Dead")
};UENUM(BlueprintType)
enum class EPlayerStaminaStatus :uint8
{EPSS_Normal UMETA(DisplayName = "Normal"),EPSS_Exhausted UMETA(DisplayName = "Exhausted"),EPSS_ExhaustedRecovering UMETA(DisplayName = "ExhaustedRecovering")
};UCLASS()
class UEGAME_API AMainPlayer : public ACharacter
{GENERATED_BODY()public:// Sets default values for this character's propertiesAMainPlayer();//新建一个SpringArmUPROPERTY(visibleAnywhere,BlueprintReadOnly)class USpringArmComponent* SpringArm;//新建一个CameraUPROPERTY(visibleAnywhere, BlueprintReadOnly)class UCameraComponent* FollowCamera;float BaseTurnRate;		//使用键盘X转向的速率float BaseLookUpRate;	//使用键盘Y转向的速率//主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Health;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float MaxHealth;UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Playe State")float Stamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")float MaxStamina;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Playe State")float StaminaConsumeRate;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Playe State", meta = (ClampMin = 0, ClampMax = 1))float ExhaustedStamina;UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Playe State")int Coins;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player State")float RunningSpeed;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player State")float SprintSpeed;UPROPERTY(VisibleAnywhere,BlueprintReadWrite,Category="Player State")EPlayerMovementStatus MovementStatus;UPROPERTY(VisibleAnywhere,BlueprintReadWrite,Category="Player State")EPlayerStaminaStatus StaminaStatus;bool bLeftShiftDown;protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;public:	// Called every framevirtual void Tick(float DeltaTime) override;// Called to bind functionality to inputvirtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;//重新Character类中的Jump方法void Jump() override;void MoveForward(float value);void MoveRight(float value);void Turn(float Value);void LookUp(float Value);void TurnRate(float Rate);void LookUpRate(float Rate);//改变状态UFUNCTION(BlueprintCallable,Category="Player|State")void AddHealth(float value);UFUNCTION(BlueprintCallable, Category = "Player|State")void AddStamina(float value);UFUNCTION(BlueprintCallable, Category = "Player|State")void AddCoin(float value);//重写TakeDamage方法float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;//短小精悍FORCEINLINE void LeftShiftDown() { bLeftShiftDown = true; }FORCEINLINE void LeftShiftUp() { bLeftShiftDown = false; }void SetMovementStatus(EPlayerMovementStatus Status);
};

MainPlayer.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "MainPlayer.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/CharacterMovementComponent.h"// Sets default values
AMainPlayer::AMainPlayer()
{// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));SpringArm->SetupAttachment(GetRootComponent());//设置SPringArm无碰撞臂长SpringArm->TargetArmLength = 600.f;SpringArm->bUsePawnControlRotation = true;//硬编码SpringArm继承controlller旋转为真FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));FollowCamera->SetupAttachment(SpringArm, NAME_None);FollowCamera->bUsePawnControlRotation = false;//硬编码FollowCamera继承controlller旋转为假//设置胶囊体的默认宽高GetCapsuleComponent()->SetCapsuleSize(35.f, 100.f);//对Character的Pawn进行硬编码bUseControllerRotationPitch = false;bUseControllerRotationYaw = false;bUseControllerRotationRoll = false;//硬编码orient Rotation to Movement,给个默认转向速率GetCharacterMovement()->bOrientRotationToMovement = true;GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);//设置跳跃初始值与在空中的坠落时横向运动控制量GetCharacterMovement()->JumpZVelocity = 600.f;GetCharacterMovement()->AirControl = 0.15f;//给键盘控制转向的速率变量赋初值BaseTurnRate = 21.f;BaseLookUpRate = 21.f;//初始化角色状态MaxHealth = 100.f;Health = MaxHealth;MaxStamina = 200.f;Stamina = MaxStamina;StaminaConsumeRate = 20.f;ExhaustedStamina = 0.167f;Coins = 0;RunningSpeed = 600.f;SprintSpeed = 900.f;MovementStatus = EPlayerMovementStatus::EPMS_Normal;StaminaStatus = EPlayerStaminaStatus::EPSS_Normal;//默认没有按下shiftbLeftShiftDown = false;
}// Called when the game starts or when spawned
void AMainPlayer::BeginPlay()
{Super::BeginPlay();
}// Called every frame
void AMainPlayer::Tick(float DeltaTime)
{Super::Tick(DeltaTime);switch (StaminaStatus){case EPlayerStaminaStatus::EPSS_Normal://当Shift按下if (bLeftShiftDown){if (Stamina - StaminaConsumeRate * DeltaTime <= MaxStamina * ExhaustedStamina){StaminaStatus = EPlayerStaminaStatus::EPSS_Exhausted;}//无论是不是精疲力尽状态都要减去当前帧冲刺消耗的耐力Stamina -= StaminaConsumeRate * DeltaTime;SetMovementStatus(EPlayerMovementStatus::EPMS_Sprinting);}else{//当Shift没有按下,恢复耐力Stamina = FMath::Clamp(Stamina + StaminaConsumeRate * DeltaTime, 0.f, MaxStamina);SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}break;case EPlayerStaminaStatus::EPSS_Exhausted:if (bLeftShiftDown){//如果耐力已经为0if (Stamina - StaminaConsumeRate * DeltaTime <= 0.f){//么我们需要内部编码把shift抬起,此时StaminaStatus状态转换为ExhaustedRecovering状态,然后设置移动状态为NormalLeftShiftUp();StaminaStatus = EPlayerStaminaStatus::EPSS_ExhaustedRecovering;	SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}else{Stamina -= StaminaConsumeRate * DeltaTime;}}else{StaminaStatus = EPlayerStaminaStatus::EPSS_ExhaustedRecovering;Stamina = FMath::Clamp(Stamina + StaminaConsumeRate * DeltaTime, 0.f, MaxStamina);SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);}break;case EPlayerStaminaStatus::EPSS_ExhaustedRecovering://当恢复大于疲劳区时,StaminaStatus状态为Normalif (Stamina + StaminaConsumeRate * DeltaTime >= MaxStamina * ExhaustedStamina){StaminaStatus = EPlayerStaminaStatus::EPSS_Normal;}//这状态值肯定是加定了Stamina += StaminaConsumeRate * DeltaTime;//抬起shiftLeftShiftUp();SetMovementStatus(EPlayerMovementStatus::EPMS_Normal);break;default:break;}
}// Called to bind functionality to input
void AMainPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{Super::SetupPlayerInputComponent(PlayerInputComponent);//检查PlayerInputComponent指针,check函数只能在这使用check(PlayerInputComponent);//绑定跳跃轴映射事件PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMainPlayer::Jump);//按下空格PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);//抬起空格PlayerInputComponent->BindAction("Sprint", IE_Pressed, this, &AMainPlayer::LeftShiftDown);//按下shiftPlayerInputComponent->BindAction("Sprint", IE_Released, this, &AMainPlayer::LeftShiftUp);//抬起shift//绑定移动轴映射事件PlayerInputComponent->BindAxis("MoveForward", this, &AMainPlayer::MoveForward);PlayerInputComponent->BindAxis("MoveRight", this, &AMainPlayer::MoveRight);//绑定Controller控制器去管理视角旋转PlayerInputComponent->BindAxis("Turn", this, &AMainPlayer::Turn);PlayerInputComponent->BindAxis("LookUp", this, &AMainPlayer::LookUp);//绑定键盘鼠标轴映射事件PlayerInputComponent->BindAxis("TurnRate", this, &AMainPlayer::TurnRate);PlayerInputComponent->BindAxis("LookUpRate", this, &AMainPlayer::LookUpRate);}void AMainPlayer::Jump()
{//继承父类的方法Super::Jump();
}void AMainPlayer::MoveForward(float value)
{if (Controller != nullptr && value != 0.f){//获取到Control旋转FRotator Rotation = Controller->GetControlRotation();//转向只关注水平Yaw方向,因此置0防止影响FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::X);AddMovementInput(Direction, value);}}void AMainPlayer::MoveRight(float value)
{if (Controller != nullptr && value != 0.f){//获取到Controller旋转FRotator Rotation = Controller->GetControlRotation();//转向只关注水平Yaw方向,因此置0防止影响FRotator YowRotation = FRotator(0.0f, Rotation.Yaw, 0.0f);//获取相机(鼠标控制器的朝向),并且朝这个轴的方向移动FVector Direction = FRotationMatrix(YowRotation).GetUnitAxis(EAxis::Y);AddMovementInput(Direction, value);}
}void AMainPlayer::Turn(float Value)
{if (Value != 0.f){AddControllerYawInput(Value);}}void AMainPlayer::LookUp(float Value)
{//UE_LOG(LogTemp, Warning, TEXT("%f"), GetControlRotation().Pitch);//控制视角if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f){return;}else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f){return;}AddControllerPitchInput(Value);
}void AMainPlayer::TurnRate(float Rate)
{//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题float Value = Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds();if (Value != 0.f){AddControllerYawInput(Value);}
}void AMainPlayer::LookUpRate(float Rate)
{//要乘以一个DeltaTime这样就可以避免高帧底帧差值问题float Value = Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds();//控制视角if (GetControlRotation().Pitch < 270.f && GetControlRotation().Pitch >180.f && Value > 0.f){return;}else if (GetControlRotation().Pitch < 180.f && GetControlRotation().Pitch >45.f && Value < 0.f){return;}AddControllerPitchInput(Value);}void AMainPlayer::AddHealth(float value)
{Health = FMath::Clamp(Health + value, 0.f, MaxHealth);
}void AMainPlayer::AddStamina(float value)
{Stamina = FMath::Clamp(Stamina + value, 0.f, MaxStamina);
}void AMainPlayer::AddCoin(float value)
{Coins += value;
}float AMainPlayer::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{if (Health - Damage <= 0.f){Health = FMath::Clamp(Health - Damage, 0.f, MaxHealth);//TODO Die();}else{Health -= Damage;}return Health;
}void AMainPlayer::SetMovementStatus(EPlayerMovementStatus Status)
{MovementStatus = Status;//切换状态的时候改变移动速度switch (MovementStatus){case EPlayerMovementStatus::EPMS_Sprinting:GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;break;default:GetCharacterMovement()->MaxWalkSpeed = RunningSpeed;break;}
}

相关文章:

虚幻C++ day5

角色状态的常见机制 创建角色状态设置到UI上 在MainPlayer.h中新建血量&#xff0c;最大血量&#xff0c;耐力&#xff0c;最大耐力&#xff0c;金币变量&#xff0c;作为角色的状态 //主角状态UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category "Playe Stats&…...

C#中的DateTime类

C# 中的 DateTime 类是用于表示日期和时间的结构。它提供了一系列属性和方法&#xff0c;用于处理日期和时间的各种操作和计算。下面是一些常用的 DateTime 类的用法和方法解释&#xff0c;以及相应的示例说明&#xff1a; 创建 DateTime 对象&#xff1a; 使用当前日期和时间创…...

Flutter笔记:Matrix4矩阵变换与案例

Flutter笔记 Matrix4矩阵变换及其案例 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134474764 【简介…...

数字IC前端学习笔记:时钟切换电路

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 有些时候我们需要在系统运行时切换系统时钟&#xff0c;最简单的方法就是使用一个MUX&#xff08;数据选择器&#xff09;选择输出的时钟&#xff0c;如下代码片所…...

.NET6使用MiniExcel根据数据源横向导出头部标题及数据

.NET6MiniExcel根据数据源横向导出头部标题 MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。 特点: 低内存耗用&#xff0c;避免OOM、频繁 Full GC 情况 支持即时操作每行数据 兼具搭配 LINQ 延迟查询特性&#xff0c;能办到低消耗、快速分页等复杂查询 轻量…...

表内容的操作(增删查改)【MySQL】

文章目录 表的 CRUDCreate&#xff08;增加&#xff09;插入记录插入冲突则更新记录替换记录 Retrieve&#xff08;查找&#xff09;查找记录指定表达式的别名为结果去重WHERE 子句运算符条件查询区间查询模糊查询空值查询 对结果排序筛选分页结果 Update&#xff08;修改&…...

C++快速入门 - 2(几分钟让你快速入门C++)

C快速入门 - 2 1. 内联函数1.1 概念1.2 特性 2. auto关键字(C11)2.1 类型别名思考2.2 auto简介2.3 auto的使用细则2.4 auto不能推导的场景 3. 基于范围的for循环(C11)3.1 范围for的语法3.2 范围for的使用条件 1. 内联函数 1.1 概念 以inline修饰的函数叫做内联函数&#xff0c…...

Excel自定义函数提取超链接

通过自定义函数的方法&#xff0c;批量提取超链接 首选开启开发工具选项 文件-选项-自定义功能区-勾选开发工具选项-确认 AltF11或者直接点击跳转到开发工具-Visual Basic 在左上方VBA project空白处右键点击空白区域-插入-模块 在弹出的窗口中输入以下命令定义GetURL函数 F…...

计算矩阵边缘元素之和

Description 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。 Input 第一行分别为矩阵的行数m和列数n&#xff08;m<100&#xff0c;n<100&#xff09;&#xff0c;…...

回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测

回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测 目录 回归预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现HPO-ELM猎食者算法优化极限学习机的数据回归预测&#xff08;…...

Flutter笔记:目录与文件存储以及在Flutter中的使用(下)

Flutter笔记 目录与文件存储以及在Flutter中的使用&#xff08;下&#xff09; 文件读写与Flutter中文件管理 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;…...

机器学习笔记 - Ocr识别中的CTC算法原理概述

一、文字识别 在文本检测步骤中,分割出了文本区域。现在需要识别这些片段中存在哪些文本。 机器学习笔记 - Ocr识别中的文本检测EAST网络概述-CSDN博客文章浏览阅读300次。在 EAST 网络的这个分支中,它合并了 VGG16 网络不同层的特征输出。现在,该层之后的特征大小将等于 p…...

系列二、Lock接口

一、多线程编程模板 线程 操作 资源类 高内聚 低耦合 二、实现步骤 1、创建资源类 2、资源类里创建同步方法、同步代码块 三、12306卖票程序 3.1、synchronized实现 3.1.1、Ticket /*** Author : 一叶浮萍归大海* Date: 2023/11/20 8:54* …...

JVM虚拟机:通过日志学习PS+PO垃圾回收器

我们刚才设置参数的时候看到了-XXPrintGCDetails表示输出详细的GC处理日志&#xff0c;那么我们如何理解这个日志呢&#xff1f;日志是有规则的&#xff0c;我们需要按照这个规则来理解日志中的内容&#xff0c;它有两个格式&#xff0c;一个格式是GC的格式&#xff08;新生代&…...

从0开始学习JavaScript--JavaScript使用Promise

JavaScript中的异步编程一直是开发中的重要话题。传统的回调函数带来了回调地狱和代码可读性的问题。为了解决这些问题&#xff0c;ES6引入了Promise&#xff0c;一种更现代、更灵活的异步编程解决方案。本文将深入探讨JavaScript中如何使用Promise&#xff0c;通过丰富的示例代…...

使用契约的链上限价订单

我们开发了链上限价订单。 它基于一种称为契约的智能合约&#xff0c;只有在花费输出的交易满足特定条件时才可以花费输出。 为了演示其工作原理&#xff0c;我们实施了以比特币支付的 Ordinals 代币买卖限价订单&#xff0c;无需托管人。 它可以运行在任何比特币协议链上&…...

Iceberg学习笔记(1)—— 基础知识

Iceberg是一个面向海量数据分析场景的开放表格式&#xff08;Table Format&#xff09;&#xff0c;其设计的目的是解决数据存储和计算引擎之间的适配的问题 表格式&#xff08;Table Format&#xff09;可以理解为元数据以及数据文件的一种组织方式&#xff0c;处于计算框架&…...

springboot中动态api如何设置

1.不需要编写controller 等mvc层&#xff0c;通过接口动态生成api。 这个问题&#xff0c;其实很好解决&#xff0c;以前编写接口&#xff0c;是要写controller&#xff0c;需要有 RestController RequestMapping("/test1") public class xxxController{ ApiOperat…...

Java —— 抽象类和接口

目录 1. 抽象类 1.1 抽象类概念 1.2 抽象类语法与特性 1.3 抽象类的作用 2. 接口 2.1 接口的概念 2.2 接口的语法规则与特性 2.3 实现多个接口(解决多继承的问题) 2.4 接口间的继承 2.5 抽象类和接口的区别 2.6 接口的使用实例 2.7 Clonable 接口和深拷贝 2.7.1 Cloneable接口 …...

数字IC前端学习笔记:异步复位,同步释放

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 异步复位 异步复位是一种常见的复位方式&#xff0c;可以使电路进入一个可知的状态。但是不正确地使用异步复位会导致出现意想不到的错误&#xff0c;复位释放便是…...

Linux内核移植之网络驱动更改说明一

一. 简介 本文学习 NXP官方Linux内核移植网络驱动的更改。 为了方便后面 Linux驱动的开发调试&#xff0c;所以&#xff0c;必须要把网络驱动调试好。 如果在做 Linux驱动开发时&#xff0c;写了一个 app或驱动&#xff0c;就需要将系统全部文件&#xff08;即 uboot&#…...

邮件|gitpushgithub报错|Lombok注解

基于 Spring Boot 搭建一个定时发送邮件的项目可以按照以下步骤进行&#xff1a; 创建一个新的 Spring Boot 项目&#xff0c;并添加所需的依赖。在 pom.xml 文件中添加以下依赖项&#xff08;根据你的需要进行调整&#xff09;&#xff1a; xml org.springframework.boot sp…...

【前端知识】Node——events模块的相关方法

一、events模块的常用方法 // 事件总线 const EventsEmitter require(events);const emitter new EventsEmitter();function HLog(msg){console.log(msg); }// 监听 emitter.on(hlog, HLog);setTimeout(() > {// 触发&#xff0c;打印emitter.emit(hlog, hello emitter!)…...

广州华锐互动VRAR | VR课件内容编辑器解决院校实践教学难题

VR课件内容编辑器由VR制作公司广州华锐互动开发&#xff0c;是一款专为虚拟现实教育领域设计的应用&#xff0c;它能够将传统的教学内容转化为沉浸式的三维体验。通过这款软件&#xff0c;教师可以轻松创建和编辑各种虚拟场景、模型和动画&#xff0c;以更生动、直观的方式展示…...

Wireshark抓包:理解TCP三次握手和四次挥手过程

TCP是一种面向连接、端到端可靠的协议&#xff0c;它被设计用于在互联网上传输数据和确保成功传递数据和消息。本节来介绍一下TCP中的三次握手和四次挥手。 文章目录 1 TCP头部格式2 wireshark抓包分析2.1 SEQ和ACK2.2 三次握手2.3 四次挥手 3 程序 1 TCP头部格式 TCP头部占据…...

网络工程师-HCIA网课视频学习

这里是速成的&#xff0c;只积累下&#xff0c;自己未曾学习到的东西。通过书本补充知识点。 视频&#xff1a;hcia17-链路聚合_哔哩哔哩_bilibili hcia16-路由高级特性&#xff1a; hcia17-链路聚合&#xff1a; 由于如果根据视频来学习的话&#xff0c;感觉视频的总结并不…...

【每日刷题——语音信号篇】

思考与练习 练习2.1 语音信号在产生的过程中&#xff0c;以及被感知的过程中&#xff0c;分别要经过人体的哪些器官&#xff1f; 1.产生过程&#xff1a; 肺部空气 → \rightarrow →冲击声带 → \rightarrow →通过声道&#xff08;可以调节&#xff09; → \rightarrow →…...

Linux进程通信——IPC、管道、FIFO的引入

进程间的通信——IPC 进程间通信 (IPC&#xff0c;InterProcess Communication) 是指在不同进程之间传播或交换信息。 IPC的方式通常有管道 (包括无名管道和命名管道) 、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。 …...

数理统计的基本概念(一)

文章目录 总体、样本与统计量总体及其分布样本及其分布统计量统计量概念样本矩顺序统计量及其分布样本中位数与样本极差经验分布函数 参考文献 总体、样本与统计量 总体及其分布 在数理统计中&#xff0c;称所研究的对象的全体为总体&#xff0c;总体中的元素称为个体。若总体…...

clickhouse分布式之弹性扩缩容的故事

现状 社区不支持喔&#xff0c;以后也不会有了。曾经尝试过&#xff0c;难道是是太难了&#xff0c;无法实现吗&#xff1f;因为他们企业版支持了&#xff0c;可能是利益相关吧&#xff0c;谁知道呢&#xff0c;毕竟开源也要赚钱&#xff0c;谁乐意一直付出没有回报呢。 社区…...