Files
TerracottaWarriors/Plugins/ObjectPool/Source/OBJPool/Private/PooledPawn.cpp

230 lines
8.2 KiB
C++
Raw Normal View History

2025-07-14 22:24:27 +08:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
/// 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(){}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////