Skip to content

NeelFrostrain/ObjectPoolingSubsystem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

6 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ObjectPoolingSubsystem - Advanced Object Pooling Plugin for Unreal Engine

Version: 1.0
Author: NeelFrostrain
Engine Support: Unreal Engine 5.x
License: See LICENSE file


๐Ÿ“š Full Documentation Available in /Documentation Folder

Document Purpose Read Time
INDEX.md Complete documentation index & navigation 5 min
QUICK_START.md Get started in 5 minutes 5 min
HOW_TO_USE.md Step-by-step usage guide 20 min
HOW_IT_WORKS.md Technical architecture & deep dive 40 min
BLUEPRINT_GUIDE_DETAILED.md Complete Blueprint guide 30 min
API_REFERENCE.md Complete API documentation Reference

๐Ÿ‘‰ START HERE: See Documentation/INDEX.md for complete navigation guide!


๐ŸŽฏ What is Object Pooling?

Object pooling is a performance optimization pattern that reuses objects instead of constantly creating and destroying them. Instead of:

Traditional: Spawn โ†’ Use โ†’ Destroy โ†’ [Expensive!]
Pooling:     Spawn Once โ†’ Reuse โ†’ Return โ†’ [Fast!]

Example: 100 Projectiles/Second

Without Pooling:

  • Allocate memory, initialize, add to world
  • Frame rate spike โŒ

With Pooling:

  • Reuse 100 pre-created actors
  • Instant spawn โœ…

โœจ Features

Core Features

  • โœ… World Subsystem Integration - Automatic per-world management
  • โœ… Expandable Pools - Grow when needed (with constraints)
  • โœ… Batch Processing - Spread spawning/destruction over frames
  • โœ… Blueprint Compatible - Full Blueprint & C++ support
  • โœ… Soft Class Loading - Efficient lazy class loading
  • โœ… Lifetime Management - Auto-return after configurable duration
  • โœ… Event System - Customize pool behavior with events
  • โœ… Multiple Pools - Unlimited pools for different actor types

Performance Benefits

  • ๐Ÿš€ Smooth Frame Rate - No GC spikes from allocations
  • ๐Ÿ’พ Memory Efficient - Prevents fragmentation
  • โšก Instant Spawning - O(1) retrieval from pool
  • ๐Ÿ“Š Scalable - Handle hundreds of actors
  • ๐ŸŽฎ Responsive - Better gameplay feel

๐Ÿš€ Quick Start 5 Minutes

Step 1: Install Plugin

1. Copy ObjectPoolingSubsystem/ to YourProject/Plugins/
2. Right-click .uproject โ†’ Generate Visual Studio project files
3. Build and open in Unreal Engine
4. Plugin auto-enables โœ“

Step 2: Create Poolable Actor

C++ Header:

#include "GameFramework/Actor/ObjectPoolingEntry.h"

UCLASS()
class YOURPROJECT_API AMyPooledActor : public AObjectPoolingEntry
{
    GENERATED_BODY()

protected:
    virtual void OnInitializeInPool_Implementation() override;
    virtual void OnSpawnActor_Implementation(float Lifetime, bool bForceReturnToPool) override;
    virtual void OnDespawnActor_Implementation() override;
};

Or Blueprint: Inherit from AObjectPoolingEntry and override events in Blueprint

Step 3: Create Pool

C++ (In Game Mode BeginPlay):

UObjectPooling::SpawnActorsPoolListByClass(
    this,
    AMyPooledActor::StaticClass(),
    100,    // Initial
    300,    // Max
    true,   // Expandable
    0.02f   // Spawn rate
);

Or Blueprint: Call "Spawn Actors Pool List By Class" node in Event BeginPlay

Step 4: Spawn from Pool

C++:

AObjectPoolingEntry* PooledActor = nullptr;
UObjectPooling::SpawnActorFromActorListByClass(
    this,
    AMyPooledActor::StaticClass(),
    FTransform(Location),
    PooledActor,
    nullptr,
    true,   // Auto-return
    5.0f    // 5 second lifetime
);

