Make pickups pooled

This commit is contained in:
baz 2025-02-16 22:29:37 +00:00
parent c133ccd1e9
commit f74ae1d263
19 changed files with 174 additions and 59 deletions

BIN
Content/Enemy/DA_Enemy.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Gamemode/BP_DefaultGamemode.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Pickups/EXP/BP_PickupTemplate.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Pickups/EXP/DA_BlueEXPPickup.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -9,18 +9,13 @@ void AEXPPickup::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
} }
void AEXPPickup::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void AEXPPickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, void AEXPPickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult) const FHitResult& SweepResult)
{ {
if (UEXPComponent* expComponent = OtherActor->GetComponentByClass<UEXPComponent>()) if (UEXPComponent* expComponent = OtherActor->GetComponentByClass<UEXPComponent>())
{ {
expComponent->IncrementEXP(EXP); expComponent->IncrementEXP(PickupValue);
Super::OnInnerBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult); Super::OnInnerBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);
} }
} }

View File

@ -14,17 +14,10 @@ class VAMPIRES_API AEXPPickup : public APickup
{ {
GENERATED_BODY() GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Pickup")
int EXP = 1;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
virtual void Tick(float DeltaSeconds) override;
virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult) override; const FHitResult& SweepResult) override;

View File

@ -45,34 +45,53 @@ void AEnemyCharacter::OnDamaged(FDamageInfo damageInfo)
void AEnemyCharacter::OnDeath(FDamageInfo damageInfo) void AEnemyCharacter::OnDeath(FDamageInfo damageInfo)
{ {
// TODO: Replace pickup spawning with pooling // TODO: Replace pickup spawning with pooling
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
auto spawnLocation = GetActorLocation(); if (PickupTemplate)
spawnLocation.Z = 75.0f; {
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
GetWorld()->SpawnActor<AEXPPickup>(EXPPickupTemplate, spawnLocation, FRotator::ZeroRotator, if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
actorSpawnParameters); {
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetPickupObjectPoolManager(gamemode))
{
AActor* pickup = objectPoolManager->GetObject();
if (UKismetSystemLibrary::DoesImplementInterface(pickup, UPickupable::StaticClass()))
{
IPickupable::Execute_LoadDataFromDataAsset(pickup, PickupTemplate);
pickup->SetActorLocation(GetActorLocation());
}
}
}
}
// FActorSpawnParameters actorSpawnParameters;
// actorSpawnParameters.Owner = this;
// actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
//
// auto spawnLocation = GetActorLocation();
// spawnLocation.Z = 75.0f;
//
// GetWorld()->SpawnActor<AEXPPickup>(EXPPickupTemplate, spawnLocation, FRotator::ZeroRotator,
// actorSpawnParameters);
} }
void AEnemyCharacter::LoadDataFromDataAsset_Implementation(UEnemyDataAsset* enemyDataAsset) void AEnemyCharacter::LoadDataFromDataAsset_Implementation(UEnemyDataAsset* enemyDataAsset)
{ {
if (enemyDataAsset != nullptr) if (enemyDataAsset != nullptr)
{ {
// TODO: Load more data
StaticMeshComponent->SetStaticMesh(enemyDataAsset->StaticMesh); StaticMeshComponent->SetStaticMesh(enemyDataAsset->StaticMesh);
BehaviorTree = enemyDataAsset->BehaviorTree; BehaviorTree = enemyDataAsset->BehaviorTree;
PickupTemplate = enemyDataAsset->PickupDataAsset;
} }
} }
void AEnemyCharacter::ResetData_Implementation() void AEnemyCharacter::ResetData_Implementation()
{ {
// TODO: Reset more data
StaticMeshComponent->SetStaticMesh(nullptr); StaticMeshComponent->SetStaticMesh(nullptr);
BehaviorTree = nullptr; BehaviorTree = nullptr;
PickupTemplate = nullptr;
} }
float AEnemyCharacter::GetCapsuleRadius_Implementation() float AEnemyCharacter::GetCapsuleRadius_Implementation()

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "PickupDataAsset.h"
#include "VampireCharacter.h" #include "VampireCharacter.h"
#include "Interfaces/Enemyable.h" #include "Interfaces/Enemyable.h"
#include "EnemyCharacter.generated.h" #include "EnemyCharacter.generated.h"
@ -28,6 +29,8 @@ private:
UObjectPoolComponent* ObjectPoolComponent = nullptr; UObjectPoolComponent* ObjectPoolComponent = nullptr;
UPickupDataAsset* PickupTemplate = nullptr;
public: public:
AEnemyCharacter(const FObjectInitializer& ObjectInitializer); AEnemyCharacter(const FObjectInitializer& ObjectInitializer);

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "PickupDataAsset.h"
#include "Engine/DataAsset.h" #include "Engine/DataAsset.h"
#include "EnemyDataAsset.generated.h" #include "EnemyDataAsset.generated.h"
@ -23,4 +24,7 @@ public:
UPROPERTY(EditDefaultsOnly, Meta = (AllowPrivateAccess = "true")) UPROPERTY(EditDefaultsOnly, Meta = (AllowPrivateAccess = "true"))
UBehaviorTree* BehaviorTree = nullptr; UBehaviorTree* BehaviorTree = nullptr;
UPROPERTY(EditDefaultsOnly, Meta = (AllowPrivateAccess = "true"))
UPickupDataAsset* PickupDataAsset = nullptr;
}; };

