This commit is contained in:
2025-07-14 22:24:27 +08:00
parent daacc18ecf
commit 4af19ef574
7722 changed files with 72086 additions and 0 deletions

View File

@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2019 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "IOBJPool.h"
#include "OBJPool.h"
#include "OBJPool_Shared.h"
#if WITH_EDITORONLY_DATA
#include "ISettingsModule.h"
#include "ISettingsSection.h"
#include "ISettingsContainer.h"
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define LOCTEXT_NAMESPACE "Synaptech"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FOBJPool : public IOBJPool {
public:
virtual void StartupModule() override {}
virtual void ShutdownModule() override {}
virtual bool SupportsDynamicReloading() override {return false;}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IMPLEMENT_GAME_MODULE(FOBJPool,OBJPool);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,750 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2019 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "OBJPool.h"
#include "OBJPool_Shared.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Object Pool Component Functions
UObjectPool::UObjectPool(const FObjectInitializer &OBJ) : Super(OBJ) {
TemplateClass = APooledActor::StaticClass();
SetComponentTickEnabled(false);
SetActive(true,false);
//
bWantsInitializeComponent = true;
NeverFailDeferredSpawn = false;
KeepOrphanActorsAlive = false;
ReinitializeInstances = true;
InstantiateOnDemand = false;
AutoInitialize = true;
}
void UObjectPool::BeginPlay() {
Super::BeginPlay();
//
if (AutoInitialize) {InitializeObjectPool();}
}
void UObjectPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
else {
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->Spawned) {continue;}
Pool[ID]->Destroy(true,true);
}
}
//
Super::EndPlay(EndPlayReason);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UObjectPool::InitializeObjectPool() {
if (TemplateClass==nullptr) {
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
return;} EmptyObjectPool();
//
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
for (int32 I=0; I<PoolSize; I++) {
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledActor>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
if (ACT) {
ACT->SharedPool = nullptr;
ACT->OwningPool = const_cast<UObjectPool*>(this);
ACT->FinishSpawning(SpawnTransform);
ACT->Initialize();}}
//
FlushObjectPool();
}
void UObjectPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledActor> Template, const int32 SizeOfPool) {
TemplateClass = Template;
PoolSize = SizeOfPool;
//
InitializeObjectPool();
}
void UObjectPool::FlushObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
}
}
void UObjectPool::EmptyObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
} Pool.Empty();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledActor* UObjectPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UObjectPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
//
if (ObjectPool->TemplateClass.Get() != PooledClass) {
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
return nullptr;}
//
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
APooledActor* DeferredSpawn = ObjectPool->GetInactiveObject();
//
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledActor>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
if (DeferredSpawn) {DeferredSpawn->SharedPool = nullptr; DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
DeferredSpawn = ObjectPool->GetSpawnedObject();
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
} ObjectPool->FlushObjectPool();
//
if (DeferredSpawn!=nullptr) {
const APawn* Instigator = Cast<APawn>(WorldContextObject);
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
//
DeferredSpawn->OwningPool = ObjectPool;
DeferredSpawn->SharedPool = nullptr;
DeferredSpawn->SetOwner(Owner);
DeferredSpawn->Initialize();
//
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
SpawnSuccessful = DeferredSpawn->Spawned;
} else {
SpawnSuccessful = false;
DeferredSpawn = ObjectPool->GetSpawnedObject();
} return DeferredSpawn;
}
APooledActor* UObjectPool::FinishDeferredSpawnFromPool(APooledActor* Actor, const bool Reconstruct, const FTransform &SpawnTransform) {
if (IsValid(Actor)&&(!Actor->IsActorInitialized())) {
Actor->FinishSpawning(SpawnTransform);
} if (IsValid(Actor)) {
Actor->FinishSpawnFromPool(Reconstruct,SpawnTransform);
} return Actor;
}
void UObjectPool::ReturnActor(APooledActor* PooledActor) {
if (!GetOwner()->IsValidLowLevelFast()||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
//
if (TemplateClass.Get()==nullptr) {return;}
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
if (!Pool.Contains(PooledActor)) {
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
Pool.Add(PooledActor);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UObjectPool::GetObjectsFromPool(TArray<APooledActor*> &Spawned, TArray<APooledActor*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
}
void UObjectPool::GetSpawnedObjects(TArray<APooledActor*> &Spawned) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
}
void UObjectPool::GetInactiveObjects(TArray<APooledActor*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
}
APooledActor* UObjectPool::GetSpawnedObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
APooledActor* UObjectPool::GetInactiveObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (!Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Pawn Pool Component Functions
UPawnPool::UPawnPool(const FObjectInitializer &OBJ) : Super(OBJ) {
TemplateClass = APooledPawn::StaticClass();
SetComponentTickEnabled(false);
SetActive(true,false);
//
bWantsInitializeComponent = true;
NeverFailDeferredSpawn = false;
KeepOrphanActorsAlive = false;
ReinitializeInstances = true;
InstantiateOnDemand = false;
AutoInitialize = true;
}
void UPawnPool::BeginPlay() {
Super::BeginPlay();
//
if (AutoInitialize) {InitializeObjectPool();}
}
void UPawnPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
else {
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->Spawned) {continue;}
Pool[ID]->Destroy(true,true);
}
}
//
Super::EndPlay(EndPlayReason);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UPawnPool::InitializeObjectPool() {
if (TemplateClass==nullptr) {
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
return;} EmptyObjectPool();
//
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
for (int32 I=0; I<PoolSize; I++) {
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledPawn>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
if (ACT) {
ACT->OwningPool = const_cast<UPawnPool*>(this);
ACT->FinishSpawning(SpawnTransform);
ACT->Initialize();}}
}
void UPawnPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledPawn> Template, const int32 SizeOfPool) {
TemplateClass = Template;
PoolSize = SizeOfPool;
//
InitializeObjectPool();
}
void UPawnPool::FlushObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
}
}
void UPawnPool::EmptyObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (IsValid(Pool[ID])) {Pool[ID]->Destroy(true,true);}
} Pool.Empty();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledPawn* UPawnPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UPawnPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
//
if (ObjectPool->TemplateClass.Get() != PooledClass) {
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
return nullptr;}
//
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
APooledPawn* DeferredSpawn = ObjectPool->GetInactiveObject();
//
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledPawn>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
if (DeferredSpawn) {DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
DeferredSpawn = ObjectPool->GetSpawnedObject();
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
} ObjectPool->FlushObjectPool();
//
if (DeferredSpawn!=nullptr) {
const APawn* Instigator = Cast<APawn>(WorldContextObject);
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
//
DeferredSpawn->OwningPool = ObjectPool;
DeferredSpawn->SetOwner(Owner);
DeferredSpawn->Initialize();
//
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
SpawnSuccessful = DeferredSpawn->Spawned;
} else {
SpawnSuccessful = false;
DeferredSpawn = ObjectPool->GetSpawnedObject();
} return DeferredSpawn;
}
APooledPawn* UPawnPool::FinishDeferredSpawnFromPool(APooledPawn* Pawn, const bool Reconstruct, const FTransform &SpawnTransform) {
if (IsValid(Pawn)&&(!Pawn->IsActorInitialized())) {
Pawn->FinishSpawning(SpawnTransform);
} if (IsValid(Pawn)) {
Pawn->FinishSpawnFromPool(Reconstruct,SpawnTransform);
} return Pawn;
}
void UPawnPool::ReturnActor(APooledPawn* PooledActor) {
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
//
if (TemplateClass.Get()==nullptr) {return;}
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
if (!Pool.Contains(PooledActor)) {
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
Pool.Add(PooledActor);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UPawnPool::GetObjectsFromPool(TArray<APooledPawn*> &Spawned, TArray<APooledPawn*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
}
void UPawnPool::GetSpawnedObjects(TArray<APooledPawn*> &Spawned) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
}
void UPawnPool::GetInactiveObjects(TArray<APooledPawn*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
}
APooledPawn* UPawnPool::GetSpawnedObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
APooledPawn* UPawnPool::GetInactiveObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (!Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Character Pool Component Functions
UCharacterPool::UCharacterPool(const FObjectInitializer &OBJ) : Super(OBJ) {
TemplateClass = APooledCharacter::StaticClass();
SetComponentTickEnabled(false);
SetActive(true,false);
//
bWantsInitializeComponent = true;
NeverFailDeferredSpawn = false;
KeepOrphanActorsAlive = false;
ReinitializeInstances = true;
InstantiateOnDemand = false;
AutoInitialize = true;
}
void UCharacterPool::BeginPlay() {
Super::BeginPlay();
//
if (AutoInitialize) {InitializeObjectPool();}
}
void UCharacterPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
else {
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->Spawned) {continue;}
Pool[ID]->Destroy(true,true);
}
}
//
Super::EndPlay(EndPlayReason);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UCharacterPool::InitializeObjectPool() {
if (TemplateClass==nullptr) {
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
return;} EmptyObjectPool();
//
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
for (int32 I=0; I<PoolSize; I++) {
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledCharacter>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
if (ACT) {
ACT->OwningPool = const_cast<UCharacterPool*>(this);
ACT->FinishSpawning(SpawnTransform);
ACT->Initialize();}}
}
void UCharacterPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledCharacter> Template, const int32 SizeOfPool) {
TemplateClass = Template;
PoolSize = SizeOfPool;
//
InitializeObjectPool();
}
void UCharacterPool::FlushObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
}
}
void UCharacterPool::EmptyObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
} Pool.Empty();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledCharacter* UCharacterPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UCharacterPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
//
if (ObjectPool->TemplateClass.Get() != PooledClass) {
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
return nullptr;}
//
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
APooledCharacter* DeferredSpawn = ObjectPool->GetInactiveObject();
//
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledCharacter>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
if (DeferredSpawn) {DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
DeferredSpawn = ObjectPool->GetSpawnedObject();
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
} ObjectPool->FlushObjectPool();
//
if (DeferredSpawn!=nullptr) {
const APawn* Instigator = Cast<APawn>(WorldContextObject);
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
//
DeferredSpawn->OwningPool = ObjectPool;
DeferredSpawn->SetOwner(Owner);
DeferredSpawn->Initialize();
//
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
SpawnSuccessful = DeferredSpawn->Spawned;
} else {
SpawnSuccessful = false;
DeferredSpawn = ObjectPool->GetSpawnedObject();
} return DeferredSpawn;
}
APooledCharacter* UCharacterPool::FinishDeferredSpawnFromPool(APooledCharacter* Character, const bool Reconstruct, const FTransform &SpawnTransform) {
if (IsValid(Character)&&(!Character->IsActorInitialized())) {
Character->FinishSpawning(SpawnTransform);
} if (IsValid(Character)) {
Character->FinishSpawnFromPool(Reconstruct,SpawnTransform);
} return Character;
}
void UCharacterPool::ReturnActor(APooledCharacter* PooledActor) {
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
//
if (TemplateClass.Get()==nullptr) {return;}
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
if (!Pool.Contains(PooledActor)) {
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
Pool.Add(PooledActor);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UCharacterPool::GetObjectsFromPool(TArray<APooledCharacter*> &Spawned, TArray<APooledCharacter*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
}
void UCharacterPool::GetSpawnedObjects(TArray<APooledCharacter*> &Spawned) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
}
void UCharacterPool::GetInactiveObjects(TArray<APooledCharacter*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
}
APooledCharacter* UCharacterPool::GetSpawnedObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
APooledCharacter* UCharacterPool::GetInactiveObject() const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (!Pool[ID]->Spawned) {return Pool[ID];}}
//
return nullptr;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Shared Object Pool Component Functions
USharedObjectPool::USharedObjectPool(const FObjectInitializer &OBJ) : Super(OBJ) {
SetComponentTickEnabled(false);
SetActive(true,false);
//
bWantsInitializeComponent = true;
NeverFailDeferredSpawn = false;
KeepOrphanActorsAlive = false;
ReinitializeInstances = true;
InstantiateOnDemand = false;
AutoInitialize = true;
}
void USharedObjectPool::PostInitProperties() {
Super::PostInitProperties();
}
void USharedObjectPool::BeginPlay() {
Super::BeginPlay();
//
if (AutoInitialize) {InitializeObjectPool();}
}
void USharedObjectPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
if (!KeepOrphanActorsAlive) {
EmptyObjectPool(APooledActor::StaticClass());
} else {
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (Pool[ID]->Spawned) {continue;}
Pool[ID]->Destroy(true,true);
}
}
//
Super::EndPlay(EndPlayReason);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void USharedObjectPool::InitializeObjectPool() {
if (TemplateClasses.Num()<=0) {
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Classes!"));
return;} EmptyObjectPool(APooledActor::StaticClass());
//
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
TArray<TSubclassOf<APooledActor>>Classes;
TemplateClasses.GenerateKeyArray(Classes);
//
for (const TSubclassOf<APooledActor>Class : Classes) {
if (Class.Get()==nullptr) {continue;}
int32 PoolSize = TemplateClasses.FindRef(Class);
//
for (int32 I=0; I<PoolSize; I++) {
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledActor>(Class,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
if (ACT) {
ACT->OwningPool = nullptr;
ACT->SharedPool = const_cast<USharedObjectPool*>(this);
ACT->FinishSpawning(SpawnTransform);
ACT->Initialize();}}
}
//
FlushObjectPool();
}
void USharedObjectPool::FlushObjectPool() {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
}
}
void USharedObjectPool::EmptyObjectPool(const UClass* Class) {
if (!Pool.IsValidIndex(0)) {return;}
//
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!Pool[ID]->IsA(Class)) {continue;}
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void USharedObjectPool::GetObjectsFromPool(const UClass* Class, TArray<APooledActor*> &Spawned, TArray<APooledActor*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->IsA(Class)) {continue;}
//
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}
}
}
void USharedObjectPool::GetSpawnedObjects(const UClass* Class, TArray<APooledActor*> &Spawned) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->IsA(Class)) {continue;}
//
if (OBJ->Spawned) {Spawned.Add(OBJ);}
}
}
void USharedObjectPool::GetInactiveObjects(const UClass* Class, TArray<APooledActor*> &Inactive) {
for (const auto &OBJ : Pool) {
if (!IsValid(OBJ)) {continue;}
if (!OBJ->IsA(Class)) {continue;}
//
if (!OBJ->Spawned) {Inactive.Add(OBJ);}
}
}
APooledActor* USharedObjectPool::GetSpawnedObject(const UClass* Class) const {
for (int32 ID=0; ID < Pool.Num(); ++ID) {
if (!IsValid(Pool[ID])) {continue;}
if (!Pool[ID]->IsA(Class)) {continue;}
//
if (Pool[ID]->Spawned) {return Pool[ID];}
}
//
return nullptr;
}
APooledActor* USharedObjectPool::GetInactiveObject(const UClass* Class) const {
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
if (!IsValid(Pool[ID])) {continue;}
if (!Pool[ID]->IsA(Class)) {continue;}
//
if (!Pool[ID]->Spawned) {return Pool[ID];}
}
//
return nullptr;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledActor* USharedObjectPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, USharedObjectPool* SharedPool, UClass* Class, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
if (!IsValid(SharedPool)||SharedPool->GetOwner()==nullptr) {
UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),TEXT("Target Shared-Pool is about to be destroyed. Spawn aborted!"));
return nullptr;}
//
//
if (Class==nullptr) {
UE_LOG(LogTemp,Warning,TEXT("{Begin Deferred Spawn from Pool}: Invalid Class."));
return nullptr;}
//
bool IsTemplate = false;
TArray<TSubclassOf<APooledActor>>Classes;
SharedPool->TemplateClasses.GenerateKeyArray(Classes);
//
for (const TSubclassOf<APooledActor>TemplateClass : Classes) {
if (Class==nullptr) {break;}
if (TemplateClass.Get()==nullptr) {continue;}
if (!Class->GetName().Equals(TemplateClass.Get()->GetName())) {continue;}
//
IsTemplate = true;
if (SharedPool->TemplateClasses.FindChecked(TemplateClass)<=0) {
UE_LOG(LogTemp,Warning,TEXT("{%s}:: %s (%s)"),*SharedPool->GetName(),TEXT("Target Class is zero-sized in Target Shared-Pool!"),*Class->GetName());
break;}
} if (!IsTemplate) {
UE_LOG(LogTemp,Warning,TEXT("{%s}:: %s (%s)"),*SharedPool->GetName(),TEXT("This Shared-Pool does NOT implement Target Template Class. Spawn Aborted:"),*Class->GetName());
return nullptr;}
//
//
if (SharedPool->Pool.Num()==0) {SharedPool->InitializeObjectPool();}
APooledActor* DeferredSpawn = SharedPool->GetInactiveObject(Class);
//
if ((DeferredSpawn==nullptr) && SharedPool->InstantiateOnDemand) {
DeferredSpawn = SharedPool->GetWorld()->SpawnActorDeferred<APooledActor>(Class,SpawnTransform,Owner,SharedPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
if (DeferredSpawn) {DeferredSpawn->SharedPool = SharedPool; DeferredSpawn->OwningPool = nullptr; DeferredSpawn->FinishSpawning(SpawnTransform);}
} else if (DeferredSpawn==nullptr && SharedPool->NeverFailDeferredSpawn) {
DeferredSpawn = SharedPool->GetSpawnedObject(Class);
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
} SharedPool->FlushObjectPool();
//
if (DeferredSpawn!=nullptr) {
const APawn* Instigator = Cast<APawn>(WorldContextObject);
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator = ContextActor->GetInstigator();} }
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
//
DeferredSpawn->SharedPool = SharedPool;
DeferredSpawn->OwningPool = nullptr;
DeferredSpawn->SetOwner(Owner);
DeferredSpawn->Initialize();
//
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
SpawnSuccessful = DeferredSpawn->Spawned;
} else {
SpawnSuccessful = false;
DeferredSpawn = SharedPool->GetSpawnedObject(Class);
}
//
return DeferredSpawn;
}
APooledActor* USharedObjectPool::FinishDeferredSpawnFromPool(APooledActor* Actor, const bool Reconstruct, const FTransform &SpawnTransform) {
if (IsValid(Actor)&&(!Actor->IsActorInitialized())) {
Actor->FinishSpawning(SpawnTransform);
} if (IsValid(Actor)) {
Actor->FinishSpawnFromPool(Reconstruct,SpawnTransform);
} return Actor;
}
void USharedObjectPool::ReturnActor(APooledActor* PooledActor) {
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
//
TArray<TSubclassOf<APooledActor>>Classes;
TemplateClasses.GenerateKeyArray(Classes);
//
for (const TSubclassOf<APooledActor>Class : Classes) {
if (Class.Get()==nullptr) {continue;}
//
if (PooledActor->GetClass()->IsChildOf(Class->GetDefaultObject()->GetClass())) {
if (!Pool.Contains(PooledActor)) {
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
Pool.Add(PooledActor);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void LOG_OBJ(const bool Debug,const float Duration, const FColor Color, const FString Message) {
if (!Debug) return; UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),*Message); if (!GEngine) {return;}
GEngine->AddOnScreenDebugMessage(-1,Duration,Color,FString::Printf(TEXT("{Pool}:: %s"),*Message));
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,249 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2017 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PooledActor.h"
#include "OBJPool_Shared.h"
#include "Runtime/Engine/Classes/Particles/ParticleSystemComponent.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledActor::APooledActor(const FObjectInitializer &OBJ) : Super(OBJ) {
InitialLifeSpan = 0.f;
LifeSpanPool = 0.f;
//
SharedPool = nullptr;
OwningPool = nullptr;
}
void APooledActor::PostInitProperties() {
Super::PostInitProperties();
}
void APooledActor::BeginPlay() {
Super::BeginPlay();
}
void APooledActor::EndPlay(const EEndPlayReason::Type EndPlayReason) {
OnPoolBeginPlay.Clear();
OnPoolEndPlay.Clear();
//
Super::EndPlay(EndPlayReason);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void APooledActor::Initialize() {
Spawned = false;
//
SetLifeSpan(0.f);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
SetActorEnableCollision(false);
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
C->SetComponentTickEnabled(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
OwningPool->ReturnActor(const_cast<APooledActor*>(this));
} else if (SharedPool && SharedPool->IsValidLowLevelFast()) {
SharedPool->ReturnActor(const_cast<APooledActor*>(this));
}
}
void APooledActor::SetLifeSpanPool(float InLifespan) {
if (IsValid(this) && HasAuthority() ) {
LifeSpanPool = InLifespan;
//
if (InLifespan>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledActor::ReturnToPool,InLifespan);
} else {GetWorldTimerManager().ClearTimer(LifeSpanHandle);}
}
}
float APooledActor::GetLifeSpanPool() const {
const float CurrentLifespan = GetWorldTimerManager().GetTimerRemaining(LifeSpanHandle);
return (CurrentLifespan!=-1.0f) ? CurrentLifespan : 0.0f;
}
UObjectPool* APooledActor::GetOwningPool() const {
return OwningPool;
}
USharedObjectPool* APooledActor::GetSharedPool() const {
return SharedPool;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void APooledActor::SpawnFromPool(const bool Reconstruct, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform) {
if ((!OwningPool||!OwningPool->IsValidLowLevelFast())&&(!SharedPool||!SharedPool->IsValidLowLevelFast())) {
UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),TEXT("Actor trying to spawn from Pool, but Owning Pool Component is invalid!"));
return;}
//
Spawned = true;
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetCollisionEnabled((ECollisionEnabled::Type)SpawnOptions.CollisionType);
P->SetComponentTickEnabled(SpawnOptions.ActorTickEnabled);
P->SetSimulatePhysics(SpawnOptions.SimulatePhysics);
P->SetVisibility(true,true);
}
}
//
if ((OwningPool && OwningPool->ReinitializeInstances)||(SharedPool && SharedPool->ReinitializeInstances)) {
SetActorLocationAndRotation(SpawnTransform.GetLocation(),SpawnTransform.GetRotation(),false,nullptr,ETeleportType::ResetPhysics);
SetActorEnableCollision(SpawnOptions.EnableCollision);
SetActorTickEnabled(SpawnOptions.ActorTickEnabled);
SetActorScale3D(SpawnTransform.GetScale3D());
}
//
//
SetActorHiddenInGame(false);
}
void APooledActor::FinishSpawnFromPool(const bool Reconstruct, const FTransform &Transform) {
FTransform FinalRootComponentTransform = (RootComponent ? RootComponent->GetComponentTransform() : Transform);
FinalRootComponentTransform.GetLocation().DiagnosticCheckNaN(TEXT("APooledActor::FinishSpawning: FinalRootComponentTransform.GetLocation()"));
FinalRootComponentTransform.GetRotation().DiagnosticCheckNaN(TEXT("APooledActor::FinishSpawning: FinalRootComponentTransform.GetRotation()"));
//
if (GetWorld()) {
FVector AdjustedLocation; FRotator AdjustedRotation;
switch (SpawnCollisionHandlingMethod) {
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} break;
//
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} else {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*AdjustedLocation.ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding:
if (GetWorld()->EncroachingBlockingGeometry(this,GetActorLocation(),GetActorRotation())) {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*GetActorLocation().ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::Undefined:
case ESpawnActorCollisionHandlingMethod::AlwaysSpawn:
default: break;}}
//
//
if (Reconstruct) {
#if WITH_EDITOR
ResetPropertiesForConstruction();
RerunConstructionScripts();
#endif
}
//
if (LifeSpanPool>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledActor::ReturnToPool,LifeSpanPool);
}
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->ActivateSystem(false);}
//
C->SetActive(true);
C->SetComponentTickEnabled(true);
}
//
//
EVENT_OnPoolBeginPlay();
OnPoolBeginPlay.Broadcast();
//
Spawned = true;
}
void APooledActor::ReturnToPool() {
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
C->SetComponentTickEnabled(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
SetActorEnableCollision(false);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
if (OwningPool->ReinitializeInstances) {
GetWorld()->GetTimerManager().ClearTimer(LifeSpanHandle);
} OwningPool->ReturnActor(const_cast<APooledActor*>(this));
//
OnPoolEndPlay.Broadcast();
EVENT_OnPoolEndPlay();
} else if (SharedPool && SharedPool->IsValidLowLevelFast()) {
if (SharedPool->ReinitializeInstances) {
GetWorld()->GetTimerManager().ClearTimer(LifeSpanHandle);
} SharedPool->ReturnActor(const_cast<APooledActor*>(this));
//
OnPoolEndPlay.Broadcast();
EVENT_OnPoolEndPlay();
} else {Destroy(true,true);}
//
Spawned = false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void APooledActor::EVENT_OnPoolBeginPlay_Implementation(){}
void APooledActor::EVENT_OnPoolEndPlay_Implementation(){}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,228 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2017 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PooledCharacter.h"
#include "OBJPool_Shared.h"
#include "Runtime/Engine/Classes/Particles/ParticleSystemComponent.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledCharacter::APooledCharacter(const FObjectInitializer &OBJ) : Super(OBJ) {
LifeSpanPool = 0.f;
}
void APooledCharacter::Initialize() {
Spawned = false;
//
SetLifeSpan(0.f);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
SetActorEnableCollision(false);
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
OwningPool->ReturnActor(const_cast<APooledCharacter*>(this));
}
}
void APooledCharacter::SetLifeSpanPool(float InLifespan) {
if (IsValid(this)) {
LifeSpanPool = InLifespan;
//
if (InLifespan>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledCharacter::ReturnToPool,InLifespan);
} else {GetWorldTimerManager().ClearTimer(LifeSpanHandle);}
}
}
float APooledCharacter::GetLifeSpanPool() const {
const float CurrentLifespan = GetWorldTimerManager().GetTimerRemaining(LifeSpanHandle);
return (CurrentLifespan!=-1.0f) ? CurrentLifespan : 0.0f;
}
void APooledCharacter::BeginPlay() {
Super::BeginPlay();
}
void APooledCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason) {
OnPoolBeginPlay.Clear();
OnPoolEndPlay.Clear();
//
Super::EndPlay(EndPlayReason);
}
void APooledCharacter::SpawnFromPool(const bool Reconstruct, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform) {
if (!OwningPool||!OwningPool->IsValidLowLevelFast()) {
UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),TEXT("Character trying to spawn from Pool, but Owning Pool Component is invalid!"));
return;}
//
Spawned = true;
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetComponentTickEnabled(SpawnOptions.ActorTickEnabled);
P->SetSimulatePhysics(SpawnOptions.SimulatePhysics);
P->SetVisibility(true,true);
}
}
//
if (OwningPool->ReinitializeInstances) {
SetActorLocationAndRotation(SpawnTransform.GetLocation(),SpawnTransform.GetRotation(),false,nullptr,ETeleportType::TeleportPhysics);
SetActorEnableCollision(SpawnOptions.EnableCollision);
SetActorTickEnabled(SpawnOptions.ActorTickEnabled);
SetActorScale3D(SpawnTransform.GetScale3D());
//
FinishSpawnFromPool(Reconstruct,SpawnTransform);
if (!Spawned) {return;}
//
if (LifeSpanPool>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledCharacter::ReturnToPool,LifeSpanPool);
}
}
//
SetActorHiddenInGame(false);
}
void APooledCharacter::FinishSpawnFromPool(const bool Reconstruct, const FTransform &Transform) {
FTransform FinalRootComponentTransform = (RootComponent ? RootComponent->GetComponentTransform() : Transform);
//
FinalRootComponentTransform.GetLocation().DiagnosticCheckNaN(TEXT("APooledCharacter::FinishSpawning: FinalRootComponentTransform.GetLocation()"));
FinalRootComponentTransform.GetRotation().DiagnosticCheckNaN(TEXT("APooledCharacter::FinishSpawning: FinalRootComponentTransform.GetRotation()"));
//
if (GetWorld()) {
FVector AdjustedLocation; FRotator AdjustedRotation;
switch (SpawnCollisionHandlingMethod) {
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} break;
//
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} else {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*AdjustedLocation.ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding:
if (GetWorld()->EncroachingBlockingGeometry(this,GetActorLocation(),GetActorRotation())) {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*GetActorLocation().ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::Undefined:
case ESpawnActorCollisionHandlingMethod::AlwaysSpawn:
default: break;}}
//
if (Reconstruct) {
#if WITH_EDITOR
ResetPropertiesForConstruction();
RerunConstructionScripts();
Reset();
#endif
}
//
if (LifeSpanPool>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledCharacter::ReturnToPool,LifeSpanPool);
}
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->ActivateSystem(false);}
//
C->SetActive(true);
}
//
//
EVENT_OnPoolBeginPlay();
OnPoolBeginPlay.Broadcast();
//
Spawned = true;
}
void APooledCharacter::ReturnToPool() {
Spawned = false;
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
SetActorEnableCollision(false);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
if (OwningPool->ReinitializeInstances) {
GetWorld()->GetTimerManager().ClearTimer(LifeSpanHandle);
} OwningPool->ReturnActor(const_cast<APooledCharacter*>(this));
//
OnPoolEndPlay.Broadcast();
EVENT_OnPoolEndPlay();
} else {Destroy();}
}
UCharacterPool* APooledCharacter::GetOwningPool() const {
return OwningPool;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void APooledCharacter::EVENT_OnPoolBeginPlay_Implementation(){}
void APooledCharacter::EVENT_OnPoolEndPlay_Implementation(){}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,230 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2017 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PooledPawn.h"
#include "OBJPool_Shared.h"
#include "Runtime/Engine/Classes/Particles/ParticleSystemComponent.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
APooledPawn::APooledPawn(const FObjectInitializer &OBJ) : Super(OBJ) {
LifeSpanPool = 0.f;
}
void APooledPawn::Initialize() {
Spawned = false;
//
SetLifeSpan(0.f);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
SetActorEnableCollision(false);
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
C->SetComponentTickEnabled(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
OwningPool->ReturnActor(const_cast<APooledPawn*>(this));
}
}
void APooledPawn::SetLifeSpanPool(float InLifespan) {
if (IsValid(this)) {
LifeSpanPool = InLifespan;
//
if (InLifespan>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledPawn::ReturnToPool,InLifespan);
} else {GetWorldTimerManager().ClearTimer(LifeSpanHandle);}
}
}
float APooledPawn::GetLifeSpanPool() const {
const float CurrentLifespan = GetWorldTimerManager().GetTimerRemaining(LifeSpanHandle);
return (CurrentLifespan!=-1.0f) ? CurrentLifespan : 0.0f;
}
void APooledPawn::BeginPlay() {
Super::BeginPlay();
}
void APooledPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) {
OnPoolBeginPlay.Clear();
OnPoolEndPlay.Clear();
//
Super::EndPlay(EndPlayReason);
}
void APooledPawn::SpawnFromPool(const bool Reconstruct, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform) {
if (!OwningPool||!OwningPool->IsValidLowLevelFast()) {
UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),TEXT("Pawn trying to spawn from Pool, but Owning Pool Component is invalid!"));
return;}
//
Spawned = true;
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetComponentTickEnabled(SpawnOptions.ActorTickEnabled);
P->SetSimulatePhysics(SpawnOptions.SimulatePhysics);
P->SetVisibility(true,true);
}
}
//
if (OwningPool->ReinitializeInstances) {
SetActorLocationAndRotation(SpawnTransform.GetLocation(),SpawnTransform.GetRotation(),false,nullptr,ETeleportType::TeleportPhysics);
SetActorEnableCollision(SpawnOptions.EnableCollision);
SetActorTickEnabled(SpawnOptions.ActorTickEnabled);
SetActorScale3D(SpawnTransform.GetScale3D());
//
FinishSpawnFromPool(Reconstruct,SpawnTransform);
if (!Spawned) {return;}
//
if (LifeSpanPool>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledPawn::ReturnToPool,LifeSpanPool);
}
}
//
SetActorHiddenInGame(false);
}
void APooledPawn::FinishSpawnFromPool(const bool Reconstruct, const FTransform &Transform) {
FTransform FinalRootComponentTransform = (RootComponent ? RootComponent->GetComponentTransform() : Transform);
//
FinalRootComponentTransform.GetLocation().DiagnosticCheckNaN(TEXT("APooledPawn::FinishSpawning: FinalRootComponentTransform.GetLocation()"));
FinalRootComponentTransform.GetRotation().DiagnosticCheckNaN(TEXT("APooledPawn::FinishSpawning: FinalRootComponentTransform.GetRotation()"));
//
if (GetWorld()) {
FVector AdjustedLocation; FRotator AdjustedRotation;
switch (SpawnCollisionHandlingMethod) {
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} break;
//
case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding:
AdjustedLocation = GetActorLocation();
AdjustedRotation = GetActorRotation();
if (GetWorld()->FindTeleportSpot(this,AdjustedLocation,AdjustedRotation)) {
SetActorLocationAndRotation(AdjustedLocation,AdjustedRotation,false,nullptr,ETeleportType::TeleportPhysics);
} else {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*AdjustedLocation.ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding:
if (GetWorld()->EncroachingBlockingGeometry(this,GetActorLocation(),GetActorRotation())) {
UE_LOG(LogTemp,Warning,TEXT("Spawn Actor from Pool: failed because of collision at the spawn location [%s] for [%s]"),*GetActorLocation().ToString(),*GetClass()->GetName());
Initialize();
return;}
break;
//
case ESpawnActorCollisionHandlingMethod::Undefined:
case ESpawnActorCollisionHandlingMethod::AlwaysSpawn:
default: break;}}
//
if (Reconstruct) {
#if WITH_EDITOR
ResetPropertiesForConstruction();
RerunConstructionScripts();
Reset();
#endif
}
//
if (LifeSpanPool>0.0001f) {
GetWorldTimerManager().SetTimer(LifeSpanHandle,this,&APooledPawn::ReturnToPool,LifeSpanPool);
}
//
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->ActivateSystem(false);}
//
C->SetActive(true);
C->SetComponentTickEnabled(true);
}
//
//
EVENT_OnPoolBeginPlay();
OnPoolBeginPlay.Broadcast();
//
Spawned = true;
}
void APooledPawn::ReturnToPool() {
Spawned = false;
//
TInlineComponentArray<UActorComponent*>Components;
GetComponents(Components);
//
for (UActorComponent* C : Components) {
const auto &PS = Cast<UParticleSystemComponent>(C);
if (PS) {PS->DeactivateSystem();}
//
C->SetActive(false);
C->SetComponentTickEnabled(false);
//
const auto &P = Cast<UPrimitiveComponent>(C);
if (P && !P->IsA(UParticleSystemComponent::StaticClass())) {
P->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector);
P->SetPhysicsLinearVelocity(FVector::ZeroVector);
P->SetComponentTickEnabled(false);
P->SetSimulatePhysics(false);
P->SetVisibility(false,true);
}
}
//
SetActorEnableCollision(false);
SetActorHiddenInGame(true);
SetActorTickEnabled(false);
//
if (OwningPool && OwningPool->IsValidLowLevelFast()) {
if (OwningPool->ReinitializeInstances) {
GetWorld()->GetTimerManager().ClearTimer(LifeSpanHandle);
} OwningPool->ReturnActor(const_cast<APooledPawn*>(this));
//
OnPoolEndPlay.Broadcast();
EVENT_OnPoolEndPlay();
} else {Destroy();}
}
UPawnPool* APooledPawn::GetOwningPool() const {
return OwningPool;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void APooledPawn::EVENT_OnPoolBeginPlay_Implementation(){}
void APooledPawn::EVENT_OnPoolEndPlay_Implementation(){}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,135 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2019 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PooledProjectile.h"
#include "OBJPool_Shared.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UPooledProjectile::UPooledProjectile(const FObjectInitializer& OBJ) : Super(OBJ) {
Movement = nullptr;
//
Direction = FVector::ForwardVector;
InitialSpeed = 3000.0f;
MaxSpeed = 3000.0f;
//
Friction = 0.2f;
Bounciness = 0.6f;
ForceSubStepping = false;
MaxSimulationIterations = 8;
ProjectileGravityScale = 1.f;
UpdateOnlyIfRendered = false;
MaxSimulationTimeStep = 0.05f;
HomingAccelerationMagnitude = 0.f;
InitialVelocityInLocalSpace = true;
BounceAngleAffectsFriction = false;
BounceVelocityStopSimulatingThreshold = 5.f;
}
void UPooledProjectile::PostInitProperties() {
Super::PostInitProperties();
//
AOwner = Cast<APooledActor>(GetOwner());
POwner = Cast<APooledPawn>(GetOwner());
if ((!AOwner)&&(!POwner)) {return;}
//
if (AOwner) {
AOwner->OnPoolBeginPlay.AddDynamic(this,&UPooledProjectile::Shoot);
AOwner->OnPoolEndPlay.AddDynamic(this,&UPooledProjectile::Break);
} else if (POwner) {
POwner->OnPoolBeginPlay.AddDynamic(this,&UPooledProjectile::Shoot);
POwner->OnPoolEndPlay.AddDynamic(this,&UPooledProjectile::Break);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UPooledProjectile::Shoot_Implementation() {
if (!Primitive) {
AOwner = Cast<APooledActor>(GetOwner());
POwner = Cast<APooledPawn>(GetOwner());
//
if (AOwner) {Primitive=Cast<UPrimitiveComponent>(AOwner->GetRootComponent());} else
if (POwner) {Primitive=Cast<UPrimitiveComponent>(POwner->GetRootComponent());}
}
//
if (((!AOwner)&&(!POwner))||!Primitive) {
UE_LOG(LogTemp,Error,TEXT("{Pool}:: %s"),TEXT("Pooled Projectile Components are meant to be used by ''Pooled Actor'' Class... but casting have failed or Owning Pool Component is invalid!"));
return;}
//
if (Direction==FVector::ZeroVector) {Direction = FVector::ForwardVector;}
//
if (Movement) {
Movement->StopSimulating(FHitResult());
Movement->DestroyComponent();
Movement = nullptr;}
//
if (AOwner) {Movement=NewObject<UProjectileMovementComponent>(AOwner);} else
if (POwner) {Movement=NewObject<UProjectileMovementComponent>(POwner);}
//
if (Movement) {
Movement->BounceVelocityStopSimulatingThreshold = BounceVelocityStopSimulatingThreshold;
Movement->bInitialVelocityInLocalSpace = InitialVelocityInLocalSpace;
Movement->HomingAccelerationMagnitude = HomingAccelerationMagnitude;
Movement->bBounceAngleAffectsFriction = BounceAngleAffectsFriction;
Movement->bRotationFollowsVelocity = RotationFollowsVelocity;
Movement->MaxSimulationIterations = MaxSimulationIterations;
Movement->ProjectileGravityScale = ProjectileGravityScale;
Movement->HomingTargetComponent = HomingTargetComponent;
Movement->MaxSimulationTimeStep = MaxSimulationTimeStep;
Movement->bUpdateOnlyIfRendered = UpdateOnlyIfRendered;
Movement->bIsHomingProjectile = IsHomingProjectile;
Movement->bForceSubStepping = ForceSubStepping;
Movement->bShouldBounce = ShouldBounce;
Movement->InitialSpeed = InitialSpeed;
Movement->Bounciness = Bounciness;
Movement->Velocity = Direction;
Movement->Friction = Friction;
Movement->MaxSpeed = MaxSpeed;
//
if (HomingTarget && HomingTarget->GetRootComponent()) {
Movement->HomingTargetComponent = HomingTarget->GetRootComponent();
} Movement->RegisterComponent();
//
Movement->OnProjectileStop.AddDynamic(this,&UPooledProjectile::ProjectileStop);
Movement->OnProjectileBounce.AddDynamic(this,&UPooledProjectile::ProjectileBounce);
}
}
void UPooledProjectile::Break_Implementation() {
if (IsValid(AOwner)) {
if ((!Primitive||!Movement)) {return;}
} else if (IsValid(POwner)) {
if ((!Primitive||!Movement)) {return;}
} else {return;}
//
Primitive->SetPhysicsLinearVelocity(FVector::ZeroVector);
//
if (Movement) {
Movement->OnProjectileStop.Clear();
Movement->OnProjectileBounce.Clear();
Movement->StopSimulating(FHitResult());
Movement->DestroyComponent();
}
}
void UPooledProjectile::ProjectileBounce(const FHitResult &HitResult, const FVector &Velocity) {
OnProjectileBounce.Broadcast(HitResult,Velocity);
}
void UPooledProjectile::ProjectileStop(const FHitResult &HitResult) {
OnProjectileStop.Broadcast(HitResult);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UProjectileMovementComponent* UPooledProjectile::GetMovementComponent() const {
return Movement;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// Copyright 2019 (C) Bruno Xavier B. Leite
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PooledSplineProjectile.h"
#include "OBJPool_Shared.h"
#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UPooledSplineProjectile::UPooledSplineProjectile() {
PrimaryComponentTick.bCanEverTick = true;
bWantsInitializeComponent = true;
SetComponentTickEnabled(true);
//
PathDistance = 0.f;
PathWidth = 10.f;
Speed = 2.f;
//
IgnoredActorsOnCollisionQuery = TArray<AActor*>();
CollisionQueryDebugMode = EDrawDebugTrace::ForDuration;
PathCollisionQueryTypes = TArray<TEnumAsByte<EObjectTypeQuery>>();
//
PathCollisionQueryTypes.Add(EObjectTypeQuery::ObjectTypeQuery1);
PathCollisionQueryTypes.Add(EObjectTypeQuery::ObjectTypeQuery2);
}
void UPooledSplineProjectile::PostInitProperties() {
Super::PostInitProperties();
//
AOwner = Cast<APooledActor>(GetOwner());
POwner = Cast<APooledPawn>(GetOwner());
//
if ((!AOwner)&&(!POwner)) {return;}
//
if (AOwner) {
AOwner->OnPoolEndPlay.AddDynamic(this,&UPooledSplineProjectile::Break);
AOwner->OnPoolBeginPlay.AddDynamic(this,&UPooledSplineProjectile::Shoot);
} else if (POwner) {
POwner->OnPoolEndPlay.AddDynamic(this,&UPooledSplineProjectile::Break);
POwner->OnPoolBeginPlay.AddDynamic(this,&UPooledSplineProjectile::Shoot);
}
//
if (!Primitive) {
AOwner = Cast<APooledActor>(GetOwner());
POwner = Cast<APooledPawn>(GetOwner());
//
if (AOwner) {Primitive=Cast<UPrimitiveComponent>(AOwner->GetRootComponent());} else
if (POwner) {Primitive=Cast<UPrimitiveComponent>(POwner->GetRootComponent());}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UPooledSplineProjectile::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) {
Super::TickComponent(DeltaTime,TickType,ThisTickFunction);
if (!SplineComponent||!Primitive) {return;}
//
//
PathDistance += (DeltaTime * Speed);
float SplineLength = SplineComponent->GetSplineLength();
float PathLocation = FMath::Lerp<float>(0.f,SplineLength,PathDistance);
//
FRotator SplineRotation = SplineComponent->GetRotationAtDistanceAlongSpline(PathLocation,ESplineCoordinateSpace::World);
FVector SplineLocation = SplineComponent->GetLocationAtDistanceAlongSpline(PathLocation,ESplineCoordinateSpace::World);
Primitive->SetWorldLocationAndRotation(SplineLocation,SplineRotation);
//
{///
const FVector TraceStart = SplineLocation;
const FVector TraceEnd = SplineLocation + FVector(KINDA_SMALL_NUMBER,KINDA_SMALL_NUMBER,KINDA_SMALL_NUMBER);
//
const bool Hit = UKismetSystemLibrary::SphereTraceSingleForObjects(
Primitive,
TraceStart,
TraceEnd,
PathWidth,
PathCollisionQueryTypes,
true,
IgnoredActorsOnCollisionQuery,
CollisionQueryDebugMode,
HitResult,
true,
FLinearColor::Yellow,
FLinearColor::Green,
1.f
);
//
if (Hit) {
OnProjectileHit.Broadcast(HitResult);
SetComponentTickEnabled(false);
//
if (AOwner) {AOwner->ReturnToPool();} else
if (POwner) {POwner->ReturnToPool();}
}
}
//
if (PathLocation >= SplineLength) {
if (AOwner) {AOwner->ReturnToPool();} else
if (POwner) {POwner->ReturnToPool();}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UPooledSplineProjectile::Shoot_Implementation() {
if (!SplineComponent) {
UE_LOG(LogTemp,Error,TEXT("{Pool}:: %s"),TEXT("Pooled Spline Projectile Components need a target Spline Component to follow. Spline path not found!"));
return;}
//
if (!Primitive) {
UE_LOG(LogTemp,Error,TEXT("{Pool}:: %s"),TEXT("Pooled Spline Projectile Components need a parent Primitive Component as root. Root Component not found!"));
return;}
//
PathDistance = 0.f;
SetComponentTickEnabled(true);
}
void UPooledSplineProjectile::Break_Implementation() {
SetComponentTickEnabled(false);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
USplineComponent* UPooledSplineProjectile::GetSplineComponent() const {
return SplineComponent;
}
void UPooledSplineProjectile::SetSplineComponent(USplineComponent* Target) {
SplineComponent = Target;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////