if (PooledActor)
{
    // Use the actor
}

Or Blueprint: Call "Spawn Actor From Pool" node and check if valid

Done! You now have object pooling working! ๐ŸŽ‰


๐Ÿ—๏ธ System Architecture

High-Level Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     Unreal Engine World                     โ”‚
โ”‚                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  UObjectPooling_Subsystem           โ”‚   โ”‚
โ”‚  โ”‚  (World Subsystem)                  โ”‚   โ”‚
โ”‚  โ”‚                                     โ”‚   โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ Pool Container (TMap)        โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚  Class โ†’ FObjectPoolList     โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚    โ”œโ”€ Actors (Array)         โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚    โ”œโ”€ Size / Max             โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚    โ””โ”€ Expandable (bool)      โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚   โ”‚
โ”‚  โ”‚                                     โ”‚   โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ Spawn Queue (Async)          โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ Destroy Queue (Async)        โ”‚   โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚   โ”‚
โ”‚  โ”‚                                     โ”‚   โ”‚
โ”‚  โ”‚  Timers:                           โ”‚   โ”‚
โ”‚  โ”‚  - TickPoolSpawning (0.02s)         โ”‚   โ”‚
โ”‚  โ”‚  - TickDestroyingActors (0.02s)    โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ AObjectPoolingPlaceholder           โ”‚   โ”‚
โ”‚  โ”‚ (Hidden attachment parent)          โ”‚   โ”‚
โ”‚  โ”‚ Contains pooled actors as children  โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Flow

1. CREATE POOL
   User Request โ†’ Add to Queue โ†’ TickPoolSpawning โ†’ 
   Load Class โ†’ Spawn Batches โ†’ Store in Container

2. SPAWN ACTOR
   User Request โ†’ Search Container โ†’ 
   Found Free โ†’ Activate โ†’ Return Actor
   Not Found โ†’ Expand if allowed โ†’ Return Actor or Null

3. RETURN ACTOR
   Called by User or Timer โ†’ Reset State โ†’ Mark Free โ†’ 
   Hide/Disable โ†’ Attach to Placeholder

4. DESTROY POOL
   User Request โ†’ Add to Destroy Queue โ†’ TickDestroyingActors โ†’ 
   Destroy Batches โ†’ Remove from Container

๐Ÿ”ง Cpp Classes Overview

1. UObjectPooling_Subsystem (Core Manager)

Location: Source/ObjectPoolingSubsystem/Public/Core/ObjectPooling_Subsystem.h

Purpose: Main pool manager for the world

Key Methods:

// Create a pool
virtual void SpawnActorPoolListBySoftClass(
    const TSoftClassPtr<AObjectPoolingEntry> EntryClass,
    int32 SpawnAmount = 10,
    int32 MaxSpawnAmount = 100,
    bool bExtendOnEmpty = false,
    float SpawnTimerRate = 0.01f
);

// Spawn from pool
virtual void SpawnActorFromActorListBySoftClass(
    const TSoftClassPtr<AObjectPoolingEntry> ActorClass,
    AObjectPoolingEntry*& OutActor,
    const FTransform SpawnTransform,
    AActor* NewOwner = nullptr,
    bool bForceReturnAfterLifetimeExpire = false,
    float Lifetime = 10.f
);

// Destroy pool
virtual void DestroyActorListBySoftClass(
    const TSoftClassPtr<AObjectPoolingEntry> ActorClass,
    float DestroyingTimerRate = 0.01f
);

// Query
int32 FindFreeEntryOnContainer(const TSoftClassPtr<AObjectPoolingEntry> EntryKey) const;
const TMap<...>& GetObjectActorPoolContainer() const;

Properties:

int32 SpawnPerBatch = 40;              // Actors/frame during spawn
int32 DestroyPerBatch = 40;            // Actors/frame during destroy

2. AObjectPoolingEntry (Base Actor Class)

Location: Source/ObjectPoolingSubsystem/Public/GameFramework/Actor/ObjectPoolingEntry.h

