Verkaufen
Lektion 13 von 18 im Kurs Unity-Spiel: Tower Defense von Coddy.
Beim Verkauf eines Turms erhältst du die Hälfte seiner Kosten zurück, einschließlich der Upgrades. Eine Verteidigung zu versetzen kostet also etwas, aber nicht alles. Der Turm führt eine laufende Summe des für ihn ausgegebenen Geldes: seinen Preis beim Bau plus den Preis jedes Upgrades, sobald es bezahlt wird. Die Rückerstattung beträgt die Hälfte dieser Summe, und eine Ganzzahldivision rundet sie ab. Bei einer Fahrradvermietung wird dieselbe Art von Summe geführt:
public void ExtendRide(int extraHours)
{
paid += extraHours * pricePerHour;
}
public int Deposit => paid / 4;Beim Verkauf wird der Turm zerstört, und das Feld tower des Pads verweist weiterhin auf ihn. Unity behandelt ein zerstörtes Objekt mit == als null, daher ist ab dem nächsten Frame pad.tower == null wahr und das Pad ist ohne zusätzlichen Code wieder frei. Beim Panel ist das anders: Es zeigt weiterhin den verkauften Turm an, und ein Klick auf Upgrade würde ein zerstörtes Objekt erreichen und eine MissingReferenceException auslösen. Beim Verkauf wird nichts ausgewählt, wodurch das Panel ausgeblendet wird.
Aufgabe
Mittel- Füge in
Towerein privates int-Feldspenthinzu: die inStartfestgelegtencostdes Turms plus den Preis jedes gekauften Upgrades. Fügepublic int SellValue => spent / 2;hinzu. - Zeige in
BuildManagerimmer dann, wenn das Panel gefüllt wird, in einem serialisierten TMP_Text-FeldsellLabelSell 25an, also den Verkaufspreis des ausgewählten Turms. - Schreibe
public void SellSelected(), das der Sell-Button aufruft: Erstatte den Verkaufspreis über den GameManager, zerstöre den Turm und wähle nichts aus.
Drücke Play, baue, verbessere und verkaufe dann ein paar Türme und klicke anschließend auf Check.
Probier es selbst
using UnityEngine;
using UnityEngine.EventSystems;
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);
[SerializeField] private GameObject towerPanel;
[SerializeField] private TMP_Text towerNameText;
[SerializeField] private TMP_Text towerStatsText;
[SerializeField] private Button upgradeButton;
[SerializeField] private TMP_Text upgradeLabel;
private Tower chosen;
private Tower selected;
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]);
Select(null);
}
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 || EventSystem.current.IsPointerOverGameObject())
{
return;
}
Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
if (!Physics.Raycast(ray, out RaycastHit hit))
{
Select(null);
return;
}
Tower tower = hit.collider.GetComponentInParent<Tower>();
if (tower != null)
{
Select(tower);
return;
}
Select(null);
if (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);
}
void Select(Tower tower)
{
selected = tower;
towerPanel.SetActive(tower != null);
if (tower != null)
{
ShowPanel();
}
}
void ShowPanel()
{
TowerData data = selected.data;
int level = selected.Level;
towerNameText.text = data.towerName + " level " + level;
if (level < data.maxLevel)
{
towerStatsText.text = "Damage " + data.DamageAt(level) + " > " + data.DamageAt(level + 1)
+ "\nRange " + data.RangeAt(level) + " > " + data.RangeAt(level + 1);
upgradeLabel.text = "Upgrade " + data.UpgradeCost(level);
upgradeButton.interactable = true;
}
else
{
towerStatsText.text = "Damage " + data.DamageAt(level) + "\nRange " + data.RangeAt(level);
upgradeLabel.text = "Max level";
upgradeButton.interactable = false;
}
}
public void UpgradeSelected()
{
if (selected.Level >= selected.data.maxLevel)
{
return;
}
if (game.TrySpend(selected.data.UpgradeCost(selected.Level)))
{
selected.Upgrade();
ShowPanel();
}
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.