UE4 C++示例工程Battery Collector(4.10版本又更名为3rd Person Power-up)

本教程提供了一系列关于如何使用C++进行虚幻4游戏开发的教学视频,包括游戏逻辑实现、引擎功能运用等内容。教程涉及Pickup、BatteryPickup、BatteryCollectorCharacter等类的实现,展示了如何创建游戏中的物品收集机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个是官方的一个C++示范工程,一共有21个教学视频,总时长2个小时。从游戏逻辑上、引擎功能使用程度上来说,都属于比较简单的层次,不过以入门、了解虚幻4的C++特性为目的,这个还是不错的素材。最终效果见优酷链接。下面是主要代码,包含5个类:Pickup,BattertyPickup,BatteryCollectorCharacter,BatteryCollectorGameMode,SpawnVolume,还有少量UMG功能也使用了C++,这里不再列出。
这里写图片描述

Pickup类

Pickup.h

#include "GameFreamework/Actor.h"
#include "Pickup.generated.h"

UCLASS()
class BATTERYCOLLECTOR_API APickup :public AActor
{
    GENERATED_BODY();

public:
    //构造函数,设置初始值
    APickup();

    //当游戏开始或者被spawn时函数被调用
    virtual void BeginPlay() override;

    //每帧调用
    virtual void Tick(float DeltaSeconds) override;

    //返回static mesh 
    FORCEINLINE class UStaticMeshComponent* GetMesh() const 
    {
        return PickupMesh;
    }

    //返回pickup当前状态
    UFUNCTION(BlueprintPure, Category = "Pickup")
    bool IsActive();
    //允许其他类安全的改变pickup的状态
    UFUNCTION(BlueprintCallable, Category = "Pickup")
    void SetActive(bool NewPickupState);

    //当pickup被拾取时调用
    UFUNCTION(BlueprintNativeEvent)
    void WasCollected();

    virtual void WasCollected_Implementation();

protected:
    //pickup 是否在激活状态
    bool bIsActive;

private:

    //static mesh 是pickup的实体表现
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pickup", meta = (AllowPrivateAccess = "true"))
    class UStaticMeshComponent* PickupMesh;
}

Pickup.cpp

#include "BatteryCollector.h"
#include "Pickup.h"


APickup::APickup()
{
    PrimaryActorTick.bCanEverTick = false;
    //创建static mesh 组件,CreateDefaultSubobject<>()函数
    PickupMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PickupMesh"));
    RootComponent = PickupMesh;
    bIsActive = true;
}

void APickup::BeginPlay()
{
    Super::BeginPlay();
}

void APickup::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

bool APickup::IsActive()
{
    return bIsActive;
}

void APickup::SetActive(bool NewPickupState)
{
    bIsActive = NewPickupState;
}
void APickup::WasCollected()
{
    Fstring PickupDebugString = GetName();
    UE_LOG(LogClass,Log, TEXT("You have collected %s",PickupDebugString));
}

BatteryPickup类

BatteryPickup.h

#include "Pickup.h"
#include "BatteryPickup.generated.h"

UCLASS()
class BATTERYCOLLECTOR_API ABatteryPickup : public APickup
{
    GENERATED_BODY();
public:
    ABatteryPickup();

    void WasCollected_Implementation() override;

    float GetPower();
protected:
   //BatteryPickup的能量值
   UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "Power" , meta = (BlueprintProtected = "true"));
   float BatteryPower
}

BatteryPickup.cpp

#include "BatteryCollector.h"
#include "BatteryPickup.h"

ABatteryPickup::ABatteryPickup()
{
    //电池pickup子类,模拟物理效果
    GetMesh()->SetSimulatePhysics(true);

    BatteryPower = 150.f;
}

void ABatteryPickup::WasCollected_Implementation()
{
    //使用基类的函数
    Super::WasCollected_Implementation();
    //销毁battery
    Destroy();
}

float ABatteryPickup::GetPower()
{
    return BatteryPower;
}

SpawnVolume类

SpawnVolume.h

#include "GameFramework/Actor.h"
#include "SpawnVolume.generated.h"

