Unity'nin ObjectPool'ı
Coddy'nin Unity Journey'sinin Unity'de Oyun Mimarisi bölümünün bir parçası. Ders 39 / 50.
Unity, UnityEngine.Pool içindeki ObjectPool<T> havuzunu sunar. Dört lambda ile her adımda ne yapacağını belirtirsin; havuz da yedekleri ve sayımları yönetir. Bu baca her 0.2 saniyede bir duman çıkarır ve her duman püskürtüsü bir saniye sonra havuza döner:
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, Get havuzu boş bulduğunda çalışır; actionOnGet her Get işleminde, actionOnRelease ise her Release işleminde çalışır. Bir duman püskürtüsü, maxSize kadar yedek zaten beklerken havuza bırakılırsa havuz onu saklamaz: actionOnDestroy onu yok eder. defaultCapacity, havuz listesinin yalnızca başlangıç boyutudur; bu yüzden önceden hiçbir şey oluşturulmaz. CountAll, havuzun oluşturduğu ve hâlâ sahip olduğu duman püskürtülerini; CountActive, oyunda olanları; CountInactive ise yedekleri sayar. Get, baca onu yerleştirmeden önce duman püskürtüsünü etkinleştirmiştir; burada bu sorun olmaz, çünkü Puff'ın konumunu okuyan bir OnEnable'ı yoktur. Duman püskürtüsü, her Unity havuzunun uyguladığı arayüz olan IObjectPool<Puff> türünde havuza başvuruyu tutar ve Launch her kullanımda yaşını sıfırlar.
collectionCheck açıkken, zaten havuzda olan bir duman püskürtüsünü havuza bırakmak InvalidOperationException hatası verir: Trying to release an object that has already been released to the pool. Yedekleri her Release işleminde aradığı için bu kontrol yalnızca Editor'da çalışır; derlemede duman püskürtüsü havuzda iki kez bulunur ve iki Get çağrısı aynı nesneyi döndürür. Bunun yaygın bir nedeni, havuza bırakıldıktan sonra çalışmaya devam edip kendini yeniden havuza bırakan bir nesnedir; actionOnRelease'ın onu devre dışı bırakmasının nedeni de budur.
Görev
OrtaHavai fişekler. Boşluk tuşuna her basışta fırlatıcıdan 8 kıvılcım fırlar ve her Spark, 1 saniyelik ömrü sona erdiğinde fırlatıcının Return(this) metodunu çağırır (Spark hazır). Bugün fırlatıcı her kıvılcımı Instantiate eder ve Destroy eder. Unity'nin havuzunu kullan:
Launcher.csiçinde Awake metodunda birObjectPool<Spark>oluştur. Bu havuz,sparkPrefabörneğini oluşturarak bir kıvılcım yaratır, kıvılcım havuzdan alındığında onu etkinleştirir, geri geldiğinde devre dışı bırakır ve havuza bırakıldığında kıvılcımın nesnesini yok eder.- Havuz en fazla 5 yedek kıvılcım tutar; bu nedenle 8 kıvılcımlık bir patlamadan sonra 5'i bekler, 3'ü yok edilir.
- Boşluk tuşu, 8 kıvılcımını örnek oluşturmak yerine havuzdan alır ve
Return, kıvılcımı yok etmek yerine havuza geri bırakır.
Oynat'a bas, birkaç patlama gerçekleştir, ardından Kontrol Et'e bas.
Kendin dene
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;
public class Launcher : MonoBehaviour
{
public Spark sparkPrefab;
public int sparks = 8;
void Awake()
{
// Havuzu oluştur: en fazla 5 yedek kıvılcım olacak şekilde oluşturma, alma, bırakma ve yok etme işlemlerini tanımla
}
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);
}
}
}
// Ömrü sona ermiş bir kıvılcım
public void Return(Spark spark)
{
Destroy(spark.gameObject);
}
// Dışarı ve yukarı doğru, fırlatıcının çevresine eşit aralıklarla yayılmış
Vector3 Direction(int i)
{
return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Unity'de Oyun Mimarisi bölümündeki tüm dersler
1Hiyerarşiler Değil, Bileşenler
Küçük BileşenlerTemel Bir Düşman BetiğiSoyut BileşenlerBirlikte Çalışan BileşenlerÖzet: Modüler Taret4Serileştirilmiş Veriler
Serileştirilebilir SınıflarInspector'da ListelerInspector'da Enum'larÖzet: Ganimet Tablosu7Durum Makineleri
Sınıflar Olarak DurumlarBir Durum MakinesiGeçişlerDüşmanların Yapay ZekâsıTekrar: Kapı Durumları10Proje: Arena Hayatta Kalma
KahramanDüşman Türleri5ScriptableObjects
Veri VarlıklarıSilah İstatistikleriPaylaşılan AyarlarVeri Olarak DalgalarTekrar: Eşya Veritabanı8Yeniden Kullanılabilir Kod
Genişletme MetotlarıGeneric SingletonGeneric YardımcılarTekrar: FindNearest