Add Enemy Batching

This commit is contained in:
baz 2024-08-22 22:11:24 +01:00
parent 2ad6b53ab3
commit 3a729caab0
10 changed files with 187 additions and 29 deletions

View File

@ -8,6 +8,7 @@
AEnemyCharacter::AEnemyCharacter(const FObjectInitializer& ObjectInitializer) AEnemyCharacter::AEnemyCharacter(const FObjectInitializer& ObjectInitializer)
{ {
ObjectPoolComponent = CreateDefaultSubobject<UObjectPoolComponent>(TEXT("Object Pool Component"));
} }
void AEnemyCharacter::BeginPlay() void AEnemyCharacter::BeginPlay()
@ -15,6 +16,8 @@ void AEnemyCharacter::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
GetHealthComponent()->OnDamaged.BindUFunction(this, "OnDamaged"); GetHealthComponent()->OnDamaged.BindUFunction(this, "OnDamaged");
GetHealthComponent()->OnDeath.BindUFunction(this, "OnDeath"); GetHealthComponent()->OnDeath.BindUFunction(this, "OnDeath");
ObjectPoolComponent->OnRetrieve.BindUFunction(this, "ResetHealth");
} }
void AEnemyCharacter::Tick(float DeltaTime) void AEnemyCharacter::Tick(float DeltaTime)
@ -33,17 +36,20 @@ void AEnemyCharacter::OnDamaged()
void AEnemyCharacter::OnDeath() void AEnemyCharacter::OnDeath()
{ {
//if (IsValid(EXPPickupTemplate)) FActorSpawnParameters actorSpawnParameters;
//{ actorSpawnParameters.Owner = this;
FActorSpawnParameters actorSpawnParameters; actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.Owner = this; actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
GetWorld()->SpawnActor<AEXPPickup>(EXPPickupTemplate, GetActorLocation(), FRotator::ZeroRotator, GetWorld()->SpawnActor<AEXPPickup>(EXPPickupTemplate, GetActorLocation(), FRotator::ZeroRotator,
actorSpawnParameters); actorSpawnParameters);
AVampireGameMode* gamemode = Cast<AVampireGameMode>(UGameplayStatics::GetGameMode(GetWorld())); AVampireGameMode* gamemode = Cast<AVampireGameMode>(UGameplayStatics::GetGameMode(GetWorld()));
gamemode->IncrementEnemyDeathCount(); gamemode->IncrementEnemyDeathCount();
//} gamemode->GetEnemyObjectPoolManager()->ReturnObject(this);
}
void AEnemyCharacter::ResetHealth()
{
GetHealthComponent()->ResetHealth();
} }

View File

@ -4,6 +4,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "EXPPickup.h" #include "EXPPickup.h"
#include "ObjectPoolComponent.h"
#include "VampireCharacter.h" #include "VampireCharacter.h"
#include "BehaviorTree/BehaviorTree.h" #include "BehaviorTree/BehaviorTree.h"
#include "EnemyCharacter.generated.h" #include "EnemyCharacter.generated.h"
@ -19,12 +20,13 @@ class VAMPIRES_API AEnemyCharacter : public AVampireCharacter
public: public:
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
TSubclassOf<AEXPPickup> EXPPickupTemplate = nullptr; TSubclassOf<AEXPPickup> EXPPickupTemplate = nullptr;
private:
private:
UPROPERTY(EditDefaultsOnly, Meta = (AllowPrivateAccess = "true")) UPROPERTY(EditDefaultsOnly, Meta = (AllowPrivateAccess = "true"))
UBehaviorTree* BehaviorTree = nullptr; UBehaviorTree* BehaviorTree = nullptr;
UObjectPoolComponent* ObjectPoolComponent = nullptr;
public: public:
AEnemyCharacter(const FObjectInitializer& ObjectInitializer); AEnemyCharacter(const FObjectInitializer& ObjectInitializer);
@ -41,4 +43,8 @@ public:
UFUNCTION() UFUNCTION()
virtual void OnDeath(); virtual void OnDeath();
private:
UFUNCTION()
void ResetHealth();
}; };

