ObjectPool di Unity
Fa parte della sezione Architettura dei giochi in Unity del percorso Unity di Coddy. Lezione 48 di 64.
Unity include un pool, ObjectPool<T> in UnityEngine.Pool. Gli dici cosa fare a ogni passaggio con quattro lambda, e il pool conserva gli elementi di riserva e i conteggi. Questo camino emette una nuvola di fumo ogni 0.2 secondi e ogni nuvola torna dopo un secondo:
using UnityEngine;
using UnityEngine.Pool;
public class Chimney : MonoBehaviour
{
public Puff puffPrefab;
private ObjectPool<Puff> pool;
private float timer;
void Awake()
{
pool = new ObjectPool<Puff>(
createFunc: () => Instantiate(puffPrefab),
actionOnGet: puff => puff.gameObject.SetActive(true),
actionOnRelease: puff => puff.gameObject.SetActive(false),
actionOnDestroy: puff => Destroy(puff.gameObject),
collectionCheck: true,
defaultCapacity: 10,
maxSize: 20);
}
void Update()
{
timer += Time.deltaTime;
if (timer >= 0.2f)
{
timer = 0f;
Puff puff = pool.Get();
puff.transform.position = transform.position + Vector3.up;
puff.Launch(pool);
}
}
}// Puff.cs
private IObjectPool<Puff> pool;
private float age;
public void Launch(IObjectPool<Puff> owner)
{
pool = owner;
age = 0f;
}
void Update()
{
transform.Translate(0f, Time.deltaTime, 0f);
age += Time.deltaTime;
if (age >= 1f) pool.Release(this);
}createFunc viene eseguita quando Get trova il pool vuoto; actionOnGet viene eseguita a ogni Get e actionOnRelease a ogni Release. Quando una nuvola viene rilasciata mentre nel pool sono già in attesa maxSize elementi di riserva, il pool non la conserva: actionOnDestroy la distrugge. defaultCapacity è solo la capacità iniziale dell'elenco del pool, quindi non viene creato nulla in anticipo. CountAll conta le nuvole create dal pool e ancora possedute, CountActive quelle presenti nel gioco e CountInactive quelle di riserva. Get ha attivato la nuvola prima che il camino la posizioni, il che va bene in questo caso perché Puff non ha un OnEnable che legga la sua posizione. La nuvola conserva il pool come IObjectPool<Puff>, l'interfaccia implementata da ogni pool Unity, e Launch azzera la sua età a ogni utilizzo.
Con collectionCheck attivo, rilasciare una nuvola che si trova già nel pool genera un'eccezione InvalidOperationException: Trying to release an object that has already been released to the pool. Il controllo viene eseguito solo nell'Editor, perché a ogni Release cerca tra gli elementi di riserva; in una build la nuvola resterebbe due volte nel pool e due Get restituirebbero lo stesso oggetto. Una causa comune è un oggetto che continua a funzionare dopo il rilascio e si rilascia di nuovo, motivo per cui actionOnRelease lo disattiva.
Sfida
MedioFai esplodere i fuochi d’artificio usando il pool di Unity.
- In
AwakediLauncher, crea unObjectPool<Spark>: crea gli oggetti conInstantiate(sparkPrefab), attivali quando vengono prelevati, disattivali quando vengono rilasciati, distruggi l’oggetto quando viene restituito e impostamaxSize: 5. - In
Update, preleva ogni scintilla conpool.Get()invece diInstantiate. - In
Return, chiamapool.Release(spark)invece diDestroy.
Premi «Gioca» e lancia alcune raffiche. Poi premi «Verifica».
Provalo tu
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;
public class Launcher : MonoBehaviour
{
public Spark sparkPrefab;
public int sparks = 8;
void Awake()
{
// Crea il pool: crea, ottieni, rilascia e distruggi, con al massimo 5 scintille di riserva
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
for (int i = 0; i < sparks; i++)
{
Spark spark = Instantiate(sparkPrefab);
spark.transform.position = transform.position + Vector3.up;
spark.Launch(Direction(i), this);
}
}
}
// Una scintilla che ha esaurito il suo ciclo di vita
public void Return(Spark spark)
{
Destroy(spark.gameObject);
}
// Verso l'esterno e verso l'alto, distribuite uniformemente intorno al lanciatore
Vector3 Direction(int i)
{
return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
}
}
Tutte le lezioni di Architettura dei giochi in Unity
1Componenti, non gerarchie
Componenti piccoliUno script base per i nemiciComponenti astrattiComponenti che collaboranoRipasso: torretta modulareRipasso: cannone doppio4Dati serializzati
Classi serializzabiliElenchi nell'InspectorEnum nell'InspectorRiepilogo: tabella del bottinoRiepilogo: tira il bottino2Interfacce in Unity
IDamageableInterfacce e TryGetComponentGetComponentsRiepilogo: tasto InteragisciRiepilogo: il più vicino a portata5ScriptableObjects
Asset di datiStatistiche delle armiImpostazioni condiviseSalva il ventoOnde come datiRiepilogo: database degli oggettiRiepilogo: comprare dal negozio3Eventi
Eventi C# in UnityIscrizione in OnEnableCampi UnityEventGli eventi guidano l'interfaccia utenteRiepilogo: popup dei risultatiRiepilogo: timer del popup6Salvare con JSON
JsonUtilitySalva la partitaCaricamento e valori predefinitiRiepilogo: slot di salvataggioScegli ed elimina uno slot9Pooling degli oggetti
Perché usare un pool di oggettiUn pool con una codaObjectPool di UnityRiepilogo: pool di proiettiliEsercitati da solo: Playground Unity