שדרוג
שיעור 12 מתוך 18 בקורס משחק Unity: הגנת מגדלים של Coddy.
לחיצה על מגדל פותחת חלונית עם הרמה שלו וכפתור שדרוג. כל רמה מוסיפה לנזק ולטווח של המגדל, וכל שדרוג עולה יותר מהקודם. הרמות פועלות לפי כלל, ולכן הנכס מכיל את הכלל ולא רשימת מספרים: הנתונים ברמה 1, מה שכל רמה מוסיפה ומחירו של שדרוג. המתודות ב־ScriptableObject מחשבות את השאר, כך שכל סקריפט ששואל מקבל את אותה תשובה. היבול במשחק חווה:
public int YieldAt(int level)
{
return baseYield + yieldPerLevel * (level - 1);
}המגדל שומר רק את ה־level שלו, והחלונית מציגה את המספרים של הרמה הבאה לצד המספרים הנוכחיים, כך שהשחקן רואה על מה הכסף שלו הולך. לחיצה על מגדל פוגעת באחד החלקים שלו, בבסיס או בראש, שהם ילדים של המגדל, ולכן hit.collider.GetComponentInParent<Tower>() מוצא את המגדל שאליו הם שייכים: הוא מחפש באובייקט שנפגע, ואז עולה להורים שלו.
החלונית היא ממשק משתמש שמוצג מעל תצוגת התלת־ממד, ולחיצה על כפתור השדרוג שלה היא גם לחיצת עכבר ש־BuildManager מזהה. הקרן שלו עוברת דרך הכפתור אל הקרקע שמאחוריו, ו־BuildManager סוגר את החלונית לפני שחרור הכפתור. EventSystem.current.IsPointerOverGameObject() מחזיר true כשהמצביע נמצא מעל ממשק המשתמש, ולכן BuildManager חוזר מיד ומשאיר את הלחיצות האלה לכפתורים.
אתגר
בינוני- ב־
TowerData, הוסף את המשתנים הציבוריים מסוג intmaxLevel,upgradeCostו־damagePerLevel, ואת המשתנה הציבורי מסוג floatrangePerLevel. הוסף אתint DamageAt(int level)ואתfloat RangeAt(int level): ברמה 1 נעשה שימוש בנזק ובטווח המקוריים של הנכס, ובכל רמה מעליה מתווסף הערך לכל רמה. הוסף אתint UpgradeCost(int level), המחיר של מעבר מהרמה הזו לבאה אחריה:upgradeCostכפול הרמה. - ב־
Tower, שמור משתנה פרטי מסוג int בשםlevelשמתחיל ב־1, ושניתן לקרוא את ערכו באמצעותpublic int Level => level;. בצע ירי באמצעותDamageAt(level)וכוון למטרות שנמצאות בטווחRangeAt(level). הוסף אתpublic void Upgrade(), שמוסיף 1 לרמה. - ב־
BuildManager, לחיצה על מגדל בוחרת אותו, ולחיצה על כל דבר אחר אינה בוחרת דבר (לחיצה על משטח פנוי עדיין בונה עליו). החלונית המסודרתtowerPanelמוצגת רק כאשר נבחר מגדל, ובה מופיעיםArrow level 1בתוךtowerNameText, הערכיםDamage 2 > 3ו־Range 4.5 > 5בשתי שורות בתוךtowerStatsText, ו־Upgrade 40בתוךupgradeLabel. ברמהmaxLevel, הנתונים מציגים רק את הערכים הנוכחיים, התווית מציגהMax levelו־upgradeButtonאינו ניתן ללחיצה. - כתוב את
public void UpgradeSelected(), שאותו מפעיל כפתור Upgrade: מתחת לרמה המרבית, אם GameManager יכול לשלם על השדרוג, שדרג את המגדל ורענן את החלונית. התעלם מלחיצות על ממשק המשתמש בתוךUpdate.
לחץ על Play, בנה מגדל, לחץ עליו ושדרג אותו, ואז לחץ על Check.
נסו בעצמכם
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using TMPro;
public class BuildManager : MonoBehaviour
{
[SerializeField] private GameManager game;
[SerializeField] private Tower[] shop;
[SerializeField] private Button[] shopButtons;
[SerializeField] private Color chosenColor = new Color(1f, 0.85f, 0.3f);
private Tower chosen;
void Start()
{
for (int i = 0; i < shop.Length; i++)
{
Tower prefab = shop[i];
shopButtons[i].GetComponentInChildren<TMP_Text>().text = prefab.data.towerName + "\n" + prefab.data.cost;
shopButtons[i].onClick.AddListener(() => Choose(prefab));
}
Choose(shop[0]);
}
void Choose(Tower prefab)
{
chosen = prefab;
for (int i = 0; i < shop.Length; i++)
{
shopButtons[i].image.color = shop[i] == chosen ? chosenColor : Color.white;
}
}
void Update()
{
if (!Mouse.current.leftButton.wasPressedThisFrame)
{
return;
}
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider.TryGetComponent(out BuildPad pad))
{
Build(pad);
}
}
void Build(BuildPad pad)
{
if (pad.tower != null)
{
return;
}
if (!game.TrySpend(chosen.data.cost))
{
Debug.Log("Not enough money");
return;
}
pad.tower = Instantiate(chosen, pad.transform.position, Quaternion.identity);
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.