Skip to content

Sharashino/Unity-Object-Pool-Solution

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Robust Unity Object Pooling Solution

Overview

The Object Pooling system provides a high-performance solution for managing frequently instantiated and destroyed objects in Unity. It pre-allocates objects during initialization and reuses them throughout the game lifecycle, eliminating costly instantiation/destruction operations that cause performance spikes and garbage collection overhead.

Key Features:

  • Asynchronous initialization with warm-up support
  • Type-safe generic pooling (GameObject, ParticleSystem, AudioSource, custom components)
  • Addressables and Resources integration
  • Additive scene support with dynamic reparenting
  • Auto-growth with configurable limits
  • Specialized VFX/SFX convenience methods with auto-return

Use Cases

Visual Effects (VFX)

When to Use:

  • Particle systems (explosions, hits, trails, muzzle flashes)
  • Recurring effects spawned multiple times per second
  • Effects with predictable lifetimes

Benefits:

  • Eliminates instantiation hitches during combat
  • Prevents GC spikes from destroyed particle systems
  • Auto-returns to pool after particle duration

Example:

// Get VFX from pool (auto-returns after particle duration)
var explosion = poolManager.GetVFX("ExplosionVFX", hitPosition, Quaternion.identity);

Sound Effects (SFX)

When to Use:

  • One-shot audio clips (UI clicks, footsteps, gunshots)
  • Spatial 3D audio sources
  • Multiple simultaneous sounds

Benefits:

  • Prevents audio source exhaustion
  • Reduces overhead from AudioSource component creation
  • Auto-cleanup after playback

Example:

// Play SFX with auto-return after 2 seconds
poolManager.PlaySFX("GunfireSFX", gunfireClip, volume: 0.8f, delayReturn: 2f);

Projectiles & Gameplay Objects

When to Use:

  • Bullets, arrows, grenades
  • Enemy spawners with wave-based systems
  • Collectibles (coins, pickups)

Example:

// Get bullet from pool
var bullet = poolManager.Get<Bullet>("BulletPool");
if (bullet != null)
{
    bullet.transform.position = barrelPosition;
    bullet.Launch(direction, speed);
}

// Later, return to pool
poolManager.Return("BulletPool", bullet);

UI Elements

When to Use:

  • Damage numbers, floating text
  • Inventory item icons
  • Dynamic lists with frequent updates

Setting Up Poolable Objects

Option 1: Using IPoolable Interface (Recommended)

Implement IPoolable for custom initialization/cleanup logic:

using PoolSolution.Interfaces;
using UnityEngine;

public class Bullet : MonoBehaviour, IPoolable
{
    private Rigidbody rb;

    public GameObject PoolableObject => gameObject;

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    // Called when object is retrieved from pool
    public void GetFromPool()
    {
        gameObject.SetActive(true);
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
    }

    // Called when object is returned to pool
    public void ReturnToPool()
    {
        rb.velocity = Vector3.zero;
        gameObject.SetActive(false);
    }

    public void Launch(Vector3 direction, float speed)
    {
        rb.AddForce(direction * speed, ForceMode.Impulse);
    }
}

Unity Setup:

  1. Create prefab (e.g., Bullet.prefab)
  2. Attach your IPoolable script
  3. Configure components (Rigidbody, Collider, etc.)
  4. Add to Addressables or place in Resources folder

Option 2: Standard GameObjects (No Interface)

For prefabs without IPoolable, the pool handles basic activation/deactivation:

Unity Setup:

  1. Create prefab (e.g., CoinPickup.prefab)
  2. Add required components (MeshRenderer, Collider, etc.)
  3. Add to Addressables or Resources folder

The pool automatically:

  • Activates GameObject on Get()
  • Deactivates and resets transform on Return()

Option 3: VFX-Specific (ParticleSystem)

Unity Setup:

  1. Create prefab with ParticleSystem component
  2. Configure particle settings (duration, emission, etc.)
  3. Set Stop Action to "Disable" (prevents auto-destruction)
  4. Add to Addressables with PoolType.VFX

The pool automatically:

  • Plays particles on GetVFX()
  • Stops and clears particles on return
  • Auto-returns after ParticleSystem.main.duration

Option 4: SFX-Specific (AudioSource)

Unity Setup:

  1. Create empty GameObject with AudioSource component
  2. Add PoolableAudioSource component (required for pooling)
  3. Configure AudioSource settings (spatial blend, min/max distance)
  4. Leave clip empty (assigned at runtime)
  5. Add to Addressables with PoolType.SFX

The pool automatically:

  • Wraps AudioSource in PoolableAudioSource component
  • Assigns clip and plays on PlaySFX()
  • Stops and clears clip on return
  • Auto-returns after specified delay

Important: All pooled AudioSource prefabs MUST have the PoolableAudioSource component attached.


Setting Up Pool Database

Step 1: Create Pool Database Asset

  1. Right-click in Project window
  2. Navigate to Create > Optimization > Pooling > Pool Database
  3. Name it (e.g., MainPoolDatabase)

Step 2: Configure Pool Entries

In the PoolDatabase inspector, add pool configurations:

Example 1: Bullet Pool

