code
This commit is contained in:
41
Plugins/ObjectPool/Source/OBJPool/Private/IOBJPool.cpp
Normal file
41
Plugins/ObjectPool/Source/OBJPool/Private/IOBJPool.cpp
Normal 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);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
750
Plugins/ObjectPool/Source/OBJPool/Private/OBJPool.cpp
Normal file
750
Plugins/ObjectPool/Source/OBJPool/Private/OBJPool.cpp
Normal 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));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
249
Plugins/ObjectPool/Source/OBJPool/Private/PooledActor.cpp
Normal file
249
Plugins/ObjectPool/Source/OBJPool/Private/PooledActor.cpp
Normal 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(){}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
228
Plugins/ObjectPool/Source/OBJPool/Private/PooledCharacter.cpp
Normal file
228
Plugins/ObjectPool/Source/OBJPool/Private/PooledCharacter.cpp
Normal 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(){}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
230
Plugins/ObjectPool/Source/OBJPool/Private/PooledPawn.cpp
Normal file
230
Plugins/ObjectPool/Source/OBJPool/Private/PooledPawn.cpp
Normal 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(){}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
135
Plugins/ObjectPool/Source/OBJPool/Private/PooledProjectile.cpp
Normal file
135
Plugins/ObjectPool/Source/OBJPool/Private/PooledProjectile.cpp
Normal 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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
@ -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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
Reference in New Issue
Block a user