Menu
CoddyTech

Mejorar

Lección 12 de 18 del curso Juego de Unity: defensa de torres de Coddy.

Al hacer clic en una torre, se abre un panel con su nivel y un botón de mejora. Cada nivel aumenta el daño y el alcance de la torre, y cada mejora cuesta más que la anterior. Los niveles siguen una regla, así que el recurso contiene la regla en lugar de una lista de números: las estadísticas del nivel 1, lo que añade cada nivel y el precio de una mejora. Los métodos del ScriptableObject calculan el resto, así que todos los scripts que lo consultan obtienen la misma respuesta. El cultivo de un juego de granja:

public int YieldAt(int level)
{
    return baseYield + yieldPerLevel * (level - 1);
}

La torre solo guarda su propio level, y el panel muestra los números del siguiente nivel junto a los actuales, para que el jugador vea qué obtiene por su dinero. Al hacer clic en una torre, se alcanza una de sus partes, la base o la cabeza, que son objetos secundarios de la torre; por eso, hit.collider.GetComponentInParent<Tower>() encuentra la torre a la que pertenecen: busca en el objeto alcanzado y luego en sus objetos principales.

El panel es una interfaz superpuesta a la vista 3D, y hacer clic en su botón de mejora también es una pulsación del ratón que detecta el BuildManager. Su rayo atraviesa el botón hasta el suelo que hay detrás, y el BuildManager cierra el panel antes de que se suelte el botón. EventSystem.current.IsPointerOverGameObject() es true mientras el puntero está sobre la interfaz, así que el BuildManager retorna antes y deja esos clics a los botones.

challenge icon

Desafío

Intermedio
  1. En TowerData, añade los enteros públicos maxLevel, upgradeCost y damagePerLevel, y el float público rangePerLevel. Añade int DamageAt(int level) y float RangeAt(int level): el nivel 1 tiene el daño y el alcance propios del recurso, y cada nivel superior añade la cantidad correspondiente por nivel. Añade int UpgradeCost(int level), el precio de subir desde ese nivel: upgradeCost multiplicado por el nivel.
  2. En Tower, mantén un entero privado level que empieza en 1 y que se pueda leer como public int Level => level;. Dispara con DamageAt(level) y busca objetivos dentro de RangeAt(level). Añade public void Upgrade(), que suma 1 al nivel.
  3. En BuildManager, al hacer clic en una torre se selecciona, y al hacer clic en cualquier otra cosa no se selecciona nada (un clic en una plataforma libre aun así construye en ella). El towerPanel serializado solo se muestra mientras haya una torre seleccionada, con Arrow level 1 en towerNameText, Damage 2 > 3 y Range 4.5 > 5 en dos líneas en towerStatsText, y Upgrade 40 en upgradeLabel. En maxLevel, las estadísticas muestran solo los valores actuales, la etiqueta dice Max level y upgradeButton no es interactuable.
  4. Escribe public void UpgradeSelected(), que es lo que llama el botón Upgrade: por debajo del nivel máximo, cuando GameManager pueda pagar la mejora, mejora la torre y actualiza el panel. Ignora los clics sobre la interfaz en Update.

Pulsa Play, construye una torre, haz clic en ella y mejórala; después, pulsa Check.

Pruébalo tú mismo

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);
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Juego de Unity: defensa de torres