Menu
CoddyTech

ObjectPool di Unity

Termasuk bagian Arsitektur Game di Unity dalam perjalanan Unity di Coddy. Pelajaran 48 dari 64.

Unity menyediakan pool, ObjectPool<T> di UnityEngine.Pool. Kamu memberi tahu pool apa yang harus dilakukan pada setiap langkah dengan empat lambda, lalu pool menyimpan objek cadangan dan jumlahnya. Cerobong ini mengepulkan asap setiap 0.2 detik, dan setiap kepulan dikembalikan setelah satu detik:

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 dijalankan saat Get mendapati pool kosong; actionOnGet dijalankan setiap kali Get dipanggil dan actionOnRelease setiap kali Release dipanggil. Saat sebuah kepulan dikembalikan ketika sudah ada objek cadangan sebanyak maxSize, pool tidak menyimpannya: actionOnDestroy akan menghancurkannya. defaultCapacity hanya menentukan kapasitas awal list milik pool, jadi tidak ada objek yang dibuat sejak awal. CountAll menghitung kepulan yang telah dibuat dan masih dimiliki pool, CountActive menghitung yang sedang ada di dalam game, dan CountInactive menghitung objek cadangan. Get mengaktifkan kepulan sebelum cerobong menempatkannya, dan ini tidak masalah di sini karena Puff tidak memiliki OnEnable yang membaca posisinya. Kepulan menyimpan pool sebagai IObjectPool<Puff>, yaitu interface yang diimplementasikan oleh setiap pool Unity, dan Launch mengatur ulang usianya setiap kali digunakan.

Jika collectionCheck aktif, mengembalikan kepulan yang sudah ada di dalam pool akan memunculkan InvalidOperationException: Trying to release an object that has already been released to the pool. Pemeriksaan ini hanya berjalan di Editor karena pemeriksaan mencari objek cadangan pada setiap Release; dalam build, kepulan akan tersimpan dua kali di dalam pool dan dua pemanggilan Get akan memberikan object yang sama. Penyebab umumnya adalah object yang terus berjalan setelah dikembalikan lalu mengembalikan dirinya lagi. Karena itu, actionOnRelease menonaktifkannya.

challenge icon

Tantangan

Sedang

Luncurkan kembang api dari pool Unity.

  1. Di Awake milik Launcher, buat ObjectPool<Spark>: buat dengan Instantiate(sparkPrefab), aktifkan saat diambil, nonaktifkan saat dilepas, hancurkan object saat dilepas, maxSize: 5.
  2. Di Update, ambil setiap spark dengan pool.Get() alih-alih Instantiate.
  3. Di Return, panggil pool.Release(spark) alih-alih Destroy.

Tekan tombol “Main” dan luncurkan beberapa rentetan kembang api. Lalu tekan tombol “Periksa”.

Coba sendiri

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;

public class Launcher : MonoBehaviour
{
    public Spark sparkPrefab;
    public int sparks = 8;

    void Awake()
    {
        // Buat pool: ciptakan, ambil, lepaskan, dan hancurkan, dengan maksimal 5 percikan cadangan
    }

    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);
            }
        }
    }

    // Percikan yang masa hidupnya telah berakhir
    public void Return(Spark spark)
    {
        Destroy(spark.gameObject);
    }

    // Ke luar dan ke atas, tersebar merata di sekeliling peluncur
    Vector3 Direction(int i)
    {
        return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
    }
}

Semua pelajaran di Arsitektur Game di Unity

Latihan sendiri: Playground Unity