אירועי C# ב-Unity
חלק מהיחידה ארכיטקטורת משחקים ב-Unity במסלול ה-Unity של Coddy. שיעור 12 מתוך 64.
כשהניקוד משתנה, לכמה דברים אכפת מכך: טקסט הניקוד, צליל, הישג. אם ScoreKeeper קורא לכל אחד מהם, הוא זקוק לשדה עבור כל אחד, וכל תכונה חדשה מחייבת לערוך אותו. אירוע הופך את המצב: ScoreKeeper מודיע על השינוי, ומי שאכפת לו נרשם להאזנה.
שתי מילים ב-C# מאפשרות זאת. Action<int> הוא טיפוס של מתודה שמקבלת int אחד ואינה מחזירה דבר. event מטיפוס זה הוא רשימה של מתודות כאלה: קוד אחר מוסיף את המתודה שלו באמצעות +=, והבעלים קורא לכולן באמצעות Invoke. ב-C# רגיל:
using System;
class Alarm
{
public event Action<int> Rang;
public void Ring(int hour)
{
Rang?.Invoke(hour);
}
}
class Sleeper
{
public void WakeUp(int hour)
{
Console.WriteLine("Up at " + hour);
}
}
// במקום אחר
Alarm alarm = new Alarm();
Sleeper sleeper = new Sleeper();
alarm.Rang += sleeper.WakeUp;
alarm.Ring(7); // קמים בשעה 7ב-Unity המפרסם והמאזינים שלו הם רכיבים, בדרך כלל על אובייקטים שונים במשחק:
using System;
using UnityEngine;
public class ScoreKeeper : MonoBehaviour
{
public event Action<int> OnScoreChanged;
private int score;
public void AddPoints(int points)
{
score += points;
OnScoreChanged?.Invoke(score);
}
}// ScoreLabel.cs, על הטקסט של ה-HUD
public ScoreKeeper keeper;
public TMP_Text label;
void Start()
{
keeper.OnScoreChanged += ShowScore;
}
void ShowScore(int score)
{
label.text = "Score: " + score;
}Action<int> פירושו שכל מאזין הוא מתודה שמקבלת int אחד, ובמקרה הזה את הניקוד החדש. Invoke קורא לכל המתודות שנרשמו, לפי סדר ההרשמה שלהן. כשאין מאזין, ערך האירוע הוא null, ולכן קריאה רגילה כמו OnScoreChanged(score) תגרום ל-NullReferenceException, ואילו ?. מדלג על הקריאה. מילת המפתח event מגבילה סקריפטים אחרים לשימוש ב-+= וב--=: ב-ScoreLabel, הביטויים keeper.OnScoreChanged(5) או keeper.OnScoreChanged = null לא מתקמפלים.
ל-ScoreKeeper אין שדה עבור התווית והוא לא יודע שהיא קיימת. מונה משולבים או נגן צלילים יכולים להירשם באותה הדרך, ו-ScoreKeeper נשאר כפי שהוא; גם סצנת בדיקה ללא HUD פועלת ללא שגיאות. מאזין מאתר את המפרסם באמצעות הפניה ב-Inspector, כמו כאן, או בכל דרך אחרת שמוכרת לך, כגון GetComponent או singleton. חשוב להסיר מאזין באמצעות -= ברגע שאובייקטים מושמדים, ועל כך נלמד בשיעור הבא.
אתגר
קלגרמו ללוחם להכריז על רצף המכות שלו.
- ב־
Fighter.cs, הוסיפוusing System;ואתpublic event Action<int> OnComboChanged;. - החליפו את השורות שמשתמשות ב־
comboTextוב־flameב־OnComboChanged?.Invoke(combo);, ומחקו את שני השדות. - בתוך
Start()שלComboTextושלComboFlame, כתבוfighter.OnComboChanged += Show;ו־+= Grow;.
לחצו על "שחק" ולחצו על מקש הרווח כמה פעמים: רצף המכות גדל ואז מתאפס. לאחר מכן לחצו על "בדיקה".
נסו בעצמכם
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
public class Fighter : MonoBehaviour
{
public float comboWindow = 1f;
public TMP_Text comboText;
public Transform flame;
private int combo;
private float sinceHit;
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
combo++;
sinceHit = 0f;
comboText.text = "Combo x" + combo;
flame.localScale = Vector3.one * (0.5f + 0.25f * combo);
}
else if (combo > 0)
{
sinceHit += Time.deltaTime;
if (sinceHit > comboWindow)
{
combo = 0;
comboText.text = "";
flame.localScale = Vector3.one * 0.5f;
}
}
}
}
כל השיעורים ביחידה ארכיטקטורת משחקים ב-Unity
1רכיבים, לא היררכיות
רכיבים קטניםסקריפט בסיסי לאויברכיבים מופשטיםרכיבים שפועלים יחדחזרה: צריח מודולריחזרה: תותח כפול4נתונים שעברו סריאליזציה
מחלקות שניתנות לסריאליזציהרשימות ב־Inspectorטיפוסי Enum ב־Inspectorחזרה: טבלת שללהגרלת השלל2ממשקים ב-Unity
IDamageableממשקים ו-TryGetComponentGetComponentsסיכום: מקש אינטראקציהסיכום: הקרוב ביותר בטווחתרגלו בעצמכם: Unity אונליין