البيع
الدرس 13 من 18 في دورة لعبة Unity: الدفاع عن الأبراج على Coddy.
يعيد بيع البرج نصف تكلفته، بما في ذلك الترقيات، لذا فإن نقل الدفاع يكلّف شيئًا، ولكن ليس كل شيء. يحتفظ البرج بمجموع جارٍ للأموال المنفقة عليه: سعره عند بنائه، بالإضافة إلى سعر كل ترقية عند دفعه. يكون المبلغ المسترد نصف هذا المجموع، ويقرّب القسمة على عدد صحيح الناتج إلى الأسفل. يحتفظ استئجار الدراجة بالنوع نفسه من المجموع:
public void ExtendRide(int extraHours)
{
paid += extraHours * pricePerHour;
}
public int Deposit => paid / 4;يؤدي البيع إلى تدمير البرج، ويظل الحقل tower في المنصة يشير إليه. يتعامل Unity مع == على أنه يساوي null للكائن المدمّر، لذا ابتداءً من الإطار التالي تكون pad.tower == null صحيحة، وتصبح المنصة متاحة مجددًا من دون أي تعليمات برمجية إضافية. أما اللوحة فمسألة أخرى: فهي لا تزال تعرض البرج المباع، والنقر على الترقية سيصل إلى كائن مدمّر ويطرح MissingReferenceException. لا يؤدي البيع إلى تحديد أي شيء، وهذا يخفي اللوحة.
التحدي
متوسط- في
Tower، احتفظ بمتغير int خاصspent: تكلفة البرجcost، التي تُحدَّد فيStart، بالإضافة إلى تكلفة كل ترقية عند شرائها. أضفpublic int SellValue => spent / 2;. - في
BuildManager، اعرضSell 25، قيمة بيع البرج المحدد، في عنصر TMP_Text متسلسلsellLabelكلما تم ملء اللوحة. - اكتب
public void SellSelected()، التي يستدعيها زر البيع: أعد قيمة البيع عبر GameManager، ودمّر البرج، ولا تحدد أي شيء.
اضغط Play، ثم ابنِ بعض الأبراج وطوّرها وبِعها، ثم اضغط Check.
جرّب بنفسك
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();
}
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.