UEC++ 捡电池初级案例 day16

捡电池案例

  • 创建第三人称模版

创建Actor基类

  • 创建一个Actor类用来作为可拾取物品基类
  • 需求:我们让这个基类有静态网格可识别,然后得有一个状态就是是否被拾取的状态,那就得拥有改变状态的函数与返回状态的函数,然后和返回这个实体的函数

CollectActor.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CollectActor.generated.h"UCLASS()
class BATTERYRETRIEVER_API ACollectActor : public AActor
{GENERATED_BODY()public:	// Sets default values for this actor's propertiesACollectActor();//静态网格UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Properties")class UStaticMeshComponent* StaticMesh;protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;//是否被拾取bool bIsActive;
public:	// Called every framevirtual void Tick(float DeltaTime) override;//返回拾取的物体FORCEINLINE class UStaticMeshComponent* GetMesh() { return StaticMesh; }//返回拾取的状态UFUNCTION(BlueprintPure, Category = "Pickup")bool IsActive();//改变拾取的状态UFUNCTION(BlueprintCallable, Category = "Pickup")void SetActive(bool NewPickupState);
};

CollectActor.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "CollectActor.h"
#include "Components/StaticMeshComponent.h"
// Sets default values
ACollectActor::ACollectActor()
{// 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;StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));RootComponent = StaticMesh;
}// Called when the game starts or when spawned
void ACollectActor::BeginPlay()
{Super::BeginPlay();}// Called every frame
void ACollectActor::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}bool ACollectActor::IsActive()
{return bIsActive;
}void ACollectActor::SetActive(bool NewPickupState)
{bIsActive = NewPickupState;
}

设置电池的物体状态

  • 创建CollectActor的子类用于创建电池子类
  • SetSimulatePhysics:设置物理效果
  • BatteryCollect.h
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "CollectActor.h"
#include "BatteryCollectActor.generated.h"/*** */
UCLASS()
class BATTERYRETRIEVER_API ABatteryCollectActor : public ACollectActor
{GENERATED_BODY()public:ABatteryCollectActor();protected:};
  • BatteryCollect.cpp
