موسس تیم BlueAge - بازیساز
بهینه سازی بازی (1) : "Object Pool" به زبان ساده (بخش 2) + پیاده سازی
در بخش قبلی، از اینکه چرا از "Object Pool" استفاده میکنیم و چطور استفاده میکنیم، پرداخته شد. حالا میرسیم به بخش دوم:
نکته آغازین: از اونجایی که Pool همچنان مجموعه ای از آبجکت هارو همراه خودش داره، وقتی هم که باهاش کاری نداریم همچنان در حافظه باقی است و جلوی Garbage Collector رو میگیره. پس برای اینکه این اتفاق نیافته، هر موقع با Pool کاری نداشتیم، بهتره که تمامی اتصالات و Reference هایی که به Pool مربوط میشن رو از بین ببریم.
آیا ایجاد و حذف آبجکت ها، به CPU ربطی داره؟
قطعا همینطوره! فرایند Instantiate() و Destroy() برای انجام کارشون نیازمند یک کمک کوچیک از سمت CPU هستن.
حالا فکر کنید چندین آبجکت مرتب درخواست Instantiate() و Destroy() رو ارسال کنن. فاجعه رخ میده.
پس فرایند Object Pooling، هوای CPU رو هم داره!
object Pool در یک نگاه:
پیاده سازی Object Pool در موتور Unity 3D (نمونه ساده)
0. قبل از هر چیز، باید یک فایل C# در یونیتی ایجاد کنیم :)
using UnityEngine;
using System.Collections.Generic;
public class Object_Pooler : MonoBehaviour
{
}
1. چندتا متغییر کوچیک رو باید وارد کنیم:
public class Object_Pooler : MonoBehaviour
{
//آبجکتی که قصد داریم ازش در بازی زیاد استفاده کنیم
public GameObject obj;
//حد و مرز برای ایجاد آبجکت
public int amount = 20;
//آبجکت هایی که در ابتدای بازی ساخته میشن، داخل این لیست ذخیره و استفاده میشن
public static List<GameObject> pooledObjects;}
2. حالا در نقطه استارت بازی، دستور میدیم که تمام آبجکت هارو ایجاد کن و در حالت "استراحت (غیرفعال)" قرار بده:
public class Object_Pooler : MonoBehaviour
{
//آبجکتی که قصد داریم ازش در بازی زیاد استفاده کنیم
public GameObject _obj;
//حد و مرز برای ایجاد آبجکت
public int _amount = 20;
//آبجکت هایی که در ابتدای بازی ساخته میشن، داخل این لیست ذخیره و استفاده میشن
public static List<GameObject> _pooledObjects;
void Start()
{
_pooledObjects = new List<GameObject>();
for (int i=0; i < _amount; i++)
{
// ایجاد اولیه
GameObject new_obj = (GameObject)Instantiate(_obj);
// آبجکت رو روی حالت "استراحت(غیرفعال)" میگذاریم
new_obj.SetActive(false);
// آبجکتی که ایجاد کردیم رو به لیست اضافه میکنیم
_pooledObjects.Add(new_obj);
}
}
}
3. یک تابع برای استفاده از آبجکت های "درحال استراحت"، اضافه میکنیم:
public class Object_Pooler : MonoBehaviour
{
public static GameObject GetPooledObject()
{
for (int i=0; i < _pooledObjects.Count; i++)
{
//چک میکنیم که آبجکت مورد نظر غیرفعال باشد
if (!_pooledObjects[i].activeInHierarchy)
return _pooledObjects[i];
}
return null;
}
}
4. حالا در یک اسکریپت دیگر، میتوانیم از Object Pool استفاده کنیم:
public class Gun : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0))
Shoot();
}
void Shoot()
{
// آبجکتی که در لیست وجود دارد و درحال استراحت است
GameObject obj = Object_Pooler.GetPooledObject();
if (obj != null)
{
obj.transfrom.position = Vector3.zero;
//فعالسازی
obj.SetActive(true);
}
}
}
5. در آخر، به آبجکتی که از Gun شلیک میشه، میگیم بعد از فلان کار انجام شده، غیرفعال شود:
مثلا بعد از 5 ثانیه، یا بعد از برخورد و...
توی این مثال، برخورد رو در نظر گرفتم:
public class Bullet : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
gameObject.SetActive(false);
}
}
توی این مثال، زمان رو در نظر گرفتم:
public class Bullet : MonoBehaviour
{
void OnEnable()
{
Invoke("Destroy", 5f);
}
private void Destroy()
{
gameObject.SetActive(false);
}
private void OnDisable()
{
CancelInvoke();
}
}
مبحث Object Pool یکی از مباحث مهم بهینه سازی بازی است که امیدوارم به پیاده سازی بهتر اون کمک کرده باشم.
مطلبی دیگر از این انتشارات
اصل Open/Closed
مطلبی دیگر از این انتشارات
موتور بازی ساز چیست؟ با موتورهای بازی ساز برتر جهان آشنا شوید!
مطلبی دیگر از این انتشارات
سرعت و جهت (velocity) در یونیتی+نحوه محاسبه