Menu
CoddyTech

המוחות של האויבים

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

המוח של אויב הוא מכונת מצבים, עם מצב אחד לכל התנהגות. שלד זה נע בין עמדות השמירה שלו, רודף אחרי שחקן שמתקרב עד למרחק של 6 יחידות, ומניף את חרבו פעם בשנייה כשהוא קרוב. כל מצב קובע בעצמו איך יוצאים ממנו, והשלד ממשיך להשתמש בפונקציות העזר המשותפות להם:

public class Skeleton : MonoBehaviour
{
    public Transform player;
    public Transform[] posts;
    public float speed = 2f;
    public StateMachine machine = new StateMachine();
    public IState patrol, chase, attack;

    void Start()
    {
        patrol = new PatrolState(this);
        chase = new ChaseState(this);
        attack = new AttackState(this);
        machine.ChangeState(patrol);
    }

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

    public float PlayerDistance() { return Vector3.Distance(transform.position, player.position); }

    public void WalkTo(Vector3 target)
    {
        target.y = transform.position.y;
        transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
    }
}

public class PatrolState : IState
{
    private Skeleton skel;
    private int next;
    public PatrolState(Skeleton skel) { this.skel = skel; }
    public void Enter() { }
    public void Exit() { }

    public void Tick()
    {
        if (skel.PlayerDistance() < 6f) { skel.machine.ChangeState(skel.chase); return; }
        Vector3 post = skel.posts[next].position;
        post.y = skel.transform.position.y;
        skel.WalkTo(post);
        if (skel.transform.position == post) next = (next + 1) % skel.posts.Length;
    }
}

public class ChaseState : IState
{
    private Skeleton skel;
    public ChaseState(Skeleton skel) { this.skel = skel; }
    public void Enter() { }
    public void Exit() { }

    public void Tick()
    {
        float d = skel.PlayerDistance();
        if (d > 6f) { skel.machine.ChangeState(skel.patrol); return; }
        if (d < 1.5f) { skel.machine.ChangeState(skel.attack); return; }
        skel.WalkTo(skel.player.position);
    }
}

public class AttackState : IState
{
    private Skeleton skel;
    private float cooldown;
    public AttackState(Skeleton skel) { this.skel = skel; }
    public void Enter() { cooldown = 0f; }
    public void Exit() { }

    public void Tick()
    {
        if (skel.PlayerDistance() > 1.5f) { skel.machine.ChangeState(skel.chase); return; }
        cooldown -= Time.deltaTime;
        if (cooldown <= 0f) { Debug.Log("Swing!"); cooldown = 1f; }
    }
}

המצבים נוצרים פעם אחת ונשארים כל עוד השלד קיים, ולכן השדות שלהם נשמרים בין ביקור לביקור. הערך next של PatrolState נשאר כפי שהיה גם אחרי מרדף, והשלד ממשיך לעמדה שאליה היה בדרך. Enter מאפס רק את מה שאמור להתחיל מחדש: Enter של AttackState מאפס את cooldown ל-0, כך שהנפת החרב הראשונה מתרחשת ברגע שהשלד מגיע לשחקן.

כל התנועה מתבצעת באמצעות WalkTo; כאן זו MoveTowards על ה-transform, שעוברת דרך קירות. כדי להזיז את השלד באמצעות Rigidbody במקום זאת, WalkTo מגדירה את מהירות הגוף, והשלד מתקדם במכונת המצבים ב-FixedUpdate, שם Time.deltaTime הוא צעד הפיזיקה. שלושת המצבים אינם משתנים: הם קובעים לאן ללכת, והאובייקט שמחזיק בהם קובע איך.

challenge icon

אתגר

בינוני

תן לאביר את PatrolState ואת ChaseState בתוך KnightStates.cs, ולכל אחת מהן תן את האביר.

  1. סיור: לך אל waypoints[next]; כשאתה במרחק קטן מ־0.3, קדם את next באחד, בלולאה, ושמור אותו בין ביקורים. אם המרחק קטן מ־sightRange, רדוף.
  2. מרדף: לך אל השחקן; אם המרחק גדול מ־loseRange, עבור לסיור.
  3. בתוך Knight, צור את המכונה ואת המצבים ב־Awake, הפעל סיור ב־Start, וקרא ל־tick ב־FixedUpdate.

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

נסו בעצמכם

using UnityEngine;

// PatrolState ו-ChaseState

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

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