ObjectPool في Unity
جزء من قسم هندسة الألعاب في Unity في رحلة Unity على Coddy. الدرس 48 من 64.
توفّر Unity تجمّعًا للكائنات، وهو ObjectPool<T> ضمن UnityEngine.Pool. تخبره بما ينبغي فعله في كل خطوة باستخدام أربع دوال لامبدا، وهو يحتفظ بالكائنات الاحتياطية وبأعدادها. تُطلق هذه المدخنة نفثة دخان كل 0.2 ثانية، وتعود كل نفثة بعد ثانية واحدة:
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 أن التجمّع فارغ؛ وتُنفَّذ actionOnGet مع كل استدعاء لـ Get، بينما تُنفَّذ actionOnRelease مع كل استدعاء لـ Release. عندما تُحرَّر نفثة بينما تنتظر بالفعل maxSize من الكائنات الاحتياطية، لا يحتفظ بها التجمّع: إذ تتلفها actionOnDestroy. إن defaultCapacity هو فقط الحجم الابتدائي لقائمة التجمّع، لذا لا يُنشأ شيء مسبقًا. يحصي CountAll النفثات التي أنشأها التجمّع وما زال يملكها، ويحصر CountActive تلك الموجودة في اللعبة، وCountInactive الكائنات الاحتياطية. يُفعّل Get النفثة قبل أن تضعها المدخنة في موضعها، وهذا مناسب هنا لأن Puff لا تحتوي على OnEnable يقرأ موضعها. تحتفظ النفثة بالتجمّع على هيئة IObjectPool<Puff>، وهي الواجهة التي تطبّقها جميع تجمّعات Unity، وتعيد Launch ضبط عمرها عند كل استخدام.
عند تفعيل collectionCheck، يؤدي تحرير نفثة موجودة بالفعل في التجمّع إلى إطلاق InvalidOperationException: Trying to release an object that has already been released to the pool. لا يعمل الفحص إلا في المحرر، لأنه يبحث بين الكائنات الاحتياطية مع كل استدعاء لـ Release؛ أما في البنية المنشورة، فستبقى النفثة في التجمّع مرتين، وسيعيد استدعاء Get مرتين الكائن نفسه. من الأسباب الشائعة لذلك أن يستمر كائن في العمل بعد تحريره ثم يحرر نفسه مرة أخرى، ولهذا السبب تُعطّله actionOnRelease.
التحدي
متوسطأطلق الألعاب النارية من مجمّع Unity.
- في
Awakeالخاص بـLauncher، أنشئObjectPool<Spark>: أنشئ العناصر باستخدامInstantiate(sparkPrefab)، وفعّلها عند أخذها، وأوقفها عند إعادتها، ودمّر العنصر عند تحريره، معmaxSize: 5. - في
Update، خذ كل شرارة باستخدامpool.Get()بدلًا منInstantiate. - في
Return، استدعِpool.Release(spark)بدلًا منDestroy.
اضغط على «العب» وأطلق بضع دفعات. ثم اضغط على «تحقق».
جرّب بنفسك
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;
public class Launcher : MonoBehaviour
{
public Spark sparkPrefab;
public int sparks = 8;
void Awake()
{
// أنشئ المجمّع: أنشئ الشرارات واسترجعها وأعدها ودمّرها، مع الاحتفاظ بحد أقصى 5 شرارات احتياطية
}
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);
}
}
}
// شرارة انتهى عمرها
public void Return(Spark spark)
{
Destroy(spark.gameObject);
}
// إلى الخارج والأعلى، موزّعة بالتساوي حول القاذف
Vector3 Direction(int i)
{
return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
}
}
جميع دروس هندسة الألعاب في Unity
1المكوّنات، لا التسلسلات الهرمية
مكوّنات صغيرةنص برمجي أساسي للعدومكوّنات مجرّدةالمكوّنات تعمل معًامراجعة: برج معياريمراجعة: مدفع مزدوج4البيانات المُسلسلة
الأصناف القابلة للتسلسلالقوائم في Inspectorالتعدادات في Inspectorمراجعة: جدول الغنائممراجعة: اختيار الغنائم عشوائيًا2الواجهات في Unity
IDamageableالواجهات وTryGetComponentGetComponentsمراجعة: مفتاح التفاعلمراجعة: أقرب عنصر ضمن النطاق3الأحداث
الأحداث في C# ضمن Unityالاشتراك في OnEnableحقول UnityEventالأحداث تحرّك واجهة المستخدممراجعة: نافذة الإنجاز المنبثقةمراجعة: مؤقّت النافذة المنبثقة6الحفظ باستخدام JSON
JsonUtilityاحفظ اللعبةالتحميل والقيم الافتراضيةمراجعة: خانات الحفظاختر خانة واحذفها9تجميع الكائنات
لماذا نعيد استخدام الكائناتمجموعة باستخدام طابورObjectPool في Unityمراجعة: مجموعة الرصاصاتتدرّب بنفسك: Playground لـ Unity