View File

@ -70,6 +70,7 @@ void UHealthComponent::SetCurrentHealth(float value)
void UHealthComponent::ResetHealth() void UHealthComponent::ResetHealth()
{ {
CurrentHealth = MaxHealth; CurrentHealth = MaxHealth;
IsDead = false;
} }
void UHealthComponent::RecoverHealth(float value) void UHealthComponent::RecoverHealth(float value)
@ -105,4 +106,4 @@ void UHealthComponent::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
ResetHealth(); ResetHealth();
} }

View File

@ -0,0 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ObjectPoolComponent.h"

View File

@ -0,0 +1,21 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ObjectPoolComponent.generated.h"
DECLARE_DELEGATE(FOnRetrieve)
DECLARE_DELEGATE(FOnReturn)
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class VAMPIRES_API UObjectPoolComponent : public UActorComponent
{
GENERATED_BODY()
public:
FOnRetrieve OnRetrieve;
FOnReturn OnReturn;
};

View File

@ -0,0 +1,69 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ObjectPoolManager.h"
#include "ObjectPoolComponent.h"
// Called when the game starts or when spawned
void AObjectPoolManager::BeginPlay()
{
Super::BeginPlay();
}
void AObjectPoolManager::InitializeObjectPool(TSubclassOf<AActor> Object, const int InitialObjectPoolSize)
{
for (int i = 0; i < InitialObjectPoolSize; i++)
{
AActor* object = GetWorld()->SpawnActor<AActor>(Object);
SetObjectStatus(false, object);
ObjectPool.Add(object);
}
}
void AObjectPoolManager::InitializeObjectPool(UClass* Object, int InitialObjectPoolSize)
{
for (int i = 0; i < InitialObjectPoolSize; i++)
{
AActor* object = GetWorld()->SpawnActor<AActor>(Object);
SetObjectStatus(false, object);
ObjectPool.Add(object);
}
}
AActor* AObjectPoolManager::GetObject()
{
for (AActor* object : ObjectPool)
{
if (object->IsHidden())
{
SetObjectStatus(true, object);
if (UObjectPoolComponent* objectPoolComponent = object->GetComponentByClass<UObjectPoolComponent>())
{
objectPoolComponent->OnRetrieve.ExecuteIfBound();
}
return object;
}
}
return nullptr;
}
void AObjectPoolManager::ReturnObject(AActor* object)
{
SetObjectStatus(false, object);
if (UObjectPoolComponent* objectPoolComponent = object->GetComponentByClass<UObjectPoolComponent>())
{
objectPoolComponent->OnReturn.ExecuteIfBound();
}
}
void AObjectPoolManager::SetObjectStatus(bool enabled, AActor* object)
{
object->SetActorHiddenInGame(!enabled);
object->SetActorTickEnabled(enabled);
object->SetActorEnableCollision(enabled);
}

View File

@ -0,0 +1,30 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ObjectPoolManager.generated.h"
UCLASS()
class VAMPIRES_API AObjectPoolManager : public AActor
{
GENERATED_BODY()
TArray<AActor*> ObjectPool = TArray<AActor*>();
public:
void InitializeObjectPool(TSubclassOf<AActor> Object, int InitialObjectPoolSize = 400);
void InitializeObjectPool(UClass* Object, int InitialObjectPoolSize = 400);
AActor* GetObject();
void ReturnObject(AActor* object);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
private:
void SetObjectStatus(bool enabled, AActor* object);
};

View File

