Menu
CoddyTech
flag Ar iconالعربيةdown icon

مجموعة باستخدام طابور

جزء من قسم هندسة الألعاب في Unity في رحلة Unity على Coddy. الدرس 38 من 50.

يحتاج المجمّع إلى مكان يحتفظ فيه بالكائنات الاحتياطية، ويوفّر C# المجموعة المناسبة لذلك، Queue<T>: تضيف Enqueue عنصرًا إلى الخلف، وتأخذ Dequeue العنصر الموجود في المقدمة، ويبيّن Count عدد العناصر المنتظرة. يطلق هذا الحوض فقاعة كل 0.3 ثانية، وتعود كل فقاعة إلى المجمّع عند السطح:

using System.Collections.Generic;
using UnityEngine;

public class BubblePool : MonoBehaviour
{
    public GameObject bubblePrefab;
    private Queue<GameObject> pool = new Queue<GameObject>();
    private float timer;

    void Update()
    {
        timer += Time.deltaTime;
        if (timer >= 0.3f)
        {
            timer = 0f;
            Get(new Vector3(Random.Range(-2f, 2f), 0f, 0f));
        }
    }

    public GameObject Get(Vector3 position)
    {
        GameObject bubble;
        if (pool.Count > 0)
        {
            bubble = pool.Dequeue();
        }
        else
        {
            bubble = Instantiate(bubblePrefab);
            bubble.GetComponent<Bubble>().pool = this;
        }
        bubble.transform.position = position;
        bubble.SetActive(true);
        return bubble;
    }

    public void Return(GameObject bubble)
    {
        bubble.SetActive(false);
        pool.Enqueue(bubble);
    }
}
// Bubble.cs، على قالب الفقاعة الجاهز
public BubblePool pool;

void Update()
{
    transform.Translate(0f, 2f * Time.deltaTime, 0f);
    if (transform.position.y > 5f) pool.Return(gameObject);
}

تتحقق Get من Count أولًا، لأن استدعاء Dequeue على قائمة انتظار فارغة يؤدي إلى طرح InvalidOperationException. وبعد ذلك فقط تستدعي Instantiate، ولا تحتاج إلا الفقاعة الجديدة إلى تعيين الحقل pool الخاص بها؛ فالفقاعة المعاد استخدامها ما زالت تحتفظ به. تعيد قائمة الانتظار الفقاعة التي انتظرت أطول مدة أولًا، وفق مبدأ «ما يدخل أولًا يخرج أولًا». تستدعي الفقاعة عند السطح Return بدلًا من Destroy، وتبقى في المشهد، غير نشطة، حتى الاستدعاء التالي لـ Get.

تضع Get الفقاعة في موضعها قبل SetActive(true)، لأن تفعيلها يشغّل OnEnable فورًا، وينبغي لأي شيء يحدث هناك أن يرى الموضع الجديد، لا الموضع الذي اختفت منه في المرة السابقة. وهنا يبدأ الكائن المعاد استخدامه من جديد أيضًا: يُستدعى Awake وStart مرة واحدة، عند إنشاء الفقاعة، بينما يُستدعى OnEnable مع كل استدعاء لـ Get.

challenge icon

التحدي

متوسط

آثار الأقدام على الرمل. الأسهم تحرّك اللاعب (جاهز). يُسقط Trail.cs، الموجود على اللاعب، أثر قدم كلما مشى مسافة مقدارها وحدة واحدة، وذلك باستدعاء Get(position)، ويستمر كل Footprint لمدة life (1.5) ثانية. حاليًا، تنشئ Get أثر قدم جديدًا في كل مرة، ثم يدمّر كل أثر نفسه. استخدم تجميع الكائنات:

  • في Trail.cs، احتفظ بآثار الأقدام الاحتياطية في Queue<GameObject>. يجب تعيين الحقل trail لكل أثر قدم ينشئه Trail إلى هذا الـ Trail.
  • في Start، املأ التجمع بـ prewarm (6) آثار أقدام، يتم إنشاؤها وإيقاف تشغيلها، لكي لا تُنشأ أشياء جديدة عند الخطوات الأولى.
  • تأخذ Get(position) أثر قدم من قائمة الانتظار إذا كان فيها واحد، وتنشئ أثرًا جديدًا فقط عندما تكون فارغة؛ ثم تضع أثر القدم وتُشغّله.
  • تُوقف Return(footprint) أثر القدم وتضعه في قائمة الانتظار.
  • في Footprint.cs، يحسب أثر القدم عمره، وبعد life ثانية يعود باستخدام trail.Return(gameObject) بدلًا من تدميره. ويستمر أثر القدم المُعاد استخدامه لمدة 1.5 ثانية كاملة مرة أخرى.

اضغط Play، وتجول قليلًا، ثم اضغط Check.

جرّب بنفسك

using System.Collections.Generic;
using UnityEngine;

public class Trail : MonoBehaviour
{
    public GameObject footprintPrefab;
    public float step = 1f;
    public int prewarm = 6;
    private Vector3 lastDrop;

    void Start()
    {
        lastDrop = transform.position;
        // املأ المجمّع بآثار أقدام مُجهّزة مسبقًا بعدد prewarm
    }

    void Update()
    {
        if (Vector3.Distance(transform.position, lastDrop) >= step)
        {
            lastDrop = transform.position;
            Get(new Vector3(transform.position.x, 0.02f, transform.position.z));
        }
    }

    public GameObject Get(Vector3 position)
    {
        GameObject footprint = Instantiate(footprintPrefab, position, Quaternion.identity);
        footprint.GetComponent<Footprint>().trail = this;
        return footprint;
    }

    public void Return(GameObject footprint)
    {
        // تنتظر آثار الأقدام الاحتياطية في المجمّع
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس هندسة الألعاب في Unity