Menu
CoddyTech

Vender

Lección 19 de 25 del curso Juego de Unity: Defensa de torres de Coddy.

Al vender una torre, se recupera la mitad de lo que costó, incluidas las mejoras, así que mover una defensa cuesta algo, pero no todo. La torre mantiene un total acumulado del dinero que se ha gastado en ella: su precio cuando se construyó, más el precio de cada mejora a medida que se paga. El reembolso es la mitad de ese total, y una división entera lo redondea hacia abajo. Un alquiler de bicicletas mantiene el mismo tipo de total:

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

public int Deposit => paid / 4;

Al venderla, la torre se destruye y el campo tower de la plataforma sigue apuntando a ella. El operador == de Unity trata un objeto destruido como null, así que desde el siguiente fotograma pad.tower == null es true, y la plataforma vuelve a estar libre sin código adicional. El panel es otra cuestión: sigue mostrando la torre vendida, y al hacer clic en Upgrade se accedería a un objeto destruido y se lanzaría una MissingReferenceException. Al vender, no se selecciona nada, lo que oculta el panel.

challenge icon

Desafío

Intermedio

Vende una torre por la mitad de lo que costó.

  1. En Tower, conserva private int spent;: data.cost en Start, más el precio de cada mejora en Upgrade(). Añade public int SellValue => spent / 2;.
  2. En BuildManager, muestra Sell 25 (el valor de venta) en un TMP_Text serializado sellLabel cuando se complete el panel.
  3. Escribe public void SellSelected(): recupera el valor de venta, destruye la torre y no selecciona nada.

Pulsa «Jugar», después construye, mejora y vende una torre. Luego pulsa «Comprobar».

Pruébalo tú mismo

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

Todas las lecciones de Juego de Unity: Defensa de torres

Practica por tu cuenta: Playground de Unity