UCLASS()
class BATTERYCOLLECTOR_API ASpawnVolume : public AActor
{
    GENERATED_BODY()


public:
    ASpawnVolume();

    virtual void BeginPlay() override;

    virtual void Tick(float DeltaSeconds) override;
    //返回GetWhereToSpawn组件
    FORCEINLIE class UBoxComponent* GetWhereToSpawn() const { return WhereToSpawn;}

    //返回spawnvolume中任意一点
    UFUNCTION(BlueprintPure, Category = "Spawning")
    FVector GetRandomPointInVolume();

    //设置是否可以spawn
    UFUNCTION(BlueprintCallable, Category = "Spawning")
    void SetSpawningActive(bool bShouldSpawn);
private:
    //box component 实例化pick up的地点
    UPROPERTY(VisibleAnywhere,BlueprintReanOnly,Category = "Spawning", meta = (AllowPrivateAccess = "true"))
    class UBoxComponent* WhereToSpawn;
    //
    void SpawnPickup();

    //当前spawn的时间间隔
    float SpawnDelay;
protected:
    //spawn的pickup类
    UPROPERTYY(EditAnywhere, Category = "Spawning")
    TSubclassof<class APickup> WhatToSpawn;

    FTimerHandle SpawnTimer;

    //spawn 时间间隔
    UPROPERTY(EditAnywhere,BlueprintReadWrite,category = "Spawning")
    float SpawnDelayRangeHigh;
    UPROPERTY(EditAnywhere,BlueprintReadWrite,category = "Spawning")
    float SpawnDelayRangeLow
}

SpawnVolume.cpp

#include "BatteryCollector.h"
#include "SpawnVolume.h"
#include "Kismet/KismetMathLiibrary.h"
#include "Pickup.h"

ASpawnVolume::ASpawnVolume()
{
    PrimaryActorTick.bCanEverTick = false;

    WhereToSpawn = CreateDefaultSubobject<UBoxComponent>(TEXT("WhereToSpawn"));
    RooComponent = WhereToSpawn;

    SpawnDelayRangeLow = 1.0f;
    SpawnDelayRangeHigh = 4.5f;

}

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

}

FVector ASpawnVolume::GetRandomPointInVolume()
{
    FVector SpawnOrigin = WhereToSpawn->Bounds.Origin;
    Fvector SpawnExtent = WhereToSpawn->Bounds.BoxExtent;
    //返回box  component内任意一点
    return UKismetMathLibrary::RandomPointInBoundingBox(SpawnOrigin,SpawnExtent);
}

void ASpawnVolume::SetSpawningActive(bool bShouldSpawn)
{

    if(bShouldSpawn)
    {
        //如果spawn时,通过timer定时器不断激活SpawnPickup()函数
        SpawnDelay = FMath::FRandRange(SpawnDelayRangeLow,SpawnDelayRangeHigh);
        GetWorldTimerManager().SetTimer(SpawnTimer,this,&ASpawnVolume::SpawnPickup,SpawnDelay,false);
    }
    else
    {
        //不spawn时,清除定时器即可
        GetWorldTimerManager().ClearTimer(SpawnTimer);
    }
}


void ASpawnVolume::SpawnPickup()
{
    //pickup是否存在
    if(WhatToSpawn != NULL)
    {
        //当前世界是否有效
        UWorld* const World = GetWorld();
        if(World)
        {

            //设置spawn参数
            FActorSpawnParameters SpawnParams;
            SpawnParams.Owner = this;
            SpawnParams.Instigator = Instigator;

            Fvector SpawnLocation = GetRandomPointInVolume();
            FRotator SpawnRotation;
            SpawnRotation.Yaw = FMath::FRand()*360.f
            SpawnRotation.Pitch = FMath::FRand()*360.f
            SpawnRotation.Roll = FMath::FRand()*360.f

            //生成pickup
            APickup* const SpawnedPickup = World->SpawnActor<APickup>(WhatToSpawn,SpawnLocation,SpawnRotation,SpawnParams);
        }
    }
}

BatteryCollectorCharacter类
限于篇幅,不再摘抄Character类自带的大量代码,只显示新增的代码

BatteryCollectorCharacter.h

#include "BatteryCollectorCharacter.generated.h"

