ObjectPool của Unity
Thuộc phần Kiến trúc trò chơi trong Unity trong hành trình Unity của Coddy. Bài học 48 trên 64.
Unity tích hợp sẵn một pool, ObjectPool<T> trong UnityEngine.Pool. Bạn cho pool biết cần làm gì ở mỗi bước bằng bốn hàm lambda, còn pool sẽ giữ các đối tượng dự phòng và bộ đếm. Ống khói này phun khói mỗi 0.2 giây, và mỗi làn khói sẽ quay lại sau một giây:
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 chạy khi Get thấy pool trống; actionOnGet chạy mỗi lần gọi Get và actionOnRelease chạy mỗi lần gọi Release. Khi trả lại một làn khói trong lúc pool đã có maxSize đối tượng dự phòng, pool sẽ không giữ nó: actionOnDestroy sẽ hủy đối tượng đó. defaultCapacity chỉ là kích thước ban đầu của danh sách trong pool, nên pool không tạo sẵn đối tượng nào. CountAll đếm số làn khói mà pool đã tạo và vẫn sở hữu, CountActive đếm những làn khói đang ở trong trò chơi, còn CountInactive đếm các đối tượng dự phòng. Get bật làn khói trước khi ống khói đặt vị trí cho nó. Điều này không gây vấn đề ở đây vì Puff không có OnEnable đọc vị trí của nó. Làn khói lưu pool dưới dạng IObjectPool<Puff>, giao diện mà mọi pool của Unity đều triển khai, còn Launch đặt lại tuổi của nó mỗi lần sử dụng.
Khi bật collectionCheck, việc trả lại một làn khói đã nằm trong pool sẽ gây ra InvalidOperationException: Trying to release an object that has already been released to the pool. Việc kiểm tra chỉ chạy trong Editor vì nó tìm trong các đối tượng dự phòng mỗi lần gọi Release; trong bản build, làn khói sẽ nằm trong pool hai lần và hai lần gọi Get sẽ trả về cùng một đối tượng. Một nguyên nhân thường gặp là đối tượng vẫn tiếp tục chạy sau khi được trả lại rồi lại tự trả về pool lần nữa. Vì vậy, actionOnRelease sẽ tắt đối tượng.
Thử thách
Trung bìnhPhóng pháo hoa từ pool của Unity.
- Trong
AwakecủaLauncher, tạo mộtObjectPool<Spark>: tạo bằngInstantiate(sparkPrefab), bật khi lấy ra, tắt khi trả lại, hủy đối tượng khi loại bỏ,maxSize: 5. - Trong
Update, lấy từng tia lửa bằngpool.Get()thay vìInstantiate. - Trong
Return, gọipool.Release(spark)thay vìDestroy.
Nhấn Chơi và bắn vài loạt pháo. Sau đó nhấn Kiểm tra.
Tự làm thử
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;
public class Launcher : MonoBehaviour
{
public Spark sparkPrefab;
public int sparks = 8;
void Awake()
{
// Tạo pool: tạo, lấy, trả về và hủy, với tối đa 5 tia lửa dự phòng
}
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);
}
}
}
// Một tia lửa đã hết thời gian tồn tại
public void Return(Spark spark)
{
Destroy(spark.gameObject);
}
// Bay ra ngoài và lên trên, tỏa đều quanh bộ phóng
Vector3 Direction(int i)
{
return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
}
}
Tất cả bài học trong Kiến trúc trò chơi trong Unity
1Thành phần, không phải hệ thống phân cấp
Thành phần nhỏTập lệnh kẻ địch cơ sởThành phần trừu tượngCác thành phần phối hợp với nhauÔn tập: tháp pháo mô-đunÔn tập: pháo nòng đôi4Dữ liệu tuần tự hóa
Lớp có thể tuần tự hóaDanh sách trong InspectorKiểu liệt kê trong InspectorÔn tập: Bảng vật phẩm rơiÔn tập: Quay vật phẩm2Giao diện trong Unity
IDamageableGiao diện và TryGetComponentGetComponentsÔn tập: phím tương tácÔn tập: đối tượng gần nhất trong tầm với5ScriptableObjects
Tài sản dữ liệuChỉ số vũ khíCài đặt dùng chungLưu gióSóng dưới dạng dữ liệuÔn tập: Cơ sở dữ liệu vật phẩmÔn tập: Mua hàng từ cửa hàng8Code có thể tái sử dụng
Phương thức mở rộngSingleton tổng quátCác hàm hỗ trợ tổng quátÔn tập: FindNearest3Sự kiện
Sự kiện C# trong UnityĐăng ký trong OnEnableCác trường UnityEventSự kiện điều khiển UIÔn tập: Cửa sổ bật lên thành tíchÔn tập: Bộ hẹn giờ cửa sổ bật lên6Lưu dữ liệu bằng JSON
JsonUtilityLưu trò chơiTải dữ liệu và giá trị mặc địnhÔn tập: các ô lưuChọn và xóa một ô lưu9Tái sử dụng đối tượng bằng pool
Vì sao cần pool đối tượngPool dùng hàng đợiObjectPool của UnityÔn tập: pool đạnTự luyện tập: Playground Unity