Purpose: Base class for all poolable actors (MUST inherit from this)

Key Methods:

// Check state
bool IsFreeInPool() const;

// Lifecycle (called automatically)
virtual void InitializeInPool();        // Reset to pool state
virtual void SpawnActor(float Lifetime, bool bForceReturnToPool);  // Activate
virtual void DespawnActor();            // Return to pool

// Override these in your actor
UFUNCTION(BlueprintNativeEvent)
void OnInitializeInPool();              // Pool state setup

UFUNCTION(BlueprintNativeEvent)
void OnSpawnActor(float Lifetime, bool bForceReturnToPool);  // Activate setup

UFUNCTION(BlueprintNativeEvent)
void OnDespawnActor();                  // Cleanup

Properties:

bool bIsFreeInPool;                     // In pool? (true/false)
FTimerHandle TH_ReturnToPool;           // Lifetime timer

3. AObjectPoolingPlaceholder (Container Actor)

Location: Source/ObjectPoolingSubsystem/Public/GameFramework/Actor/ObjectPoolingPlaceholder.h

Purpose: Hidden parent actor for pooled actors while inactive

Features:

  • Invisible billboard component (editor visibility)
  • Keeps pooled actors organized
  • Hidden during gameplay

4. UObjectPooling (Blueprint Function Library)

Location: Source/ObjectPoolingSubsystem/Public/GameFramework/Lib/ObjectPooling.h

Purpose: Convenience wrappers for subsystem functions

Static Functions:

// Wrappers around subsystem
static void SpawnActorsPoolListByClass(...);
static void SpawnActorFromActorListByClass(...);
static void DestroyActorListByClass(...);
static AObjectPoolingPlaceholder* GetObjectPoolingPlaceholder(...);
static void CleanupRedundantPlaceholders(...);

5. Data Structures

FObjectPoolList

struct FObjectPoolList
{
    TArray<TObjectPtr<AObjectPoolingEntry>> ObjectList;  // Pool actors
    int CurrentPoolSize;                                 // Current count
    int MaxSize;                                         // Max allowed
    bool bExpandable;                                    // Can grow
};

FPendingPoolTask

struct FPendingPoolTask
{
    TSoftClassPtr<AObjectPoolingEntry> EntryClass;      // Class to pool
    int32 Remaining;                                     // Actors left to spawn
    int32 MaxSize;                                       // Pool max
    bool bExpandable;                                    // Allow expansion
};

๐Ÿ“ Project Structure