UCLASS(config=Game)
{
private:
    //pickup接触到的范围
    UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = Camera)
    class USphereComponent* CollectionSphere;

    //当前能量值
    UPROPERTY(VisibleAnywhere, Category = "Power")
    float CharecterPower;

publicABatteryCollectorCharacter();

    FORCEINLINE class USphereComponent* GetCollectionSphere const { return CollectionSphere;}

    UFUNCTION(BlueprintPure,Category = "Power")
    float GetInitialPower();
    UFUNCTION(BlueprintPure,Category = "Power")
    float GetCharecterPower();
    //更新当前能量值
    UFUNCTION(BlueprintCallable, Category = "Power")
    void UpdatePower(float PowerChange);

protected:

    //当按下按键开始收集pickup
    UFUNCTION(BlueprintCallable, Category = "Pickups")
    void CollectPickups();

    //初始能量值
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power", Meta  = (BlueprintProtected = "true"))
    float InitialPower;

    //玩家速度影响因子
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power", Meta  = (BlueprintProtected = "true"))
    float SpeedFactor;

    //玩家初始速度
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Power", Meta  = (BlueprintProtected = "true"))
    float BaseSpeed;

    //
    UFUNCTION(BlueprintImplementableEvent,Category = "Power")
    void PowerChangeEffect();
}

BatteryCollectorCharacter.cpp

#include "BatteryCollector.h"
#include "BatteryCollectorCharacter.h"
#include "BatteryPickup.h"


ABatteryCollectorCharacter::ABatteryCollectorCharater()
{
   CollectionSphere = CreatDefaultSubobject<USphereComponent>(TEXT("CollectionSphere"));
   CollectionSphere->AttachTo(RootComponent);
   CollectionSphere->SetSphereRadius(200.f);

   InitialPower = 200.0f;
   CharacterPower = InitialPower;
   SpeedFactor = 0.75f;
   BaseSpeed = 10.0f
}


void ABatteryCollectorCharacter::SetupPlayerInputComponent(class UIputComponent* InputComponent)
{
    InputComponent->BindAction("Collect",IE_Pressed,this,&ABatteryCollectorCharacter::CollectPickups);
}

void ABatteryCollectorCharacter::CollectPickups()
{
    //得到所有overlapping的物体
    TArray<AActor*> CollectedActors;
    CollectionSphere->GetOverlappingActors(CollectedActors);
    //记录获得的能量值
    float CollectedPower = 0;

    //遍历得到的物体,转换为 APickup类
    for(int32 iCollected = 0; iCollected < CollectedActors.Num(); ++iCollected)
    {
        APickup* const TestPickup = Cast<APickup> (CollectedActors[iCollected]);

        if(TestPickup && !TestPickup->IsPendingKill() && TestPickup->IsActive())
        {
            //调用pickup类的WasCollected()函数
            TestPickup->WasCollected();
            ABatteryPickup* const TestBattery= Cast<ABatteryPickup>(TestPickup);
            if(TestBattery)
            {
                CollectedPower += TestBattery->GetPower();
            }
            TestPickup->SetActive(false);
        }
    }
    if(CollectedPower > 0)
    {
        UpdatePower(CollectedPower);
    }
}

float ABatteryCollectorCharacter::GetInitialPower()
{
    return InitialPower;
}

float ABatteryCollectorCharacter::GetCharacterPower()
{
    return CharacterPower;
}


void ABatteryCollectorCharacter::UpdatePower(float PowerChange)
{
    CharacterPower = CharacterPower + PowerChange;
    GetCharacterMovement()->MaxWalkSpeed = BaseSpeed + SpeedFactor*CharacterPower;
    //视觉效果
    PowerChangeEffect();
}

BatteryCollectorGameMode类

BatteryCollectorGameMode.h

#include "GameFramework/GameMode.h"
#include "BatteryCollectorGameMode.generated.h"

UENUM(BlueprintType)
enum class EBatteryPlayState
{
    EPlaying,
    EGameOver,
    EWon,
    EUnknown
};


UCLASS(minimalapi)
class ABatteryCollectorGameMode :public AGameMode
{
    GENERATED_BODY()
public:
    ABatteryCollectorGameMode();

