Menu
CoddyTech

מעברים

חלק מהיחידה ארכיטקטורת משחקים ב-Unity במסלול ה-Unity של Coddy. שיעור 38 מתוך 64.

מי מחליט מתי המצב משתנה? אם שואלים את הבעלים, כל הכללים חוזרים להימצא בתוך Update אחד, כפי שקרה עם המתג. התשובה המקובלת היא שכל מצב מכיר את הדרך שלו החוצה: ב-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 של המכונה, והכללים נמצאים במצבים שאליהם הם שייכים: פתיל של 2 שניות הוא באחריות FuseState בלבד.

ChangeState מפעיל מיד את Exit של FuseState ואת Enter של IdleState, אבל שאר הקוד ב-Tick של FuseState עדיין היה ממשיך לרוץ אחרי הקריאה. return עוצר אותו; אחרת הפתיל היה ממשיך לבעור עוד פריים אחד במצב שכבר הסתיים. כותבים Destroy בתור Object.Destroy: MonoBehaviour יורש אותו ממחלקת Object של Unity, ומחלקה רגילה חייבת לציין את שם המחלקה.

challenge icon

אתגר

בינוני

כתבו את המעברים של מלכודת הזבובים בכל הפעלה של Tick בתוך FlytrapStates.cs.

  1. פתוחה: כאשר trap.PlayerInReach(), קראו ל־trap.machine.ChangeState(trap.snap);.
  2. נסגרת בבת אחת: הוסיפו את Time.deltaTime ל־timer; אחרי 0.5, עברו אל trap.chew אם השחקן עדיין בטווח, אחרת אל trap.open.
  3. לועסת: הפחיתו את timer מ־3; כשהוא מגיע ל־0, עברו אל trap.open.

לחצו על "שחק", לכו לתוך המלכודת ואז התחמקו ממנה. לאחר מכן לחצו על "בדיקה".

נסו בעצמכם

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()
    {
    }
}

כל השיעורים ביחידה ארכיטקטורת משחקים ב-Unity

תרגלו בעצמכם: Unity אונליין