ObjectPoolingSubsystem/
โ”‚
โ”œโ”€โ”€ Documentation/                       โ† โญ START HERE!
โ”‚   โ”œโ”€โ”€ INDEX.md                         โ† Navigation hub
โ”‚   โ”œโ”€โ”€ QUICK_START.md                   โ† 5-min setup
โ”‚   โ”œโ”€โ”€ BLUEPRINT_GUIDE_DETAILED.md      โ† Detailed Blueprint guide
โ”‚   โ”œโ”€โ”€ BLUEPRINT_GUIDE.md               โ† Blueprint overview
โ”‚   โ”œโ”€โ”€ HOW_TO_USE.md                    โ† Complete usage guide
โ”‚   โ”œโ”€โ”€ HOW_IT_WORKS.md                  โ† Technical deep dive
โ”‚   โ”œโ”€โ”€ API_REFERENCE.md                 โ† All functions & classes
โ”‚   โ””โ”€โ”€ FAB_AUDIT_REPORT.md              โ† Marketplace compliance
โ”‚
โ”œโ”€โ”€ Source/ObjectPoolingSubsystem/
โ”‚   โ”œโ”€โ”€ Public/
โ”‚   โ”‚   โ”œโ”€โ”€ Core/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ObjectPooling_Subsystem.h
โ”‚   โ”‚   โ”œโ”€โ”€ GameFramework/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ Actor/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ObjectPoolingEntry.h
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ObjectPoolingPlaceholder.h
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ Lib/
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ ObjectPooling.h
โ”‚   โ”‚   โ”œโ”€โ”€ Structs/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ObjectPoolStruct.h
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ ObjectPoolEnum.h
โ”‚   โ”‚   โ””โ”€โ”€ ObjectPoolingSubsystem.h
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ Private/
โ”‚       โ”œโ”€โ”€ ObjectPoolingSubsystem.cpp
โ”‚       โ”œโ”€โ”€ Core/
โ”‚       โ”‚   โ””โ”€โ”€ ObjectPooling_Subsystem.cpp
โ”‚       โ”œโ”€โ”€ GameFramework/
โ”‚       โ”‚   โ”œโ”€โ”€ Actor/
โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ ObjectPoolingEntry.cpp
โ”‚       โ”‚   โ”‚   โ””โ”€โ”€ ObjectPoolingPlaceholder.cpp
โ”‚       โ”‚   โ””โ”€โ”€ Lib/
โ”‚       โ”‚       โ””โ”€โ”€ ObjectPooling.cpp
โ”‚
โ”œโ”€โ”€ Binaries/                            (Compiled binaries)
โ”œโ”€โ”€ Config/
โ”‚   โ”œโ”€โ”€ DefaultObjectPoolingSubsystem.ini
โ”‚   โ””โ”€โ”€ FilterPlugin.ini                 (FAB marketplace filtering)
โ”œโ”€โ”€ Content/                             (Content - empty)
โ”œโ”€โ”€ Resources/Icon128.png                (Marketplace icon)
โ”œโ”€โ”€ README.md                            (This file - overview)
โ”œโ”€โ”€ LICENSE                              (MIT License)
โ””โ”€โ”€ ObjectPoolingSubsystem.uplugin       (Plugin manifest)

๐Ÿ“š All detailed documentation is in the Documentation/ folder! โ””โ”€โ”€ LICENSE License


๐Ÿ“š Documentation Guide

All detailed documentation is in the Documentation/ folder.
Start here: Documentation/INDEX.md for complete navigation guide!

Which Document Should I Read?

Goal Document Location Time
Get started now QUICK_START.md ๐Ÿ“„ Doc 5 min
Use only Blueprints BLUEPRINT_GUIDE_DETAILED.md ๐Ÿ“„ Doc 30 min
Learn everything step-by-step HOW_TO_USE.md ๐Ÿ“„ Doc 30 min
Understand internals HOW_IT_WORKS.md ๐Ÿ“„ Doc 45 min
Look up specific API API_REFERENCE.md ๐Ÿ“„ Doc Reference
Find any document INDEX.md ๐Ÿ“„ Doc 5 min
FAB Compliance FAB_AUDIT_REPORT.md ๐Ÿ“„ Doc 15 min

Quick Learning Paths by Role

๐Ÿ‘จโ€๐ŸŽฎ Blueprint Designers (30 min):

  1. Documentation/QUICK_START.md - Get working in 5 minutes
  2. Documentation/BLUEPRINT_GUIDE_DETAILED.md - Detailed Blueprint workflow
  3. This README - Understand concepts

๐Ÿ‘จโ€๐Ÿ’ป C++ Programmers (60 min):

  1. Documentation/HOW_TO_USE.md - Learn all patterns
  2. Documentation/HOW_IT_WORKS.md - Understand internals
  3. Documentation/API_REFERENCE.md - Reference specific functions

๐Ÿ‘จโ€๐Ÿซ Technical Leads:

  1. Documentation/FAB_AUDIT_REPORT.md - Compliance verification
  2. Documentation/HOW_IT_WORKS.md - Technical architecture
  3. Documentation/API_REFERENCE.md - API evaluation

๐Ÿ“Š Performance Metrics

Memory Usage (Per Actor)


Base Actor:          ~200-500 bytes
Components:          Variable (mesh, collision, etc)
Pooling Overhead:    Minimal (~1% extra)

Example (500 pooled actors):
500 ร— 1 KB average = ~500 KB fixed
(Compare to: constant allocation/deallocation overhead)

Frame Time Impact

No Pooling (100 actors/frame):


Allocate: 2ms
Initialize: 3ms
Add to World: 1ms
Total: 6ms/frame [SPIKE!]

