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.
Desafío
Intermedio- En
TowerData, añade los enteros públicosmaxLevel,upgradeCostydamagePerLevel, y el float públicorangePerLevel. Añadeint DamageAt(int level)yfloat 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ñadeint UpgradeCost(int level), el precio de subir desde ese nivel:upgradeCostmultiplicado por el nivel. - En
Tower, mantén un entero privadolevelque empieza en 1 y que se pueda leer comopublic int Level => level;. Dispara conDamageAt(level)y busca objetivos dentro deRangeAt(level). Añadepublic void Upgrade(), que suma 1 al nivel. - 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). EltowerPanelserializado solo se muestra mientras haya una torre seleccionada, conArrow level 1entowerNameText,Damage 2 > 3yRange 4.5 > 5en dos líneas entowerStatsText, yUpgrade 40enupgradeLabel. EnmaxLevel, las estadísticas muestran solo los valores actuales, la etiqueta diceMax levelyupgradeButtonno es interactuable. - 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 enUpdate.
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);
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.