@ -61,7 +61,7 @@ void AVampireAIController::OnDeath(FDamageInfo info)
{ {
// TODO: Do stuff here // TODO: Do stuff here
EnemyCharacter->OnDeath(); EnemyCharacter->OnDeath();
EnemyCharacter->DetachFromControllerPendingDestroy(); /*EnemyCharacter->DetachFromControllerPendingDestroy();
EnemyCharacter->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision); EnemyCharacter->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
EnemyCharacter->GetCapsuleComponent()->SetCollisionResponseToAllChannels(ECR_Ignore); EnemyCharacter->GetCapsuleComponent()->SetCollisionResponseToAllChannels(ECR_Ignore);
@ -72,7 +72,7 @@ void AVampireAIController::OnDeath(FDamageInfo info)
characterMovementComponent->SetComponentTickEnabled(false); characterMovementComponent->SetComponentTickEnabled(false);
} }
GetWorldTimerManager().ClearTimer(PawnMoveToTimerHandle); GetWorldTimerManager().ClearTimer(PawnMoveToTimerHandle);
EnemyCharacter->SetLifeSpan(0.1f); EnemyCharacter->SetLifeSpan(0.1f);*/
} }
void AVampireAIController::PawnMoveTo() void AVampireAIController::PawnMoveTo()

View File

@ -57,21 +57,37 @@ void AVampireGameMode::SpawnEnemy()
UE_LOG(LogTemp, Warning, TEXT("Something broke")); UE_LOG(LogTemp, Warning, TEXT("Something broke"));
break; break;
} }
SpawnLocation.Z = PlayerCharacter->GetActorLocation().Z; SpawnLocation.Z = PlayerCharacter->GetActorLocation().Z;
FTransform Transform; FTransform Transform;
Transform.SetLocation(SpawnLocation); Transform.SetLocation(SpawnLocation);
FActorSpawnParameters SpawnParameters; FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AEnemyCharacter* Actor = GetWorld()->SpawnActor<AEnemyCharacter>(EnemyTemplate, Transform, SpawnParameters); if (AActor* object = GetEnemyObjectPoolManager()->GetObject())
float CapsuleRadius = Actor->GetCapsuleComponent()->GetScaledCapsuleRadius(); {
FVector Direction = SpawnLocation - PlayerCharacter->GetActorLocation(); AEnemyCharacter* Actor = Cast<AEnemyCharacter>(object);
Direction.Normalize(); Actor->SetActorTransform(Transform);
Direction *= CapsuleRadius; float CapsuleRadius = Actor->GetCapsuleComponent()->GetScaledCapsuleRadius();
Actor->SetActorLocation(SpawnLocation + Direction); FVector Direction = SpawnLocation - PlayerCharacter->GetActorLocation();
Actor->SpawnDefaultController(); Direction.Normalize();
Direction *= CapsuleRadius;
Actor->SetActorLocation(SpawnLocation + Direction);
Actor->SpawnDefaultController();
}
}
AObjectPoolManager* AVampireGameMode::GetEnemyObjectPoolManager()
{
if (EnemyObjectPoolManager == nullptr)
{
EnemyObjectPoolManager = GetWorld()->SpawnActor<AObjectPoolManager>();
TSubclassOf<AActor> enemyTemplate = EnemyTemplate;
EnemyObjectPoolManager->InitializeObjectPool(enemyTemplate);
}
return EnemyObjectPoolManager;
} }
void AVampireGameMode::IncrementEnemyDeathCount() void AVampireGameMode::IncrementEnemyDeathCount()

View File

@ -4,6 +4,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "EnemyCharacter.h" #include "EnemyCharacter.h"
#include "ObjectPoolManager.h"
#include "PlayerCharacter.h" #include "PlayerCharacter.h"
#include "VampirePlayerController.h" #include "VampirePlayerController.h"
#include "GameFramework/GameMode.h" #include "GameFramework/GameMode.h"
@ -30,18 +31,21 @@ private:
int EnemyDeathCount = 0; int EnemyDeathCount = 0;
AObjectPoolManager* EnemyObjectPoolManager = nullptr;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
UFUNCTION(BlueprintCallable, BlueprintPure) UFUNCTION(BlueprintCallable, BlueprintPure)
int GetEnemyDeathCount(); int GetEnemyDeathCount();
UFUNCTION() UFUNCTION()
void IncrementEnemyDeathCount(); void IncrementEnemyDeathCount();
AObjectPoolManager* GetEnemyObjectPoolManager();
protected: protected:
UFUNCTION() UFUNCTION()
void SpawnEnemy(); void SpawnEnemy();
}; };