UE4 C++示例工程Battery Collector

发表于2018-02-06
评论0 3.9k浏览

《Battery Collector》这个是官方的一个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;
public;
    ABatteryCollectorCharacter();
    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;
    }
}
来自:http://blog.csdn.net/sinat_27456831/article/details/52027818

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引