מכונת מצבים
חלק מהיחידה ארכיטקטורת משחקים ב-Unity במסלול ה-Unity של Coddy. שיעור 29 מתוך 50.
השיטה SetState של המגדלור תהיה זהה בכל אובייקט שיש לו מצבים: צריח, אויב, דלת. הקוד הזה יכול להיות במחלקה משלו, מכונת מצבים, שמחזיקה את המצב הנוכחי ומשנה אותו. כל אובייקט יוצר מכונה אחת וקורא לה, במקום לחזור על הקוד:
public class StateMachine
{
public IState Current { get; private set; }
public void ChangeState(IState next)
{
Current?.Exit();
Current = next;
Current.Enter();
}
public void Tick()
{
Current?.Tick();
}
}
public class Beacon : MonoBehaviour
{
public Renderer lamp;
private StateMachine machine = new StateMachine();
private IState blink;
private IState steady;
void Start()
{
blink = new BlinkState(lamp);
steady = new SteadyState();
machine.ChangeState(steady);
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame) machine.ChangeState(machine.Current == steady ? blink : steady);
machine.Tick();
}
}לקריאה הראשונה ל־ChangeState אין מצב לעזוב: Current הוא null, ו־?. מדלג על הקריאה ל־Exit. יחידה 1 הזהירה ש־?. לא מזהה את ה־null המדומה של Unity; זה קשור לאובייקטים של Unity שהושמדו, והמצבים הם אובייקטי C# רגילים, לכן ?. בטוח כאן. ל־Current יש private set, ולכן שום סקריפט לא יכול להחליף את המצב בלי לעבור דרך ChangeState וה־Exit וה־Enter שלה.
הסדר בתוך ChangeState חשוב בכל פעם ששני מצבים נוגעים באותו הדבר. Exit מבטל את מה שהמצב הישן שינה, ואז Enter מגדיר את המצב החדש, כך שלמצב החדש יש את המילה האחרונה. אם Enter של DarkState היה מכבה את המנורה ופועל לפני Exit של BlinkState, אותו Exit היה מדליק מחדש את המנורה במצב החשוך. גם StateMachine היא מחלקה רגילה: המגדלור, צריח ואויב יוצרים כל אחד מכונה משלו עם new וקוראים ל־Tick שלה מתוך Update שלהם.
אתגר
בינוניהחזק את Space כדי להתגנב. WalkState ו-SneakState מוכנים ב-PlayerStates.cs: המתודות Enter ו-Exit שלהן מתעדות מה קורה (Walk: enter, Sneak: exit...), והמתודה Tick שלהן קוראת ל-Move() של השחקן. כתוב את המכונה שמפעילה אותן.
- ב-
StateMachine.cs, כתוב מחלקה רגילהStateMachineעם מאפיין ציבוריCurrentשרק המכונה יכולה להגדיר, מתודהChangeState(IState next)שמפעילה את Exit של המצב הישן ואז את Enter של המצב החדש, ומתודהTick()שמפעילה את Tick של המצב הנוכחי. - השחקן מבקש את המצב שלו בכל פריים, לכן קריאה ל-
ChangeStateעם המצב שכבר נוכחי לא עושה כלום: אין Exit ואין Enter. - ב-
Player.cs, הוסף שדה מסוגStateMachineבשםmachine. ב-Start, צור את המכונה ואת שני המצבים (כל אחד מקבל את השחקן) והתחל בהליכה. ב-Update, עבור להתגנבות בזמן שמחזיקים את Space, ולהליכה אחרת כך, ואז בצע tick למכונה.
לחץ על Play, לך, החזק את Space והמשך ללכת, ואז לחץ על Check.
נסו בעצמכם
// StateMachine: Current, ChangeState ו-Tick
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה ארכיטקטורת משחקים ב-Unity
1רכיבים, לא היררכיות
רכיבים קטניםסקריפט בסיס לאויברכיבים מופשטיםרכיבים שעובדים יחדסיכום: צריח מודולרי