虚幻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;}
}

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

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

相关文章

基于人工水母算法优化概率神经网络PNN的分类预测 - 附代码

基于人工水母算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于人工水母算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于人工水母优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

Network(三)动态路由与ACL配置

一 三层交换机 1 三层交换机概述 三层交换二层交换三层转发 2 虚拟接口概述 在三层交换机上配置的VLAN接口为虚拟接口&#xff0c;使用Vlanif&#xff08;VLAN虚拟接口&#xff09;实现VLAN间路由&#xff0c;VLAN接口的引入使得应用更加灵活 三层交换机VLAN间通信的转发…

vue3+vite+SQL.js 读取db3文件数据

前言&#xff1a;好久没写博客了&#xff0c;最近一直在忙&#xff0c;没时间梳理。最近遇到一个需求是读取本地SQLite文件&#xff0c;还是花费了点时间才实现&#xff0c;没怎么看到vite方面写这个的文章&#xff0c;现在分享出来完整流程。 1.pnpm下载SQL.js(什么都可以下)…

力扣每日一题-数位和相等数对的最大和-2023.11.18

力扣每日一题&#xff1a;数位和相等数对的最大和 开篇 这道每日一题还是挺需要思考的&#xff0c;我绕晕了好久&#xff0c;根据题解的提示才写出来。 题目链接:2342.数位和相等数对的最大和 题目描述 代码思路 1.创建一个数组存储每个数位的数的最大值&#xff0c;创建一…

软件项目测试指南

软件测试是保证软件产品质量的重要手段之一。它是测量、评估软件产品特点和能力的活动。现在&#xff0c;国内一些软件企业对于软件测试的重视程度还很不够&#xff0c;认为测试工作非常简单&#xff0c;只是简单地操作所测的软件产品而已。这种错误的思想严重影响了国内软件质…

Evil靶场

Evil 1.主机发现 使用命令探测存活主机&#xff0c;80.139是kali的地址&#xff0c;所以靶机地址就是80.134 fping -gaq 192.168.80.0/242.端口扫描 开放80&#xff0c;22端口 nmap -Pn -sV -p- -A 192.168.80.1343.信息收集 访问web界面 路径扫描 gobuster dir -u http…

【C++上层应用】2. 预处理器

文章目录 【 1. #define 预处理 】【 2. #ifdef、#if 条件编译 】2.1 #ifdef2.2 #if2.3 实例 【 3. # 和 ## 预处理 】3.1 # 替换预处理3.2 ## 连接预处理 【 4. 预定义宏 】 预处理器是一些指令&#xff0c;指示编译器在实际编译之前所需完成的预处理。 所有的预处理器指令都是…

SpringBoot2—运维实用篇

目录 打包与运行 • 程序打包与运行&#xff08;Windows版&#xff09; • 程序运行&#xff08;Linux版&#xff09; 配置高级 • 临时属性设置 • 配置文件分类 • 自定义配置文件 多环境开发 多环境开发&#xff08;yaml单一文件版&#xff09; 多环境开发&am…

碰到一个逆天表中表数据渲染

1. 逆天表中表数据问题 我有一个antd-table组件&#xff0c;他的编辑可以打开一个编辑弹窗打开弹窗里面还会有一个表格&#xff0c;如果这个表格的column是在外层js文件中保存的话&#xff0c;那么第一次打开会正常渲染数据&#xff0c;再次打开就不会渲染&#xff0c;即使是已…

SQL单表复杂查询where、group by、order by、limit

1.1SQL查询代码如下&#xff1a; select job as 工作类别,count(job) as 人数 from tb_emp where entrydate <2015-01-01 group by job having count(job) > 2 order by count(job) limit 1,1where entrydate <‘2015-01-01’ 表示查询日期小于2015-01-01的记录…

【Leetcode合集】2342. 数位和相等数对的最大和

文章目录 2342. 数位和相等数对的最大和方案1方案2方案3方案4 2342. 数位和相等数对的最大和 2342. 数位和相等数对的最大和 代码仓库地址&#xff1a; https://github.com/slience-me/Leetcode 个人博客 &#xff1a;https://slienceme.xyz 给你一个下标从 0 开始的数组 nu…

Git安装与常用命令

Git简介&#xff1a; Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同&#xff0c;它采用了分布式…

动态改标题

<el-dialog :title"showTitle" :visible"showDialog" close"close"> </el-dialog>使用计算属性 computed: {showTitle() {//这里根据点击的是否有具体点击的那个id来判断return this.form.id ? "编辑部门" : "新增部…

Virtual安装centos后,xshell连接centos 测试及遇到的坑

首先来一张官方的图--各种网络模式对应的连接状况&#xff1a; 1. 网络使用Host-Only模式动态分配IP&#xff0c;点确定后&#xff0c;centos 上运行 system restart network &#xff0c;使用ifconfig查看新的ip&#xff0c;XShell可以直接连上centos&#xff0c; 但是由于使用…

【总结】坐标变换和过渡矩阵(易忘记)

xCy&#xff0c;此为x到y的坐标变换。 [β1,β2,…,βn] [α1,α2,…αn]C&#xff0c;此为基α到基β的过渡矩阵。 这个概念经常忘记。。。alpha到beta看来就是alpha后面加一个过渡矩阵了&#xff0c;很直观。坐标变换就是根据过渡矩阵和基本形式推一推得到吧&#xff0c;记…

大型 APP 的性能优化思路

做客户端开发都基本都做过性能优化&#xff0c;比如提升自己所负责的业务的速度或流畅性&#xff0c;优化内存占用等等。但是大部分开发者所做的性能优化可能都是针对中小型 APP 的&#xff0c;大型 APP 的性能优化经验并不会太多&#xff0c;毕竟大型 APP 就只有那么几个&…

linux 定时执行脚本

先写一个简单的shell脚本用来测试定时执行脚本 [rootVM-12-12-centos wz]# cat shell_cron_test.sh #!/bin/bashif [ -f "/home/wz/cron_test.txt" ];thennum$(($(wc -l /home/wz/cron_test.txt | cut -d -f 1)1))elsenum1 fi echo "$(date "%y-%m-%d …

你知道STM32和51单片机的区别吗?

你知道STM32和51单片机的区别吗&#xff1f; 51单片机是很经典的一款单片机。事实上很多电信专业本科阶段都会以这个单片机作为入门。最近很多小伙伴找我&#xff0c;说想要一些STM32的资料&#xff0c;然后我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心…

比赛调研资料

视觉文旅 现有的模型 数据 功能 精准营销 基于地理推荐能力 乡村圈分析能力 都市圈分析能力 产品体系 三大数据平台 携程问道 旅游服务框架&#xff1a;前置&#xff08;推荐种草&#xff09;&#xff0c;途中&#xff08;客服&#xff09;&#xff0c;售后&#xff0…

【SpringMvc】SpringMvc +MyBatis整理

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理 Java 框架 中 SpringMVC的知识点和值得注意的地方 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关…