Come funziona il pooling in Unity

In Unity, esistono funzioni come Instantiate e Destroy per creare e distruggere gli oggetti nel gioco. Tuttavia, queste operazioni possono essere costose, specialmente se vengono eseguite molto spesso durante il gameplay. Immagina di star giocando a uno sparatutto, dove continuamente tutti i giocatori sparano contro altri nemici infiniti proiettili… sarebbe un continuo “Instantiate’n’Destroy”!
In situazioni del genere, dove bisogna creare e distruggere frequentemente oggetti, soprattutto quando si tratta dello sviluppo di videogiochi e la gestione delle risorse è fondamentale, si usa l’algoritmo di pooling.
Il pooling (da pool, “piscina di oggetti”) viene utilizzato quando vi è la necessità di gestire diversi oggetti che sono sempre gli stessi. In fase di inizializzazione dell’applicazione, l’algoritmo genera un certo numero di oggetti, che vengono attivati e disattivati quando necessario, utilizzando sempre le stesse risorse.
Implementazione del pooling
Creiamo la classe ObjectPoolingManager per gestire il pool di oggetti. Dapprima, viene istanziato un numero predefinito di oggetti e riutilizzati quando necessario. Il metodo GetPooledObject restituisce un oggetto disattivato nel pool quando richiesto.
public class ObjectPoolingManager : MonoBehaviour
{
// Dichiarazione di variabili pubbliche
public static ObjectPoolingManager instance; // Riferimento statico a se stesso per l'accesso globale
public GameObject pooledObject; // Il tipo di oggetto da poolare
public int pooledAmount = 10; // Il numero iniziale di oggetti da poolare
// Lista di oggetti poolati
private List<GameObject> pooledObjects;
// Metodo chiamato quando l'oggetto viene inizializzato
private void Awake()
{
// Verifica se c'è già un'istanza di ObjectPoolingManager
if (instance == null)
instance = this; // Se non c'è, imposta questa istanza come l'istanza singleton
else
Destroy(gameObject); // Se c'è già un'istanza, distruggi questo oggetto per evitare duplicati
}
// Metodo chiamato all'avvio
void Start()
{
pooledObjects = new List<GameObject>(); // Inizializza la lista di oggetti poolati
// Loop per creare e inizializzare gli oggetti poolati
for (int i = 0; i < pooledAmount; i++)
{
GameObject obj = Instantiate(pooledObject); // Crea un nuovo oggetto dal prefab specificato
obj.SetActive(false); // Disattiva l'oggetto appena creato
pooledObjects.Add(obj); // Aggiunge l'oggetto alla lista di oggetti poolati
}
}
// Metodo per ottenere un oggetto poolato disponibile
public GameObject GetPooledObject()
{
// Loop attraverso gli oggetti poolati
for (int i = 0; i < pooledObjects.Count; i++)
{
// Verifica se l'oggetto non è attivo nell'attuale gerarchia
if (!pooledObjects[i].activeInHierarchy)
{
return pooledObjects[i]; // Se trovato, restituisci l'oggetto
}
}
return null; // Se non ci sono oggetti disponibili, restituisci null
}
}
Utilizzo del pooling
Vediamo ora come sfruttare il pooling manager per “spawnare”1 oggetti ogni volta che vogliamo:
public class ObjectSpawner : MonoBehaviour
{
public float spawnRate = 1f; // Frequenza di spawn degli oggetti
public float despawnTime = 5f; // Tempo prima che gli oggetti spawnati vengano disattivati
void Start()
{
StartCoroutine(SpawnObjects()); // Avvia la coroutine per lo spawn degli oggetti
}
// Coroutine per lo spawn degli oggetti
IEnumerator SpawnObjects()
{
while (true) // Loop infinito per continuare lo spawn degli oggetti
{
yield return new WaitForSeconds(spawnRate); // Attendere per la durata della frequenza di spawn
GameObject obj = ObjectPoolingManager.instance.GetPooledObject(); // Ottiene il primo oggetto disponibile (non ancora attivato) dal pooling
if (obj != null) // Se è stato ottenuto un oggetto valido
{
obj.transform.position = transform.position; // Imposta la posizione dell'oggetto sulla posizione dello spawn
obj.SetActive(true); // Attiva l'oggetto
StartCoroutine(DeactivateObject(obj)); // Avvia la coroutine per disattivare l'oggetto dopo un certo periodo di tempo
}
}
}
// Coroutine per disattivare un oggetto dopo un certo periodo di tempo
IEnumerator DeactivateObject(GameObject obj)
{
yield return new WaitForSeconds(despawnTime); // Attendere per il tempo di disattivazione
obj.SetActive(false); // Disattiva l'oggetto
}
}
In sintesi, l’algoritmo di pooling permette di:
- ridurre l’utilizzo della memoria: evita il “Instantiate’n’Destroy” continuo di oggetti in gioco, risparmiando risorse di memoria;
- migliorare le prestazioni e la stabilità: elimina il ritardo causato dalla creazione dinamica degli oggetti durante il gioco.
Esempio di Pooling in Unity
🔗 Leggi anche:
- Ottimizzazione per Realtà Virtuale in Unity
- Videogaming in Unity
- Creare un Proiettile in Unity
- [Burst Compiler e Job in Unity](/gaming/burst compiler-job-in-unity/)
Quando si parla di “spawnare” un oggetto in un gioco, si intende il processo di istanziazione di quell’oggetto all’interno del mondo virtuale del gioco. ↩︎










