Verbessern
Lektion 12 von 18 im Kurs Unity-Spiel: Tower Defense von Coddy.
Wenn du auf einen Turm klickst, öffnet sich ein Fenster mit seiner Stufe und einer Schaltfläche „Upgrade“. Jede Stufe erhöht den Schaden und die Reichweite des Turms, und jedes Upgrade kostet mehr als das vorherige. Die Stufen folgen einer Regel, daher enthält das Asset die Regel statt einer Zahlenliste: die Werte auf Stufe 1, was jede Stufe hinzufügt und den Preis eines Upgrades. Methoden auf dem ScriptableObject berechnen den Rest, sodass jedes Skript, das danach fragt, dieselbe Antwort erhält. Das Erntewachstum in einem Farmspiel:
public int YieldAt(int level)
{
return baseYield + yieldPerLevel * (level - 1);
}Der Turm speichert nur seine eigene level, und das Fenster zeigt die Werte der nächsten Stufe neben den aktuellen, sodass der Spieler sieht, wofür das Geld ausgegeben wird. Ein Klick auf einen Turm trifft eines seiner Teile, den Sockel oder den Kopf, die Kinder des Turms sind. Deshalb findet hit.collider.GetComponentInParent<Tower>() den Turm, zu dem sie gehören: Es sucht am getroffenen Objekt und dann weiter oben in dessen Elternobjekten.
Das Fenster ist eine Benutzeroberfläche über der 3D-Ansicht, und ein Klick auf die Upgrade-Schaltfläche ist auch ein Mausklick, den der BuildManager mitbekommt. Sein Strahl geht durch die Schaltfläche bis zum Boden dahinter, und der BuildManager schließt das Fenster, bevor die Schaltfläche losgelassen wird. EventSystem.current.IsPointerOverGameObject() ist wahr, während sich der Zeiger über der Benutzeroberfläche befindet. Daher kehrt der BuildManager vorzeitig zurück und überlässt diese Klicks den Schaltflächen.
Aufgabe
Mittel- Füge in
TowerDatadie öffentlichen int-FeldermaxLevel,upgradeCostunddamagePerLevelsowie das öffentliche float-FeldrangePerLevelhinzu. Fügeint DamageAt(int level)undfloat RangeAt(int level)hinzu: Auf Level 1 gelten der eigene Schaden und die eigene Reichweite des Assets, und jedes darüberliegende Level erhöht sie um den Betrag pro Level. Fügeint UpgradeCost(int level)hinzu, den Preis für den Aufstieg von diesem Level:upgradeCostmultipliziert mit dem Level. - Behalte in
Towerein privates int-Feldlevel, das bei 1 beginnt und überpublic int Level => level;lesbar ist. Feuere mitDamageAt(level)und ziele innerhalb vonRangeAt(level). Fügepublic void Upgrade()hinzu, das das Level um 1 erhöht. - In
BuildManagerwählt ein Klick auf einen Turm diesen aus, und ein Klick auf etwas anderes wählt nichts aus (ein Klick auf ein freies Feld baut weiterhin darauf). Das serialisiertetowerPanelwird nur angezeigt, wenn ein Turm ausgewählt ist, mitArrow level 1intowerNameText,Damage 2 > 3undRange 4.5 > 5in zwei Zeilen intowerStatsTextsowieUpgrade 40inupgradeLabel. BeimaxLevelzeigen die Werte nur die aktuellen Werte an, die Beschriftung lautetMax levelundupgradeButtonist nicht anklickbar. - Schreibe
public void UpgradeSelected(), das von der Upgrade-Schaltfläche aufgerufen wird: Unterhalb des höchsten Levels soll der Turm verbessert und das Panel aktualisiert werden, wenn der GameManager die Kosten für das Upgrade bezahlen kann. Ignoriere inUpdateKlicks auf die UI.
Drücke Play, baue einen Turm, klicke darauf und verbessere ihn, dann Check.
Probier es selbst
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);
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.