מעברים
חלק מהיחידה ארכיטקטורת משחקים ב-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, ומחלקה רגילה צריכה לציין את שם המחלקה.
אתגר
בינונימלכודת הזבובים נושכת כל מי שמתקרב אליה. 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()
{
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה ארכיטקטורת משחקים ב-Unity
1רכיבים, לא היררכיות
רכיבים קטניםסקריפט בסיס לאויברכיבים מופשטיםרכיבים שעובדים יחדסיכום: צריח מודולרי