// Fill out your copyright notice in the Description page of Project Settings.#include "BatteryCollectActor.h"ABatteryCollectActor::ABatteryCollectActor()
{//设置物理状态GetMesh()->SetSimulatePhysics(true);}
  • 创建一下碰撞
    在这里插入图片描述

创建生成器

  • 创建一个Actor用来当做生成器
  • 创建一个Box的组件作为生成空间,定义电池的生成变量,获取随机点生成的点处理函数与生成电池的处理函数,我们要使用定时器来进行几秒就生成一次,还需要定义时间句柄与最大最小时间范围与真实的时间
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UBoxComponent* SpawnBox;
//定义电池生成变量
UPROPERTY(EditAnywhere, Category = "Spawn Volume")
TSubclassOf<class ACollectActor>SpawnClass;
FTimerHandle TimerHandle;
//最小延迟
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawn Volume")
float MinDelayTimer;
//最大延迟
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawn Volume")
float MaxDelayTimer;
//真实的延迟
float SpawnDelay;//获取随机点UFUNCTION(BlueprintPure, Category = "Spawn Volume")FVector GetSpawnRandomLocation();//管理一个新的触发拾取void SpawnPickup();
  • 获取随机点生成的点处理函数
  • SpawnBox->Bounds.Origin:保存边界框和球体的原点
  • SpawnBox->Bounds.BoxExtent:保存边界框的范围
FVector ASpawnVolume::GetSpawnRandomLocation()
{FVector SpawnOrigin = SpawnBox->Bounds.Origin;FVector SpawnExtent = SpawnBox->Bounds.BoxExtent;return UKismetMathLibrary::RandomPointInBoundingBox(SpawnOrigin, SpawnExtent);
}
  • 也可以这样,调用函数来获取随机点
    在这里插入图片描述
  • 生成电池的处理函数
void ASpawnVolume::SpawnPickup()
{if (SpawnClass != NULL){UWorld* World = GetWorld();if (World){//设置触发参数FActorSpawnParameters SpawnParams;SpawnParams.Owner = this;SpawnParams.Instigator = GetInstigator();//获取触发的随机位置FVector SpawnLocation = GetSpawnRandomLocation();//获取触发物体的随机旋转FRotator SpawnRotation;SpawnRotation.Yaw = FMath::FRand() * 360.f;SpawnRotation.Pitch = FMath::FRand() * 360.f;SpawnRotation.Roll = FMath::FRand() * 360.f;//生成电池ACollectActor* SpawnPickup = World->SpawnActor<ACollectActor>(SpawnClass, SpawnLocation,SpawnRotation, SpawnParams);//真实延迟时间范围SpawnDelay = FMath::FRandRange(MinDelayTimer, MaxDelayTimer);//定时器生成电池GetWorld()->GetTimerManager().SetTimer(TimerHandle,this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);}}
}
  • 然后在BeginPlay中定时器生成我们的电池
// Called when the game starts or when spawned
void ASpawnVolume::BeginPlay()
{Super::BeginPlay();//真实延迟时间范围SpawnDelay = FMath::FRandRange(MinDelayTimer, MaxDelayTimer);//定时器生成电池GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);}

SpawnVolume.h

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SpawnVolume.generated.h"UCLASS()
class BATTERYRETRIEVER_API ASpawnVolume : public AActor
{GENERATED_BODY()public:	// Sets default values for this actor's propertiesASpawnVolume();UPROPERTY(VisibleAnywhere, BlueprintReadOnly)class UBoxComponent* SpawnBox;//定义电池生成变量UPROPERTY(EditAnywhere, Category = "Spawn Volume")TSubclassOf<class ACollectActor>SpawnClass;FTimerHandle TimerHandle;//最小延迟UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawn Volume")float MinDelayTimer;//最大延迟UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawn Volume")float MaxDelayTimer;//真实的延迟float SpawnDelay;
protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;	
public:	// Called every framevirtual void Tick(float DeltaTime) override;//获取随机点UFUNCTION(BlueprintPure, Category = "Spawn Volume")FVector GetSpawnRandomLocation();//管理一个新的触发拾取void SpawnPickup();
};

SpawnVolume.cpp

// Fill out your copyright notice in the Description page of Project Settings.#include "SpawnVolume.h"
#include "Components/BoxComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "../MyActors/CollectActor.h"
#include "Engine/Engine.h"
// Sets default values
ASpawnVolume::ASpawnVolume()
{// 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;SpawnBox = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnBox"));RootComponent = SpawnBox;//延迟区间MinDelayTimer = 1.f;MaxDelayTimer = 4.f;
}// Called when the game starts or when spawned
void ASpawnVolume::BeginPlay()
{Super::BeginPlay();//真实延迟时间范围SpawnDelay = FMath::FRandRange(MinDelayTimer, MaxDelayTimer);//定时器生成电池GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);}// Called every frame
void ASpawnVolume::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}FVector ASpawnVolume::GetSpawnRandomLocation()
{FVector SpawnOrigin = SpawnBox->Bounds.Origin;FVector SpawnExtent = SpawnBox->Bounds.BoxExtent;FVector OriginPoint = SpawnBox->GetComponentLocation();return UKismetMathLibrary::RandomPointInBoundingBox(SpawnOrigin, SpawnExtent);
}void ASpawnVolume::SpawnPickup()
{if (SpawnClass!=NULL){UWorld* World = GetWorld();if (World){//设置触发参数FActorSpawnParameters SpawnParams;SpawnParams.Owner = this;SpawnParams.Instigator = GetInstigator();//获取触发的随机位置FVector SpawnLocation = GetSpawnRandomLocation();//获取触发物体的随机旋转FRotator SpawnRotation;SpawnRotation.Yaw = FMath::FRand() * 360.f;SpawnRotation.Pitch = FMath::FRand() * 360.f;SpawnRotation.Roll = FMath::FRand() * 360.f;//生成电池ACollectActor* const SpawnPickup = World->SpawnActor<ACollectActor>(SpawnClass, SpawnLocation,SpawnRotation, SpawnParams);//真实延迟时间范围SpawnDelay = FMath::FRandRange(MinDelayTimer, MaxDelayTimer);//定时器生成电池GetWorld()->GetTimerManager().SetTimer(TimerHandle,this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);}}
}

测试生成器

  • 将我们的SpawnVolume类创建为蓝图拖入场景进行测试
    在这里插入图片描述

拾取类收集状态重写

  • 在CollectActor基类中添加一个收集方法,这个方法带BlueprintNativeEvent属性可以在C++中和蓝图中调用,用virtual修饰,让子类可以继承
	//当物体被收集时调用此方法UFUNCTION(BlueprintNativeEvent,BlueprintCallable)void WasCollected();virtual void WasCollected_Implementation();
void ACollectActor::WasCollected_Implementation()
{FString PickupDebug = GetName();UE_LOG(LogTemp, Warning, TEXT("你收集了%s"), *PickupDebug);
}
  • BatteryCollectActor中继承此方法
void ABatteryCollectActor::WasCollected_Implementation()
{Super::WasCollected_Implementation();//销毁电池Destroy();
}

角色控制器的按键收集

逻辑需求

  • 我们给第三人称模版添加一个球形检测组件,用于来检测电池是否可以收集,然后创建一个收集电池的处理函数
	//球形检测UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Collection")class USphereComponent* CollectionSphere;//收集电池处理函数
UFUNCTION(BlueprintCallable, Category = "Pickups")
void CollectPickups();
  • 初始化球形组件
	//创建球形组件CollectionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("CollectionSphere"));CollectionSphere->SetupAttachment(GetRootComponent());CollectionSphere->SetSphereRadius(200.f);
  • 收集电池处理函数逻辑:将所有与角色重叠的组件存入数组,遍历数组,数组中的组件转换为电池基类,成功并且电池没有被销毁也没有被拾取就调用电池被收集的处理方法,并将电池标记为已失去状态
  • GetOverlappingActors:TArray中的函数用于返回该组件的参与重叠者列表
void ABatteryRetrieverCharacter::CollectPickups()
{TArray<AActor*> CollectionActors;//返回该组件的参与重叠者列表CollectionSphere->GetOverlappingActors(CollectionActors);float CollectPower = 0.f;//能力值//遍历所有区域的电池,并存入数组for (int32 i = 0; i < CollectionActors.Num(); i++){ACollectActor* Collect = Cast<ACollectActor>(CollectionActors[i]);//转换成功,电池没有被销毁,电池没有被拾取if (Collect && !Collect->IsPendingKill() && Collect->IsActive()){Collect->WasCollected();//调用电池被收集的方法Collect->SetActive(false);//电池被拾取}}}
  • 记得将CollectActor类中的bIsActive赋初值为true,一开始就是可拾取状态
	bIsActive = true;

增强输入系统绑定

  • 我们绑定C键为捡取电池,在模版角色中添加一个增强输入行为
	/** PicktupC Input Action */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))class UInputAction* PicktupC;
  • 在SetupPlayerInputComponent()中绑定这个输入行为
//Pickup
EnhancedInputComponent->BindAction(PicktupC, ETriggerEvent::Triggered, this, &ABatteryRetrieverCharacter::CollectPickups);
  • 在UE中创建这个输入行为,因为是简单的拾取用bool值类型即可
    在这里插入图片描述
    在这里插入图片描述
  • 在设备映射集合中添加这个行为,绑定按键C
    在这里插入图片描述
  • 最后在模版蓝图中添加这个输入行为
    在这里插入图片描述
  • 运行结果
    请添加图片描述

角色能量值定义

  • 首先电池类中,我们要定义电池能恢复多少能力的初值
UCLASS()
class BATTERYRETRIEVER_API ABatteryCollectActor : public ACollectActor
{GENERATED_BODY()public:ABatteryCollectActor();void WasCollected_Implementation()override;//获取能量float GetPower();
protected:UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float BatteryPower;
};
// Fill out your copyright notice in the Description page of Project Settings.#include "BatteryCollectActor.h"ABatteryCollectActor::ABatteryCollectActor()
{//设置物理状态GetMesh()->SetSimulatePhysics(true);//电池能力值BatteryPower = 200.f;
}void ABatteryCollectActor::WasCollected_Implementation()
{Super::WasCollected_Implementation();//销毁电池Destroy();
}//返回能量值
float ABatteryCollectActor::GetPower()
{return BatteryPower;
}
  • 角色类中也是要定义初始能量值与角色最大能量值
	//初始能量值与角色能量值UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float InitalPower;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float CharacterPower;
//------------------------------------------------------------------
InitalPower = 2000.f;
CharacterPower = InitalPower;

获取能量值

  • 在角色模版中定义几个方法,分别是获取初始能量、当前能量、更新设置能量,前两个处理函数都要在蓝图中进行调用,所以要加上BlueprintPure参数宏,第三个方法没有返回值,就不能加上BlueprintPure宏,用BlueprintCallable
UFUNCTION(BlueprintPure,Category="Power")float GetInitialPower();UFUNCTION(BlueprintPure, Category = "Power")float GetCurrentPower();UFUNCTION(BlueprintCallable, Category = "Power")void UpdataPower(float PowerChange);
  • 处理函数方法
float ABatteryRetrieverCharacter::GetInitialPower()
{return InitalPower;
}float ABatteryRetrieverCharacter::GetCurrentPower()
{return CharacterPower;
}void ABatteryRetrieverCharacter::UpdataPower(float PowerChange)
{CharacterPower += PowerChange;
}
  • 在收集电池处理函数中继续编写捡起电池的逻辑
void ABatteryRetrieverCharacter::CollectPickups()
{TArray<AActor*> CollectionActors;//返回该组件的参与重叠者列表CollectionSphere->GetOverlappingActors(CollectionActors);float CollectPower = 0.f;//能力值//遍历所有区域的电池,并存入数组for (int32 i = 0; i < CollectionActors.Num(); i++){ACollectActor* Collect = Cast<ACollectActor>(CollectionActors[i]);//转换成功,电池没有被销毁,电池没有被拾取if (Collect && !Collect->IsPendingKill() && Collect->IsActive()){Collect->WasCollected();//调用电池被收集的方法//检查CollectActor是否是BatteryCollect电池类ABatteryCollectActor* Battery = Cast<ABatteryCollectActor>(Collect);if (Battery){CollectPower += Battery->GetPower();//如果是当前电池,就增加能量值}Collect->SetActive(false);//电池被拾取}}if (CollectPower > 0.f){UpdataPower(CollectPower);//更新能量值}}

角色能量衰减

  • 在GameMode里面编写角色每秒衰减能量值的逻辑
  • 添加一个衰减的速率变量,然后重写Tick逻辑

BatteryRetrieverGameMode.h

// Copyright Epic Games, Inc. All Rights Reserved.#pragma once#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "BatteryRetrieverGameMode.generated.h"UCLASS(minimalapi)
class ABatteryRetrieverGameMode : public AGameModeBase
{GENERATED_BODY()public:ABatteryRetrieverGameMode();//衰减速率UPROPERTY(EditAnywhere,BlueprintReadWrite,Category="Power")float DecayRate;protected://重写Tickvirtual void Tick(float DeltaTime) override;
};

BatteryRetrieverGameMode.cpp

// Copyright Epic Games, Inc. All Rights Reserved.#include "BatteryRetrieverGameMode.h"
#include "BatteryRetrieverCharacter.h"
#include "UObject/ConstructorHelpers.h"
#include "Kismet/GameplayStatics.h"
ABatteryRetrieverGameMode::ABatteryRetrieverGameMode()
{//开启TickPrimaryActorTick.bCanEverTick = true;// set default pawn class to our Blueprinted characterstatic ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter"));if (PlayerPawnBPClass.Class != NULL){DefaultPawnClass = PlayerPawnBPClass.Class;}DecayRate = 0.01f;
}void ABatteryRetrieverGameMode::Tick(float DeltaTime)
{Super::Tick(DeltaTime);ABatteryRetrieverCharacter* MyCharacter = Cast<ABatteryRetrieverCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));if (MyCharacter){if (MyCharacter->GetCurrentPower() > 0.f){//每帧进行衰减能量MyCharacter->UpdataPower(-(DeltaTime * DecayRate * MyCharacter->GetInitialPower()));}}}

修改玩家速度

  • 当能量到达某个状态的时候控制的玩家应该需要被减速
  • 我们新建一个玩家基础速度变量与一个速度因子用来控制玩家的速度和一个在蓝图中调用的处理能量值变化的函数方法
	//速度因子UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float SpeedFactor;//初始速度UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float BaseSpeed;UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Power")void PowerChangeEffect();
  • 根据能量更新玩家速度
SpeedFactor = 0.75f;
BaseSpeed = 10.f;void ABatteryRetrieverCharacter::UpdataPower(float PowerChange)
{CharacterPower += PowerChange;//根据Power改变玩家速度GetCharacterMovement()->MaxWalkSpeed = BaseSpeed + SpeedFactor * CharacterPower;}

拾取电池的粒子效果

  • 在电池蓝图中去进行添加粒子效果的设置,使用之前在C++编写好的处理函数,进行粒子添加
    在这里插入图片描述

设置玩家的材质变化

  • 在第三人称蓝图脚本中创建指定的材质实例
    在这里插入图片描述

  • 然后在Tick中去实现颜色的变化,注意UE5中的BlueprintImplementableEvent宏参数的函数,必须要调用了,UE4中使用的时候是不用调用的
    在这里插入图片描述

  • Tint是第三人称模版材质中的颜色变换
    在这里插入图片描述

游戏通关条件设定

  • 游戏通关状态我们在GameMode中进行判断
  • 重写一下BeginPlay函数用于编写通关逻辑,新建一个可以通关的能量值变量
	//通关需要的能量值UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")float PowerToWin;//重写BeginPlayvirtual void BeginPlay() override;
  • BeginPlay逻辑
void ABatteryRetrieverGameMode::BeginPlay()
{Super::BeginPlay();ABatteryRetrieverCharacter* MyCharacter = Cast<ABatteryRetrieverCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));//游戏通过条件if (MyCharacter){PowerToWin = MyCharacter->GetInitialPower() * 1.25f;}
}
  • 然后在项目名.Build.cs文件中添加模块

  • PublicDependencyModuleNames.AddRange(new string[] { “Slate”, “SlateCore” }); 表示将 Slate 和 SlateCore 模块添加为当前模块的公共依赖项。这意味着在编译当前模块时,编译器会确保先编译和链接 Slate 和 SlateCore 模块。

  • 而 PublicDependencyModuleNames.AddRange(new string[] { “UMG” }); 则表示将 UMG 模块添加为当前模块的公共依赖项。由于 UMG 是基于 Slate 和 SlateCore 构建的,所以在启用 UMG 插件后,Slate 和 SlateCore 会自动成为项目的依赖项。

// Copyright Epic Games, Inc. All Rights Reserved.using UnrealBuildTool;public class BatteryRetriever : ModuleRules
{public BatteryRetriever(ReadOnlyTargetRules Target) : base(Target){PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" });PublicDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });PublicDependencyModuleNames.AddRange(new string[] { "UMG" });}
}
  • 在电池类中头文件中要添加#include “Core.h”
    在这里插入图片描述
  • 在GameMode类中声明UMG组件
//HUD的WidgetUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power")TSubclassOf<class UUserWidget> HUDWidgetClass;//HUD实例UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Power")UUserWidget* CurrentWidget;
  • 创建UMG
  • CreateWidget:创建Widget,头文件#include "Blueprint/UserWidget.h"
  • AddToViewport:添加视口
void ABatteryRetrieverGameMode::BeginPlay()
{Super::BeginPlay();ABatteryRetrieverCharacter* MyCharacter = Cast<ABatteryRetrieverCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));//游戏通过条件if (MyCharacter){PowerToWin = MyCharacter->GetInitialPower() * 1.25f;}//创建UMGif (HUDWidgetClass != nullptr){CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), HUDWidgetClass);if (CurrentWidget){CurrentWidget->AddToViewport();}}
}

人物能量进度条UMG

  • 创建一个UI控件用来显示电池能量的UMG
    在这里插入图片描述
  • 创建一个蓝图的GameMode,添加上当前UI的界面
    在这里插入图片描述
  • 此时UI界面就添加上去了
    在这里插入图片描述
  • 进度条绑定一下函数,与能量值实时交互逻辑
    在这里插入图片描述

设置游戏状态

  • 在GameMode里面添加一个枚举类型表示当前游戏状态,枚举类型变量有游戏中、游戏胜利、游戏结束、游戏未知的状态
UENUM(BlueprintType)
enum class EBatteryPlayState :uint8
{EBPS_Playing	UMETA(DisplayName="Playing"),EBPS_GameOver	UMETA(DisplayName = "GemaOver"),EBPS_Won		UMETA(DisplayName = "Won"),EBPS_Unknown	UMETA(DisplayName="Unknow")
};
  • 新增一个枚举变量对象,与两个处理函数方法
	//当前状态对象EBatteryPlayState CurrentState;//获取当前状态UFUNCTION(BlueprintPure, Category = "State")EBatteryPlayState GetCurrentState();//设置当前状态UFUNCTION(BlueprintCallable,Category="State")void SetCurrentState(EBatteryPlayState StateName);
  • 处理函数逻辑
EBatteryPlayState ABatteryRetrieverGameMode::GetCurrentState()
{return CurrentState;
}void ABatteryRetrieverGameMode::SetCurrentState(EBatteryPlayState StateName)
{CurrentState = StateName;
}
  • Tick游戏中的逻辑编写,当前电池收集量大于胜利电池能量时游戏状态为胜利,当当前能量小于0了游戏设置结束
void ABatteryRetrieverGameMode::Tick(float DeltaTime)
{Super::Tick(DeltaTime);ABatteryRetrieverCharacter* MyCharacter = Cast<ABatteryRetrieverCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));if (MyCharacter){if (MyCharacter->GetCurrentPower() > PowerToWin){//游戏胜利SetCurrentState(EBatteryPlayState::EBPS_Won);}else if (MyCharacter->GetCurrentPower() > 0.f){//每帧进行衰减能量MyCharacter->UpdataPower(-(DeltaTime * DecayRate * MyCharacter->GetInitialPower()));}else{//游戏结束SetCurrentState(EBatteryPlayState::EBPS_GameOver);}}}
  • 在UI中添加一个Text用来表示当前游戏状态
    在这里插入图片描述
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

游戏状态处理

  • 需求分析:我们现在得让游戏开始的时候才开始掉落电池,游戏结束了就不在掉落电池
  • 在生成器类中添加一个是否开启掉落电池的处理方法,然后删除一开始在BeginPlay里面测试一直生成掉落电池代码
	//是否开启电池掉落UFUNCTION(BlueprintCallable, Category = "Spawn Volume")void SetSpawningActive(bool bState);
  • 处理方法逻辑:检测状态是否为真,为真就生成电池,为假就停止生产
void ASpawnVolume::SetSpawningActive(bool bState)
{if (bState){SpawnDelay = FMath::FRandRange(MinDelayTimer, MaxDelayTimer);GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);}else{GetWorld()->GetTimerManager().ClearTimer(TimerHandle);}
}
  • 在GameMode类中,添加一个数组记录关卡中的SpawnVolume,添加一个回调状态的方法
//记录关卡中的SpawnVolume
TArray<class SpawnVolume*> SpawnVolumeActors;//处理玩家状态方法回调
void HandleNewState(EBatteryPlayState NewState);
  • BeginPlay中获取到所有的ASpawnVolume
void ABatteryRetrieverGameMode::BeginPlay()
{Super::BeginPlay();TArray<AActor*> FoundActors;UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundActors);for (auto Actor : FoundActors){ASpawnVolume* SpawnVolumeActor = Cast<ASpawnVolume>(Actor);if (SpawnVolumeActor){SpawnVolumeActors.AddUnique(SpawnVolumeActor);}}SetCurrentState(EBatteryPlayState::EBPS_Playing);ABatteryRetrieverCharacter* MyCharacter = Cast<ABatteryRetrieverCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));//游戏通过条件if (MyCharacter){PowerToWin = MyCharacter->GetInitialPower() * 1.25f;}if (HUDWidgetClass != nullptr){CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), HUDWidgetClass);if (CurrentWidget){CurrentWidget->AddToViewport();}}
}
  • 在设置当前状态中更新回调处理方法
void ABatteryRetrieverGameMode::SetCurrentState(EBatteryPlayState StateName)
{CurrentState = StateName;HandleNewState(StateName);
}
  • 回调方法逻辑
void ABatteryRetrieverGameMode::HandleNewState(EBatteryPlayState NewState)
{switch (NewState){case EBatteryPlayState::EBPS_Playing:for (ASpawnVolume* Volume : SpawnVolumeActors){Volume->SetSpawningActive(true);};break;case EBatteryPlayState::EBPS_GameOver:for (ASpawnVolume* Volume : SpawnVolumeActors){Volume->SetSpawningActive(false);};break;case EBatteryPlayState::EBPS_Won:break;case EBatteryPlayState::EBPS_Unknown:break;default:break;}
}

玩家死亡效果

  • 在游戏结束后,我们要禁用用户输入,然后开启物理系统,禁止跳跃
  • 头文件:
    • #include "GameFramework/Character.h"
    • #include "GameFramework/PawnMovementComponent.h"
void ABatteryRetrieverGameMode::HandleNewState(EBatteryPlayState NewState)
{switch (NewState){case EBatteryPlayState::EBPS_Playing:for (ASpawnVolume* Volume : SpawnVolumeActors){Volume->SetSpawningActive(true);};break;case EBatteryPlayState::EBPS_GameOver:for (ASpawnVolume* Volume : SpawnVolumeActors){Volume->SetSpawningActive(false);APlayerController* PlayerControl = UGameplayStatics::GetPlayerController(this, 0);if (PlayerControl){//禁用部分输入PlayerControl->SetCinematicMode(true, false, false, true, true);}//加入布娃娃系统ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);if (MyCharacter){MyCharacter->GetMesh()->SetSimulatePhysics(true);MyCharacter->GetMovementComponent()->MovementState.bCanJump = false;}};	break;case EBatteryPlayState::EBPS_Won:break;case EBatteryPlayState::EBPS_Unknown:break;default:break;}
}
  • 在第三人称模版中添加一个物理资产
    在这里插入图片描述
  • 将第三人称模版Mesh碰撞改成启用碰撞(查询与物理)
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

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

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

相关文章

Yestar成都艺星舒适热玛吉星品沙龙会在蓉成功发布

12月21日&#xff0c;由Yestar成都艺星联合索塔医疗联合举办的“舒适无痛热玛吉星品沙龙会”在院内圆满举行&#xff0c;索塔医疗西区大客户经理肖峰、中国临床事业部刘颖&#xff0c;成都艺星运营部长程燕佳&#xff0c;皮肤科院长朱紫婷、技术院长杨海皎、主任王小琴&#xf…

年末汇总⭐️ 我是如何从学生切换到职场人身份的

目录 2023.12.23 天气阴 温度较低 一、Learning 二、Working 三、Living 章末 2023.12.23 天气阴 温度较低 小伙伴们大家好&#xff0c;冬已至 年将末 身为逮虾户的我看到大家的年末总结心中也不由得涌起一股创作热情&#xff0c;奈何没文化&#x…

MySQL——复合查询

目录 一.基本查询回顾 二. 多表查询 三.自连接 四.子查询 1.单行子查询 2.多行子查询 3.多列子查询 4.在from子句中使用子查询 5.合并查询 一.基本查询回顾 准备数据库&#xff1a; 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为…

【小沐学写作】Docsify制作在线电子书、技术文档(Docsify + Markdown + node)

文章目录 1、简介2、安装2.1 node2.2 docsify-cli 3、配置3.1 初始化3.2 预览效果3.3 加载对话框3.4 更多页面3.5 侧 栏3.6 自定义导航栏 结语 1、简介 https://docsify.js.org/#/?iddocsify 一个神奇的文档网站生成器。 简单轻巧没有静态构建的 html 文件多个主题 Docsify…

安卓13上手势导航失效、手机卡死问题

问题描述&#xff1a;打开我们开发的app后&#xff0c;手势导航无法退回、无法回到桌面、无法切换应用。 使用设备&#xff1a;小米手机、MI14,、安卓13 未适配安卓13安卓x的情况下&#xff0c;检查自己的 AndroidManifest 文件&#xff0c;过滤器是否设置了 <category a…

Python学习路线 - Python语言基础入门 - Python异常、模块与包

Python学习路线 - Python语言基础入门 - Python异常、模块与包 了解异常什么是异常bug单词的诞生异常演示 异常的捕获方法为什么要捕获异常捕获常规异常捕获指定异常捕获多个异常捕获异常并输出描述信息捕获所有异常异常 else异常的finally 异常的传递Python模块什么是模块模块…

基于docker-compose 安装Sonar并集成gitlab

文章目录 1. 前置条件2. 编写docker-compose-sonar.yml文件3. 集成 gitlab4. Sonar Login with GitLab 1. 前置条件 安装docker-compose 安装docker 创建容器运行的特有网络 创建挂载目录 2. 编写docker-compose-sonar.yml文件 version: "3" services:sonar-postgre…

银河麒麟v10 rpm安装包 安装mysql 8.35

银河麒麟v10 rpm安装包 安装mysql 8.35 1、卸载mariadb2、下载Mysql安装包3、安装Mysql 8.353.1、安装Mysql 8.353.3、安装后配置 1、卸载mariadb 由于银河麒麟v10系统默认安装了mariadb 会与Mysql相冲突&#xff0c;因此首先需要卸载系统自带的mariadb 查看系统上默认安装的M…

智能优化算法应用:基于爬行动物算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于爬行动物算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于爬行动物算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.爬行动物算法4.实验参数设定5.算法结果6.…

MySQL 事务的ACID特性

MySQL事务是什么&#xff0c;它就是一组数据库的操作&#xff0c;是访问数据库的程序单元&#xff0c;事务中可能包含一个或者多个 SQL 语句。这些SQL 语句要么都执行、要么都不执行。我们知道&#xff0c;在MySQL 中&#xff0c;有不同的存储引擎&#xff0c;有的存储引擎比如…

RobotFramework 自动化测试实战进阶篇

工具 Robotframework, 采用PO设计模式 PO模型 PO模型即Page Objects&#xff0c;直译意思就是“页面对象”&#xff0c;通俗的讲就是把一个页面&#xff0c;或者说把一个页面的某个区域当做一个对象&#xff0c;通过封装这个对象可以实现调用。 PO设计的好处 代码复用&…

ctfshow sql 195-200

195 堆叠注入 十六进制 if(preg_match(/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\|\"|select|union|or|and|\x26|\x7c|file|into/i, $username)){$ret[msg]用户名非法;die(json_encode($ret));}可以看到没被过滤&#xff0c;select 空格 被过滤了&#xff0c;可…