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

الانتقالات

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

من يقرر متى تتغير الحالة؟ إن سؤال الكائن المالك يعيد كل قاعدة إلى دالة Update واحدة، كما فعلت عبارة switch. والإجابة المعتادة هي أن كل حالة تعرف طريقها الخاص للخروج: ففي دالة Tick تتحقق من شرطها وتطلب من الآلة الانتقال إلى الحالة التالية. تنتظر هذه القنبلة حتى يقترب اللاعب، ثم تحرق فتيلها، وتعود إلى الانتظار إذا ابتعد اللاعب راكضًا:

public class Bomb : MonoBehaviour
{
    public Transform player;
    public StateMachine machine = new StateMachine();
    public IState idle;
    public IState fuse;

    void Start()
    {
        idle = new IdleState(this);
        fuse = new FuseState(this);
        machine.ChangeState(idle);
    }

    void Update() { machine.Tick(); }

    public bool PlayerNear()
    {
        return Vector3.Distance(transform.position, player.position) < 3f;
    }
}

public class IdleState : IState
{
    private Bomb bomb;
    public IdleState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { }
    public void Exit() { }

    public void Tick()
    {
        if (bomb.PlayerNear()) bomb.machine.ChangeState(bomb.fuse);
    }
}

public class FuseState : IState
{
    private Bomb bomb;
    private float timer;
    public FuseState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { timer = 2f; }
    public void Exit() { }

    public void Tick()
    {
        if (!bomb.PlayerNear())
        {
            bomb.machine.ChangeState(bomb.idle);
            return;
        }
        timer -= Time.deltaTime;
        if (timer <= 0f)
        {
            Debug.Log("Boom!");
            Object.Destroy(bomb.gameObject);
        }
    }
}

تحصل كل حالة على القنبلة في مُنشئها، ومن خلالها تصل إلى الآلة واختبار قرب اللاعب والحالات الأخرى. تنشئ القنبلة كل حالة مرة واحدة في Start، لذا لا تنشئ حالةٌ حالةً أخرى باستخدام new: فلو أنشأت حالتان إحداهما الأخرى في مُنشئَيهما، لاستمر الدوران حتى يفيض المكدس. لا تفعل دالة Update في القنبلة سوى استدعاء Tick للآلة، وتوجد القواعد في الحالات التي تخصها: فالفتيل الذي مدته ثانيتان هو مسؤولية FuseState وحدها.

تشغّل ChangeState دالتي Exit الخاصة بـ FuseState وEnter الخاصة بـ IdleState فورًا، لكن بقية دالة Tick في FuseState ستظل تعمل بعد الاستدعاء. يوقفها return، وإلا فسيحترق الفتيل إطارًا إضافيًا واحدًا لحالة انتهت بالفعل. تُكتب Destroy بالشكل Object.Destroy: ترثها MonoBehaviour من فئة Object في Unity، أما الفئة العادية فعليها ذكر اسم الفئة.

challenge icon

التحدي

متوسط

ينقضّ مصيدة الذباب على كل من يقترب منها. الملف Flytrap.cs جاهز: ينشئ آلة الحالات والحالات الثلاث (الحقول العامة open وsnap وchew)، ويبدأ بحالة Open ويحدّث الآلة في كل إطار، وتُبيّن PlayerInReach() ما إذا كان اللاعب على بُعد أقل من 2 على الأرض. في FlytrapStates.cs كُتبت دالة Enter لكل حالة (الألوان والمؤقتات ورسالة السجل Chomp!). اكتب الانتقالات في دالة Tick لكل حالة:

  • Open: عندما يكون اللاعب في متناول المصيدة، تنقضّ المصيدة.
  • Snap تستمر 0.5 ثانية. بعد ذلك، تمضغ المصيدة اللاعب إذا كان لا يزال في متناولها، وتفتح مجددًا إذا تمكن من الهرب.
  • Chew تستمر 3 ثوانٍ، أيًا كان من حولها، ثم تفتح المصيدة مجددًا.

تُحرّك الأسهم اللاعب. اضغط Play، وامشِ نحو المصيدة، ثم حاول تفاديها، وبعدها اضغط Check.

جرّب بنفسك

using UnityEngine;

public class OpenState : IState
{
    private Flytrap trap;

    public OpenState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        trap.Paint(new Color(0.3f, 0.8f, 0.2f));
    }

    public void Tick()
    {
        // أطبِق عندما يصبح اللاعب في المتناول
    }

    public void Exit()
    {
    }
}

public class SnapState : IState
{
    private Flytrap trap;
    private float timer;

    public SnapState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 0f;
        trap.Paint(new Color(1f, 0.55f, 0.1f));
    }

    public void Tick()
    {
        // بعد 0.5 ثانية: امضغ إذا كان اللاعب لا يزال في المتناول، وإلا فافتح مجددًا
    }

    public void Exit()
    {
    }
}

public class ChewState : IState
{
    private Flytrap trap;
    private float timer;

    public ChewState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 3f;
        trap.Paint(new Color(0.5f, 0.05f, 0.1f));
        Debug.Log("Chomp!");
    }

    public void Tick()
    {
        // بعد 3 ثوانٍ: افتح مجددًا
    }

    public void Exit()
    {
    }
}
quiz iconاختبر نفسك

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

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