    virtual void Tick(float DeltaTime)

    UFUNCTION(BlueprintPure, Category = "Power")
    float GetPowerTowin() const();


    virtual void BeginPlay() override;

    UFUNCTION(BlueprintPure, Category = "Power")
    EBatteryPlayState GetCurrentState();


    void  SetCurrentState(EBatteryPlayState NewState);

protected:
    //玩家角色能量值减少频率
    UPROPERTY(EditDefaultOnly, BlueprintReadWrite, Category = "Power", BlueprintProtected = "true")
    float DecayRate;    


    //玩家获胜的能量值
    UPROPERTY(EditDefaultOnly, BlueprintReadWrite, Category = "Power", BlueprintProtected = "true")
    float PowerToWin;


private:
    EBatteryPlayState CurrentState;

    TArray<class ASpawnVolume*> SpawnVolumeActors;

    //改变state
    void HandleNewState(EBatteryPlayState NewState);
}

BatteryCollectorGameMode.cpp

#include "BatteryCollector.h"
#include "BatteryCollectorGameMode.h"
#include "BatteryCollectorCharacter.h"
#include "Kismet/GameplayStatics.h"


ABatteryCollectorGameMode:: ABatteryCollectorGameMode()
{



    DecayRate = 0.01f;
}

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

    //从场景内找到所有SpawnVolume类
    TArray<AActors*> FoundActors;
    UGameplayStatics::GetAllActorsOfClass(GetWorld(),ASpawnVolume::StaticClass(),FoundActors);

    for(auto Actor :FoundActors)
    {
        ASpawnVolume* SpawnVolumeActor = Cast<ASpawnVolume>(Actor);
        if(SpawnVolumeActor)
        {
            SpawnVolumeActors.AddUnique(SpawnVolumeActor);
        }
    }
}

    SetCurrentState(EBatteryPlayState::EPlaying);


    ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this,0));
    if(MyCharacter)
    {
        PowerToWin = MyCharacter->GetInitialPower()*1.25f;
    }


void ABatteryCollectorGameMode::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this,0));


    if(MyCharacter)
    {
        if(MyCharacter->GetCurrentPower() > PowerToWin)
        {
            SetCurrentState(EBatteryPlayState::EWon);
        }

        else if(MyCharacter->GetPlayerPower() > 0)
        {
             MyCharacter->UpdatePower(-DeltaTime*DecayRate*(MyCharacter->GetInitialPower()));
        }

        else 
        {
            SetCurrentState(EBatteryPlayState::EGameOver);
        }
    }
}

EBatteryPlayState ABatteryCollectorGameMode::GetCurrentState() const
{
    return CurrentState;
}
void ABatteryCollectorGameMode::SetCurrentState(EBatteryPlayState NewState)
{
    CurrentState = NewState;
    HandleNewState(CurrentState);
}

//切换游戏状态
void ABatteryCollectorGameMode::HandleNewState(EBatteryPlayState NewState)
{
    switch(NewState)
    {
        case EBatteryPlayState::EPlaying:
        {
            //激活spawnvolume
            for(ASpawnVolume* Volume : SpawnVolumeActors)
            {
                Volume->SetSpawningActive(true);
            }
        }
        break;
        case EBatteryPlayState::EWon:
        {
            for(ASpawnVolume* Volume : SpawnVolumeActors)
            {
                Volume->SetSpawningActive(false);
            }
            //关闭player的输入接收
            APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this,0);
            if(PlayerController)
            {
                PlayerController->SetCinematicMode(true,false,false,true);
            }
            //ragdoll ,最后玩家没电时的瘫痪效果
            ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this,0);
            if(MyCharacter)
            {
                MyCharacter->GetMesh()->SetSimulatePhysics(true);
                MyCharacter->GetMovementComponent->MovementState.bCanJump = false;
            }
        }
        break;
        case EBatteryPlayState::EGameOver:
        {
            for(ASpawnVolume* Volume : SpawnVolumeActors)
            {
                Volume->SetSpawningActive(false);
            }
        }
        break;
        case EBatteryPlayState::EUnknown:
        {

        }
        break;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值