الترقية
الدرس 12 من 18 في دورة لعبة Unity: الدفاع عن الأبراج على Coddy.
يؤدي النقر على برج إلى فتح لوحة تعرض مستواه وزر ترقية. يضيف كل مستوى إلى ضرر البرج ومداه، وتكلف كل ترقية أكثر من سابقتها. تتبع المستويات قاعدة، لذا يحتفظ الأصل بالقاعدة بدلًا من قائمة أرقام: الإحصاءات عند المستوى 1، وما يضيفه كل مستوى، وسعر الترقية. تحسب الطرق الموجودة في ScriptableObject بقية القيم، لذا تحصل كل شيفرة تطلبها على الإجابة نفسها. محصول في لعبة مزرعة:
public int YieldAt(int level)
{
return baseYield + yieldPerLevel * (level - 1);
}يحتفظ البرج بقيمة level الخاصة به فقط، وتعرض اللوحة أرقام المستوى التالي بجوار الأرقام الحالية، ليرى اللاعب ما الذي يشتريه بالمال. يصيب النقر على برج أحد أجزائه، القاعدة أو الرأس، وهما ابنان للبرج، لذا يعثر hit.collider.GetComponentInParent<Tower>() على البرج الذي ينتميان إليه: يبحث في الكائن الذي أصابه النقر، ثم يصعد عبر آبائه.
اللوحة واجهة مستخدم فوق العرض ثلاثي الأبعاد، والنقر على زر الترقية فيها هو أيضًا ضغطة زر بالماوس يراها BuildManager. يمر شعاعه عبر الزر إلى الأرض خلفه، ويغلق BuildManager اللوحة قبل تحرير الزر. تكون EventSystem.current.IsPointerOverGameObject() صحيحة ما دام المؤشر فوق واجهة المستخدم، لذا يعود 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المُسلسلة إلا عند تحديد برج، وتعرضArrow level 1فيtowerNameText، وDamage 2 > 3وRange 4.5 > 5على سطرين فيtowerStatsText، وUpgrade 40فيupgradeLabel. عند بلوغmaxLevel، تعرض الإحصائيات القيم الحالية فقط، ويكون النصMax levelويكونupgradeButtonغير قابل للتفاعل. - اكتب
public void UpgradeSelected()، الذي يستدعيه زر الترقية: دون بلوغ المستوى الأعلى، عندما يتمكن 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);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.