Улучшение
Урок 12 из 18 курса Игра в Unity: защита башен на Coddy.
При нажатии на башню открывается панель с её уровнем и кнопкой улучшения. Каждый уровень увеличивает урон и дальность башни, а каждое улучшение стоит дороже предыдущего. Уровни подчиняются правилу, поэтому ресурс содержит само правило, а не список чисел: характеристики на уровне 1, прибавка за каждый уровень и цена улучшения. Методы в ScriptableObject вычисляют всё остальное, поэтому каждый скрипт, который запрашивает данные, получает одинаковый ответ. Урожай в игре про фермерство:
public int YieldAt(int level)
{
return baseYield + yieldPerLevel * (level - 1);
}Башня хранит только свой level, а панель показывает числа для следующего уровня рядом с текущими, чтобы игрок видел, на что тратятся деньги. При нажатии на башню щелчок попадает в одну из её частей — основание или верхушку, которые являются дочерними объектами башни, — поэтому hit.collider.GetComponentInParent<Tower>() находит башню, которой они принадлежат: сначала проверяет объект, в который попал щелчок, затем его родительские объекты.
Панель — это UI поверх 3D-вида, и нажатие кнопки улучшения также является нажатием мыши, которое видит BuildManager. Луч проходит сквозь кнопку к земле за ней, а BuildManager закрывает панель до того, как кнопка будет отпущена. EventSystem.current.IsPointerOverGameObject() возвращает true, пока указатель находится над UI, поэтому BuildManager сразу завершает выполнение и оставляет эти нажатия кнопкам.
Задание
Средне- В
TowerDataдобавь публичные целые числаmaxLevel,upgradeCostиdamagePerLevel, а также публичное число с плавающей точкойrangePerLevel. Добавьint DamageAt(int level)иfloat RangeAt(int level): на уровне 1 используются собственные значения урона и дальности актива, а каждый следующий уровень прибавляет значение за уровень. Добавьint UpgradeCost(int level)— цену перехода с этого уровня на следующий:upgradeCost, умноженное на уровень. - В
Towerхрани приватное целое числоlevel, начинающееся с 1, и предоставь к нему доступ для чтения черезpublic int Level => level;. Стреляй с урономDamageAt(level)и выбирай цель в пределахRangeAt(level). Добавьpublic void Upgrade(), увеличивающий уровень на 1. - В
BuildManagerщелчок по башне выбирает её, а щелчок по любому другому объекту ничего не выбирает (щелчок по свободной площадке всё ещё строит на ней башню). Сериализованная панельtowerPanelотображается только при выбранной башне; вtowerNameTextпоказываетсяArrow level 1, вtowerStatsTextв двух строках —Damage 2 > 3иRange 4.5 > 5, а вupgradeLabel—Upgrade 40. При достиженииmaxLevelотображаются только текущие значения характеристик, подпись гласитMax level, а кнопкаupgradeButtonнедоступна для нажатия. - Напиши
public void UpgradeSelected(), которую вызывает кнопка Upgrade: если башня не достигла максимального уровня и GameManager может оплатить улучшение, улучши башню и обнови панель. ВUpdateигнорируй щелчки по элементам интерфейса.
Нажми Play, построй башню, щёлкни по ней и улучши её, затем нажми Check.
Попробуйте сами
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);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.