With Pooling (100 actors/frame):


Retrieve from pool: 0.1ms
Activate: 0.2ms
Total: 0.3ms/frame [SMOOTH!]

Spawn Time Comparison


Scenario: Spawn 1000 projectiles

Without Pooling:      ~100ms spike
With Pooling (40/batch, 0.02s rate):  25 frames (~417ms smooth)


๐ŸŽฎ Common Use Cases

1. Projectiles (Most Common)

// Setup (BeginPlay)
UObjectPooling::SpawnActorsPoolListByClass(
    this, AProjectile::StaticClass(), 100, 300, true, 0.02f
);

// Usage
void AWeapon::Fire(FVector Direction)
{
    AObjectPoolingEntry* ProjPtr = nullptr;
    UObjectPooling::SpawnActorFromActorListByClass(
        this, AProjectile::StaticClass(),
        FTransform(MuzzleLocation), ProjPtr, this
    );
    
    if (AProjectile* Proj = Cast<AProjectile>(ProjPtr))
    {
        Proj->Launch(Direction * 2000.0f);
    }
}

// Return to pool (on hit)
void AProjectile::OnHit(const FHitResult& Hit)
{
    ApplyDamage();
    DespawnActor();  // Back to pool
}

2. Visual Effects

void AGameMode::PlayExplosion(FVector Location)
{
    AObjectPoolingEntry* FXPtr = nullptr;
    UObjectPooling::SpawnActorFromActorListByClass(
        this, AExplosionEffect::StaticClass(),
        FTransform(Location), FXPtr, nullptr,
        true,   // Auto-return
        3.0f    // 3 second lifetime
    );
    // Auto-cleans up after 3 seconds!
}

3. Enemies

void AGameMode::SpawnWave(int32 Count)
{
    for (int i = 0; i < Count; i++)
    {
        AObjectPoolingEntry* EnemyPtr = nullptr;
        UObjectPooling::SpawnActorFromActorListByClass(
            this, AEnemy::StaticClass(),
            FTransform(GetRandomSpawn()), EnemyPtr
        );
        
        if (AEnemy* Enemy = Cast<AEnemy>(EnemyPtr))
        {
            Enemy->Initialize();
        }
    }
}

void AGameMode::OnEnemyDeath(AEnemy* DeadEnemy)
{
    DeadEnemy->DespawnActor();  // Return to pool
}

4. Items/Pickups

void AGameMode::SpawnCoins(FVector Location, int32 Count)
{
    for (int i = 0; i < Count; i++)
    {
        AObjectPoolingEntry* CoinPtr = nullptr;
        FVector CoinLoc = Location + FMath::RandPointInRadius(100.0f);
        
        UObjectPooling::SpawnActorFromActorListByClass(
            this, ACoin::StaticClass(),
            FTransform(CoinLoc), CoinPtr
        );
    }
}

๐Ÿ” Configuration & Tuning

Pool Sizing Strategy

Initial Size = Average concurrent actors used
Max Size = 2-10x initial size (depends on variability)

Examples:
- Stable projectiles:   100 initial, 300 max
- Variable effects:     50 initial, 200 max
- Unpredictable enemies: 30 initial, 150 max

Batch Size Tuning

SpawnPerBatch = 40 (default)
โ”œโ”€ Increase (50-100): Faster pool setup, higher frame spike
โ””โ”€ Decrease (10-30): Slower setup, smoother frame rate

DestroyPerBatch = 40 (default)
โ””โ”€ Recommendations same as SpawnPerBatch

Timer Rate Tuning

SpawnTimerRate = 0.01s (100 Hz, default)
โ”œโ”€ Lower (0.005): Faster but more overhead
โ”œโ”€ Default (0.01): Balanced
โ””โ”€ Higher (0.05): Slower but less overhead

Calculation: Time to spawn N actors = (N / SpawnPerBatch) ร— SpawnTimerRate
Example: 1000 actors at 40/batch, 0.02s = 25 batches ร— 0.02s = 0.5s smooth spread

