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)
{
ObjectPoolComponent = CreateDefaultSubobject<UObjectPoolComponent>(TEXT("Object Pool Component"));
}
void AEnemyCharacter::BeginPlay()
@ -15,6 +16,8 @@ void AEnemyCharacter::BeginPlay()
Super::BeginPlay();
GetHealthComponent()->OnDamaged.BindUFunction(this, "OnDamaged");
GetHealthComponent()->OnDeath.BindUFunction(this, "OnDeath");
ObjectPoolComponent->OnRetrieve.BindUFunction(this, "ResetHealth");
}
void AEnemyCharacter::Tick(float DeltaTime)
@ -33,8 +36,6 @@ void AEnemyCharacter::OnDamaged()
void AEnemyCharacter::OnDeath()
{
//if (IsValid(EXPPickupTemplate))
//{
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
@ -45,5 +46,10 @@ void AEnemyCharacter::OnDeath()
AVampireGameMode* gamemode = Cast<AVampireGameMode>(UGameplayStatics::GetGameMode(GetWorld()));
gamemode->IncrementEnemyDeathCount();
//}
gamemode->GetEnemyObjectPoolManager()->ReturnObject(this);
}
void AEnemyCharacter::ResetHealth()
{
GetHealthComponent()->ResetHealth();
}

View File

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

View File

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

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
EnemyCharacter->OnDeath();
EnemyCharacter->DetachFromControllerPendingDestroy();
/*EnemyCharacter->DetachFromControllerPendingDestroy();
EnemyCharacter->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
EnemyCharacter->GetCapsuleComponent()->SetCollisionResponseToAllChannels(ECR_Ignore);
@ -72,7 +72,7 @@ void AVampireAIController::OnDeath(FDamageInfo info)
characterMovementComponent->SetComponentTickEnabled(false);
}
GetWorldTimerManager().ClearTimer(PawnMoveToTimerHandle);
EnemyCharacter->SetLifeSpan(0.1f);
EnemyCharacter->SetLifeSpan(0.1f);*/
}
void AVampireAIController::PawnMoveTo()

View File

@ -65,13 +65,29 @@ void AVampireGameMode::SpawnEnemy()
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AEnemyCharacter* Actor = GetWorld()->SpawnActor<AEnemyCharacter>(EnemyTemplate, Transform, SpawnParameters);
if (AActor* object = GetEnemyObjectPoolManager()->GetObject())
{
AEnemyCharacter* Actor = Cast<AEnemyCharacter>(object);
Actor->SetActorTransform(Transform);
float CapsuleRadius = Actor->GetCapsuleComponent()->GetScaledCapsuleRadius();
FVector Direction = SpawnLocation - PlayerCharacter->GetActorLocation();
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()

View File

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