View File

@ -12,18 +12,13 @@ void AGoldPickup::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
} }
void AGoldPickup::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void AGoldPickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, void AGoldPickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult) const FHitResult& SweepResult)
{ {
if (UGoldComponent* goldComponent = OtherActor->GetComponentByClass<UGoldComponent>()) if (UGoldComponent* goldComponent = OtherActor->GetComponentByClass<UGoldComponent>())
{ {
goldComponent->IncrementGold(Gold); goldComponent->IncrementGold(PickupValue);
Super::OnInnerBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult); Super::OnInnerBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);
} }
} }

View File

@ -14,17 +14,10 @@ class VAMPIRES_API AGoldPickup : public APickup
{ {
GENERATED_BODY() GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
int Gold = 1;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
virtual void Tick(float DeltaSeconds) override;
virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult) override; const FHitResult& SweepResult) override;

View File

@ -0,0 +1,7 @@
// Louis Hobbs | 2024-2025
#include "Pickupable.h"
// Add default functionality here for any IPickupable functions that are not pure virtual.

View File

@ -0,0 +1,31 @@
// Louis Hobbs | 2024-2025
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Pickupable.generated.h"
class UPickupDataAsset;
// This class does not need to be modified.
UINTERFACE()
class UPickupable : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class VAMPIRES_API IPickupable
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent)
void LoadDataFromDataAsset(UPickupDataAsset* PickupDataAsset);
UFUNCTION(BlueprintNativeEvent)
void ResetData();
};

View File

@ -28,4 +28,7 @@ public:
UFUNCTION(BlueprintNativeEvent) UFUNCTION(BlueprintNativeEvent)
AObjectPoolManager* GetProjectileObjectPoolManager(); AObjectPoolManager* GetProjectileObjectPoolManager();
UFUNCTION(BlueprintNativeEvent)
AObjectPoolManager* GetPickupObjectPoolManager();
}; };

View File

@ -2,10 +2,15 @@
#include "Pickup.h" #include "Pickup.h"
#include "ObjectPoolManager.h"
#include "PlayerCharacter.h" #include "PlayerCharacter.h"
#include "Components/SphereComponent.h" #include "Components/SphereComponent.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "PaperSpriteComponent.h" #include "PaperSpriteComponent.h"
#include "PickupDataAsset.h"
#include "GameFramework/GameModeBase.h"
#include "Interfaces/Pools.h"
// Sets default values // Sets default values
APickup::APickup() APickup::APickup()
@ -54,6 +59,38 @@ void APickup::BeginPlay()
} }
} }
void APickup::LoadDataFromDataAsset_Implementation(UPickupDataAsset* PickupDataAsset)
{
if (PickupDataAsset != nullptr)
{
PickupValue = PickupDataAsset->PickupValue;
SpriteComponent->SetSprite(PickupDataAsset->PickupSprite);
PickupSoundBase = PickupDataAsset->PickupSoundBase;
CurveFloat = PickupDataAsset->CurveFloat;
if (CurveFloat != nullptr)
{
TimelineComponent->AddInterpFloat(CurveFloat, onTimelineCallback);
TimelineComponent->SetTimelineFinishedFunc(onTimelineFinishedCallback);
}
}
}
void APickup::ResetData_Implementation()
{
PickupValue = 0;
SpriteComponent->SetSprite(nullptr);
PickupSoundBase = nullptr;
CurveFloat = nullptr;
TSet<UCurveBase*> AllCurves;
TimelineComponent->GetAllCurves(AllCurves);
if (AllCurves.Num() > 0)
{
AllCurves.Reset();
}
}
void APickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, void APickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult) const FHitResult& SweepResult)
@ -66,9 +103,21 @@ void APickup::OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AAct
UGameplayStatics::PlaySound2D(GetWorld(), PickupSoundBase); UGameplayStatics::PlaySound2D(GetWorld(), PickupSoundBase);
} }
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
ResetData_Implementation();
objectPoolManager->ReturnObject(this);
}
}
else
{
Destroy(); Destroy();
} }
} }
}
void APickup::OnOuterBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, void APickup::OnOuterBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,

View File