โ“ Troubleshooting

OutActor is Null After Spawning

Causes:

  1. Pool wasn't created yet
  2. Pool exhausted and not expandable
  3. Actor class failed to load

Solutions:

// Ensure pool created first (in BeginPlay!)
UObjectPooling::SpawnActorsPoolListByClass(this, YourClass, 100, 300, true, 0.02f);

// Check for valid actor
if (PooledActor)
{
    // Use it
}
else
{
    // Pool exhausted - increase size or enable expandable
}

Actors Not Appearing

Cause: OnSpawnActor_Implementation not properly hiding/showing

Solution:

void AMyActor::OnSpawnActor_Implementation(float Lifetime, bool bForceReturnToPool)
{
    // System already called SetActorHiddenInGame(false)
    // Verify visibility
    if (IsHidden())
    {
        SetActorHiddenInGame(false);
    }
}

Frame Rate Spikes During Spawning

Cause: Too many actors created per frame

Solution:

// Reduce batch size
UObjectPooling::SpawnActorsPoolListByClass(
    this, ActorClass, 100, 300, true,
    0.05f  // Slower (2x) โ†’ smoother spawning
);

// OR in Project Settings: Reduce SpawnPerBatch from 40 to 20

Memory Growing Unbounded

Cause: Expandable pool growing without limit

Solution:

UObjectPooling::SpawnActorsPoolListByClass(
    this, ActorClass,
    50,     // Start small
    200,    // Set realistic max
    true,   // Limited expansion
    0.02f
);

โœ… Best Practices

DO โœ“

  • โœ“ Create pools during BeginPlay (not runtime)
  • โœ“ Always check if OutActor is valid before using
  • โœ“ Use auto-return for temporary objects (effects, projectiles)
  • โœ“ Use manual despawn for interactive objects (enemies, items)
  • โœ“ Set realistic max pool sizes
  • โœ“ Monitor frame rate during development
  • โœ“ Clean up pools when levels transition

DON'T โœ—

  • โœ— Create pools during gameplay
  • โœ— Forget null checks on spawned actors
  • โœ— Set unlimited max sizes
  • โœ— Spawn thousands of actors at once
  • โœ— Leave pools uncleaned on level exit
  • โœ— Use pooling for rarely-spawned objects (overthinking)

๐Ÿ“ž Support & Resources

๐Ÿ“š Documentation Files (All in Documentation/ folder)

File Purpose Link
INDEX.md Navigation hub ๐Ÿ“„
QUICK_START.md Get started in 5 minutes ๐Ÿ“„
BLUEPRINT_GUIDE_DETAILED.md Detailed Blueprint guide ๐Ÿ“„
HOW_TO_USE.md Complete usage guide ๐Ÿ“„
HOW_IT_WORKS.md Technical architecture ๐Ÿ“„
API_REFERENCE.md Complete API documentation ๐Ÿ“„
FAB_AUDIT_REPORT.md Marketplace compliance ๐Ÿ“„

โ“ Questions?

  1. Start with: Documentation/INDEX.md for complete navigation
  2. Get started: Documentation/QUICK_START.md (5 minutes)
  3. Learn patterns: Documentation/HOW_TO_USE.md
  4. Reference API: Documentation/API_REFERENCE.md
  5. Troubleshoot: See "Troubleshooting" section in Documentation/HOW_TO_USE.md

๐ŸŽ“ Next Steps

  1. Read: Documentation/QUICK_START.md (5 minutes)
  2. Create: A poolable actor blueprint
  3. Initialize: A pool in BeginPlay
  4. Test: Spawning and returning actors
  5. Implement: Your game mechanics
  6. Monitor: Performance and tune as needed
  7. Reference: Documentation/ for detailed information

๐Ÿ“„ License

Copyright (c) 2026 Neel Frostrain. All Rights Reserved.
See LICENSE file for details.


๐ŸŽ‰ You're Ready

The ObjectPoolingSubsystem is now ready to use. Start with QUICK_START.md and enjoy optimized performance!

Happy pooling! ๐Ÿš€

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Contributors