UE4 C++示例工程Battery Collector
发表于2018-02-06
《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