Menu
CoddyTech

Ulepszanie

Lekcja 12 z 18 w kursie Gra Unity: Obrona wieżowa w Coddy.

Po kliknięciu wieży otwiera się panel z jej poziomem i przyciskiem Ulepsz. Każdy poziom zwiększa obrażenia i zasięg wieży, a każde ulepszenie kosztuje więcej niż poprzednie. Poziomy podlegają regule, więc zasób przechowuje regułę zamiast listy liczb: statystyki na poziomie 1, wartość dodawaną na każdym poziomie oraz cenę ulepszenia. Metody w obiekcie ScriptableObject obliczają resztę, dzięki czemu każdy skrypt, który o nie pyta, otrzymuje tę samą odpowiedź. Uprawa w grze rolniczej:

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

Wieża przechowuje tylko swój własny level, a panel wyświetla wartości dla następnego poziomu obok bieżących, dzięki czemu gracz widzi, na co wydaje pieniądze. Kliknięcie wieży trafia w jedną z jej części — podstawę lub głowicę — które są obiektami potomnymi wieży, więc hit.collider.GetComponentInParent<Tower>() znajduje wieżę, do której należą: szuka na trafionym obiekcie, a następnie w jego obiektach nadrzędnych.

Panel interfejsu użytkownika znajduje się nad widokiem 3D, a kliknięcie jego przycisku Ulepsz jest również naciśnięciem myszy, które wykrywa BuildManager. Promień przechodzi przez przycisk i trafia w podłoże za nim, a BuildManager zamyka panel, zanim przycisk myszy zostanie zwolniony. EventSystem.current.IsPointerOverGameObject() ma wartość true, gdy wskaźnik znajduje się nad interfejsem użytkownika, więc BuildManager kończy działanie wcześniej i pozostawia te kliknięcia przyciskom.

challenge icon

Wyzwanie

Średni
  1. W TowerData dodaj publiczne wartości typu int: maxLevel, upgradeCost i damagePerLevel, a także publiczną wartość typu float: rangePerLevel. Dodaj int DamageAt(int level) i float RangeAt(int level): na poziomie 1 obowiązują własne obrażenia i zasięg zasobu, a każdy kolejny poziom dodaje wartość przypadającą na poziom. Dodaj int UpgradeCost(int level), czyli cenę awansu z danego poziomu: upgradeCost pomnożone przez poziom.
  2. W Tower zachowaj prywatną wartość typu int level, która zaczyna od 1 i jest dostępna do odczytu jako public int Level => level;. Strzelaj, używając DamageAt(level), i namierzaj w obrębie RangeAt(level). Dodaj public void Upgrade(), która zwiększa poziom o 1.
  3. W BuildManager kliknięcie wieży wybiera ją, a kliknięcie czegokolwiek innego niczego nie wybiera (kliknięcie wolnego pola budowy nadal buduje na nim wieżę). Serializowany towerPanel jest widoczny tylko wtedy, gdy wybrano wieżę; w towerNameText wyświetla Arrow level 1, w towerStatsText — w dwóch wierszach Damage 2 > 3 i Range 4.5 > 5, a w upgradeLabel — Upgrade 40. Na poziomie maxLevel statystyki pokazują tylko bieżące wartości, etykieta wyświetla Max level, a przycisk upgradeButton jest nieaktywny.
  4. Napisz public void UpgradeSelected(), wywoływaną przez przycisk Upgrade: poniżej maksymalnego poziomu, gdy GameManager może opłacić ulepszenie, ulepsz wieżę i odśwież panel. W metodzie Update ignoruj kliknięcia w obszarze interfejsu.

Naciśnij Play, zbuduj wieżę, kliknij ją i ulepsz, a następnie naciśnij Check.

Spróbuj swoich sił

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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Gra Unity: Obrona wieżowa