Menu
CoddyTech

الحالات كأصناف

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

يجمع مفتاح Section 3 المبني على تعداد عمل كل حالة في دالة Update واحدة. لكن هذا النهج لا يتوسع عندما تصبح لكل حالة بياناتها الخاصة: إذ ينتهي المطاف بمؤقت لا تستخدمه سوى حالة واحدة بوصفه حقلًا في MonoBehaviour، إلى جانب حقول كل الحالات الأخرى، ويجب أن تتذكر كل حالة في case إعادة ضبط ما تستخدمه. يمنح نمط الحالة في C# كل حالة صفًا خاصًا بها، وتطبّق كل الفئات واجهة واحدة. يومض هذا المنارة أو يبقى مضاءً، ويبدّل Space بين الحالتين:

public interface IState
{
    void Enter();
    void Tick();
    void Exit();
}

public class BlinkState : IState
{
    private Renderer lamp;
    private float timer;

    public BlinkState(Renderer lamp)
    {
        this.lamp = lamp;
    }

    public void Enter() { timer = 0f; }

    public void Tick()
    {
        timer += Time.deltaTime;
        if (timer >= 0.5f)
        {
            timer = 0f;
            lamp.enabled = !lamp.enabled;
        }
    }

    public void Exit() { lamp.enabled = true; }
}

public class SteadyState : IState
{
    public void Enter() { }
    public void Tick() { }
    public void Exit() { }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private IState blink;
    private IState steady;
    private IState current;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        SetState(steady);
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
        current.Tick();
    }

    void SetState(IState next)
    {
        if (current != null) current.Exit();
        current = next;
        current.Enter();
    }
}

الحالات فئات C# عادية، وليست MonoBehaviours. تنشئها باستخدام new وتمرر إليها ما تحتاجه عبر المُنشئ، وهنا هو Renderer الخاص بالمصباح، لأنها ليست مكوّنات ولا يمكنها استدعاء GetComponent أو عرض حقول في Inspector. ولا تستدعي Unity دوالها أيضًا: فـ Beacon هو MonoBehaviour، لذا تستدعي دالة Update الخاصة به current.Tick() في كل إطار.

ينتمي timer إلى BlinkState وحدها، وتضبطه Enter على 0 في كل مرة تبدأ فيها المنارة بالوميض. تنظّف Exit الحالة عند انتهائها: قد يُضغط Space بينما يكون المصباح مطفأً، فتُعيده Exit إلى الإضاءة، وبالتالي لا تبدأ SteadyState ومصباحها مطفأ. تنفّذ SetState دالة Exit للحالة القديمة، ثم دالة Enter للحالة الجديدة. أما الحالة الثالثة، مثل النبض البطيء، فتكون فئة إضافية، ولا يتغير Update الخاص بـ Beacon.

challenge icon

التحدي

متوسط

اكتب حالة المسح للبرج.

  1. في IState.cs، أعلن public interface IState مع void Enter(); وvoid Tick(); وvoid Exit();.
  2. في TurretStates.cs، اكتب ScanState : IState، مع تمرير الرأس إليه. عند الدخول: اجعل الزاوية 0، ولون الرأس Color.green. عند التحديث: حرّك زاوية y المحلية للرأس بين -45 و45، بمعدل 90 درجة في الثانية.
  3. Turret: أدخِل حالة واحدة في Start، وحدّثها في Update.

اضغط على «العب»: سيتحرك الرأس الأخضر ذهابًا وإيابًا. ثم اضغط على «تحقق».

جرّب بنفسك

using UnityEngine;

// ScanState

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

تدرّب بنفسك: Playground لـ Unity