@ -5,6 +5,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Components/TimelineComponent.h" #include "Components/TimelineComponent.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "Interfaces/Pickupable.h"
#include "Pickup.generated.h" #include "Pickup.generated.h"
class UPickupDataAsset; class UPickupDataAsset;
@ -13,19 +14,13 @@ class USphereComponent;
class UPaperSpriteComponent; class UPaperSpriteComponent;
UCLASS() UCLASS()
class VAMPIRES_API APickup : public AActor class VAMPIRES_API APickup : public AActor, public IPickupable
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UPickupDataAsset> PickupDataAsset;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
double PickupMovementRange = 500; int PickupValue = 1;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
double PickupMovementSpeed = 1000;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
USphereComponent* InnerSphereComponent = nullptr; USphereComponent* InnerSphereComponent = nullptr;
@ -33,6 +28,7 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
USphereComponent* OuterSphereComponent = nullptr; USphereComponent* OuterSphereComponent = nullptr;
// TODO: Replace with static mesh
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere)
UPaperSpriteComponent* SpriteComponent = nullptr; UPaperSpriteComponent* SpriteComponent = nullptr;
@ -40,7 +36,7 @@ public:
USoundBase* PickupSoundBase = nullptr; USoundBase* PickupSoundBase = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Timeline") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Timeline")
TObjectPtr<UTimelineComponent> TimelineComponent; TObjectPtr<UTimelineComponent> TimelineComponent = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Timeline") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Timeline")
UCurveFloat* CurveFloat; UCurveFloat* CurveFloat;
@ -59,6 +55,10 @@ protected:
// Called when the game starts or when spawned // Called when the game starts or when spawned
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void LoadDataFromDataAsset_Implementation(UPickupDataAsset* PickupDataAsset) override;
virtual void ResetData_Implementation() override;
UFUNCTION() UFUNCTION()
virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,

View File

@ -20,14 +20,9 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
int PickupValue = 1; int PickupValue = 1;
// TODO: Replace with static mesh
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
double PickupMovementRange = 500; TObjectPtr<UPaperSprite> PickupSprite = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
double PickupMovementSpeed = 1000;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
TObjectPtr<UPaperSprite> WeaponSprite = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties") UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
TObjectPtr<USoundBase> PickupSoundBase = nullptr; TObjectPtr<USoundBase> PickupSoundBase = nullptr;

View File

@ -4,8 +4,10 @@
#include "VampireGameMode.h" #include "VampireGameMode.h"
#include "EnemyCharacter.h" #include "EnemyCharacter.h"
#include "EXPPickup.h"
#include "HealthComponent.h" #include "HealthComponent.h"
#include "ObjectPoolManager.h" #include "ObjectPoolManager.h"
#include "Pickup.h"
#include "PlayerCharacter.h" #include "PlayerCharacter.h"
#include "Projectile.h" #include "Projectile.h"
#include "VampirePlayerController.h" #include "VampirePlayerController.h"
@ -125,6 +127,18 @@ AObjectPoolManager* AVampireGameMode::GetProjectileObjectPoolManager_Implementat
return ProjectileObjectPoolManager; return ProjectileObjectPoolManager;
} }
AObjectPoolManager* AVampireGameMode::GetPickupObjectPoolManager_Implementation()
{
if (PickupObjectPoolManager == nullptr)
{
PickupObjectPoolManager = GetWorld()->SpawnActor<AObjectPoolManager>();
TSubclassOf<AActor> pickupTemplate = PickupTemplate;
PickupObjectPoolManager->InitializeObjectPool(pickupTemplate);
}
return PickupObjectPoolManager;
}
void AVampireGameMode::IncrementEnemyDeathCount() void AVampireGameMode::IncrementEnemyDeathCount()
{ {
EnemyDeathCount++; EnemyDeathCount++;

View File

@ -8,6 +8,7 @@
#include "Interfaces/Pools.h" #include "Interfaces/Pools.h"
#include "VampireGameMode.generated.h" #include "VampireGameMode.generated.h"
class AEXPPickup;
class UEnemyDataAsset; class UEnemyDataAsset;
class AProjectile; class AProjectile;
class AObjectPoolManager; class AObjectPoolManager;
@ -29,6 +30,9 @@ public:
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
TSubclassOf<AProjectile> ProjectileTemplate; TSubclassOf<AProjectile> ProjectileTemplate;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AEXPPickup> PickupTemplate;
FOnEnemyDeathCountIncrementDelegate OnEnemyDeathCountIncrementDelegate; FOnEnemyDeathCountIncrementDelegate OnEnemyDeathCountIncrementDelegate;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
@ -47,6 +51,8 @@ private:
TObjectPtr<AObjectPoolManager> ProjectileObjectPoolManager = nullptr; TObjectPtr<AObjectPoolManager> ProjectileObjectPoolManager = nullptr;
TObjectPtr<AObjectPoolManager> PickupObjectPoolManager = nullptr;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
@ -64,6 +70,8 @@ public:
virtual AObjectPoolManager* GetProjectileObjectPoolManager_Implementation() override; virtual AObjectPoolManager* GetProjectileObjectPoolManager_Implementation() override;
virtual AObjectPoolManager* GetPickupObjectPoolManager_Implementation() override;
protected: protected:
UFUNCTION() UFUNCTION()
void SpawnEnemy(); void SpawnEnemy();