Key: "BulletPool"
Initial Size: 50
Max Growth Size: 100
Allow Growth: ✓
Prefab Address: "Prefabs/Gameplay/Bullet" (Addressables path)
Prefab Reference: [Leave empty if using Addressables]
Parent: [Optional - Transform for pooled objects]
Type: Object

Example 2: Explosion VFX Pool

Key: "ExplosionVFX"
Initial Size: 10
Max Growth Size: 20
Allow Growth: ✓
Prefab Address: "VFX/Particles/Explosion"
Type: VFX

Example 3: Gunfire SFX Pool

Key: "GunfireSFX"
Initial Size: 5
Max Growth Size: 10
Allow Growth: ✓
Prefab Address: "Audio/Sources/GenericAudioSource"
Type: SFX

Step 3: Setup ObjectPoolManager in Scene

  1. Create empty GameObject named PoolManager
  2. Add ObjectPoolManager component
  3. Assign your PoolDatabase asset
  4. (Optional) Assign Default Parent transform
ObjectPoolManager
├─ Pool Database: MainPoolDatabase
└─ Default Parent: [Optional Transform]

Step 4: Using Pools in Code

Access via Direct Reference

using PoolSolution.Runtime;
using UnityEngine;

public class WeaponController : MonoBehaviour
{
    [SerializeField] private ObjectPoolManager poolManager;

    public void Fire()
    {
        var bullet = poolManager.Get<Bullet>("BulletPool");
        bullet.transform.position = barrelTransform.position;
        bullet.Launch(transform.forward, bulletSpeed);
    }
}

Access via IPoolService (DI/Service Locator)

using _Pawnshop.Optimization.Pooling;

public class VFXSpawner : MonoBehaviour
{
    private IPoolService poolService;

    private void Awake()
    {
        poolService = FindObjectOfType<PoolServiceWrapper>();
    }

    public void SpawnHitEffect(Vector3 position)
    {
        poolService.GetVFX("HitVFX", position, Quaternion.identity);
    }
}

Configuration Reference

PoolConfig Parameters

Parameter Type Description
key string Unique identifier for pool lookup
initialSize int Objects pre-allocated during warm-up
maxGrowthSize int Maximum total objects (0 = unlimited)
allowGrowth bool Allow dynamic creation when pool exhausted
prefabAddress string Addressables key or Resources path
prefabReference GameObject Direct prefab reference (overrides address)
parent Transform Parent transform for pooled objects
type PoolType Object/VFX/SFX (enables specialized behavior)

Best Practices

  1. Warm-up pools during loading screens - Initialize pools asynchronously before gameplay
  2. Size pools appropriately - Monitor pool exhaustion logs and adjust sizes
  3. Use Addressables for large assets - Reduces memory footprint during build
  4. Implement IPoolable for complex objects - Custom reset logic prevents state leaks
  5. Avoid holding pool references - Always return objects when done
  6. Use type-specific pools - VFX/SFX types enable auto-return and cleanup

Advanced: Additive Scene Support

Multi-Scene Architecture

The pooling system is designed for projects using additive scenes (e.g., GameBrain + GameWorld):

Scene Structure:

GameBrain (Manager Scene)
├── ObjectPoolManager
│   ├── AudioSourcePool_Parent
│   │   └── AudioSource_Pool0 (lives in GameBrain)
│   └── BulletPool_Parent
│       └── Bullet_Pool0 (lives in GameBrain)

GameWorld (Content Scene)
└── Level geometry, environment

Key Features:

  • Pooled objects are explicitly moved to ObjectPoolManager's scene (GameBrain)
  • Pools persist when GameWorld unloads/reloads
  • No cross-scene parenting issues
  • Clean separation: managers in GameBrain, pools in GameBrain, content in GameWorld

How It Works:

  1. ObjectPoolManager lives in GameBrain scene
  2. When creating pooled objects, system calls SceneManager.MoveGameObjectToScene()
  3. All pooled objects move to GameBrain scene automatically
  4. Parents are created as children of ObjectPoolManager in GameBrain

This ensures pools survive level transitions and scene reloads.


Troubleshooting

Pool exhausted warnings:

  • Increase initialSize or maxGrowthSize
  • Enable allowGrowth
  • Check if objects are being returned properly

Null references when getting objects:

  • Verify prefab address/path is correct
  • Check Addressables build includes the asset
  • Ensure PoolDatabase is assigned to ObjectPoolManager

Objects not resetting properly:

  • Implement IPoolable interface
  • Override ReturnToPool() to reset custom state

API Reference

ObjectPoolManager

// Generic get/return
T Get<T>(string key) where T : class
void Return<T>(string key, T item) where T : class

// VFX convenience (auto-return after duration)
ParticleSystem GetVFX(string key, Vector3 position, Quaternion rotation)

// SFX convenience (auto-return after delay)
AudioSource PlaySFX(string key, AudioClip clip, float volume = 1f, float delayReturn = 2f)

IPoolable Interface

GameObject PoolableObject { get; }
void GetFromPool();     // Called when retrieved from pool
void ReturnToPool();    // Called when returned to pool

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages