Menu
CoddyTech

מכירה

שיעור 13 מתוך 18 בקורס משחק Unity: הגנת מגדלים של Coddy.

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

public void ExtendRide(int extraHours)
{
    paid += extraHours * pricePerHour;
}

public int Deposit => paid / 4;

מכירה הורסת את המגדל, והשדה tower של המשטח עדיין מצביע עליו. == של Unity מתייחס לאובייקט שהושמד כאילו הוא null, כך שהחל מהפריים הבא pad.tower == null הוא true, והמשטח שוב פנוי בלי צורך בקוד נוסף. הפאנל הוא עניין אחר: הוא עדיין מציג את המגדל שנמכר, ולחיצה על Upgrade תגיע לאובייקט שהושמד ותגרום ל-MissingReferenceException. מכירה לא בוחרת שום דבר, ולכן הפאנל מוסתר.

challenge icon

אתגר

בינוני
  1. ב־Tower, שמור משתנה int פרטי בשם spent: העלות של המגדל, המוגדרת ב־Start, בתוספת המחיר של כל שדרוג בעת רכישתו. הוסף את public int SellValue => spent / 2;.
  2. ב־BuildManager, הצג את Sell 25, ערך המכירה של המגדל שנבחר, בתוך sellLabel מסוג TMP_Text שעבר סריאליזציה, בכל פעם שהתוכן של החלונית מתעדכן.
  3. כתוב את public void SellSelected(), שאותו מפעיל כפתור Sell: החזר את ערך המכירה באמצעות GameManager, השמד את המגדל ובטל את הבחירה.

לחץ על Play, ואז בנה, שדרג ומכור כמה מגדלים, ואז לחץ על Check.

נסו בעצמכם

using UnityEngine;
using UnityEngine.EventSystems;
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);
    [SerializeField] private GameObject towerPanel;
    [SerializeField] private TMP_Text towerNameText;
    [SerializeField] private TMP_Text towerStatsText;
    [SerializeField] private Button upgradeButton;
    [SerializeField] private TMP_Text upgradeLabel;

    private Tower chosen;
    private Tower selected;

    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]);
        Select(null);
    }

    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 || EventSystem.current.IsPointerOverGameObject())
        {
            return;
        }

        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        if (!Physics.Raycast(ray, out RaycastHit hit))
        {
            Select(null);
            return;
        }

        Tower tower = hit.collider.GetComponentInParent<Tower>();
        if (tower != null)
        {
            Select(tower);
            return;
        }

        Select(null);
        if (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);
    }

    void Select(Tower tower)
    {
        selected = tower;
        towerPanel.SetActive(tower != null);
        if (tower != null)
        {
            ShowPanel();
        }
    }

    void ShowPanel()
    {
        TowerData data = selected.data;
        int level = selected.Level;
        towerNameText.text = data.towerName + " level " + level;
        if (level < data.maxLevel)
        {
            towerStatsText.text = "Damage " + data.DamageAt(level) + " > " + data.DamageAt(level + 1)
                + "\nRange " + data.RangeAt(level) + " > " + data.RangeAt(level + 1);
            upgradeLabel.text = "Upgrade " + data.UpgradeCost(level);
            upgradeButton.interactable = true;
        }
        else
        {
            towerStatsText.text = "Damage " + data.DamageAt(level) + "\nRange " + data.RangeAt(level);
            upgradeLabel.text = "Max level";
            upgradeButton.interactable = false;
        }
    }

    public void UpgradeSelected()
    {
        if (selected.Level >= selected.data.maxLevel)
        {
            return;
        }

        if (game.TrySpend(selected.data.UpgradeCost(selected.Level)))
        {
            selected.Upgrade();
            ShowPanel();
        }
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה משחק Unity: הגנת מגדלים