Amélioration
Leçon 12 sur 18 du cours Jeu Unity : défense de tours de Coddy.
Cliquer sur une tour ouvre un panneau indiquant son niveau et proposant un bouton d’amélioration. Chaque niveau augmente les dégâts et la portée de la tour, et chaque amélioration coûte plus cher que la précédente. Les niveaux suivent une règle : l’asset contient donc la règle plutôt qu’une liste de nombres : les statistiques au niveau 1, ce que chaque niveau ajoute et le prix d’une amélioration. Les méthodes du ScriptableObject calculent le reste, de sorte que chaque script qui le demande obtient la même réponse. La récolte d’une culture dans un jeu de ferme :
public int YieldAt(int level)
{
return baseYield + yieldPerLevel * (level - 1);
}La tour ne conserve que son propre level, et le panneau affiche les chiffres du niveau suivant à côté de ceux du niveau actuel, afin que le joueur voie ce que lui coûtent ses pièces. Un clic sur une tour touche l’une de ses parties, la base ou la tête, qui sont des enfants de la tour ; hit.collider.GetComponentInParent<Tower>() trouve donc la tour à laquelle elles appartiennent : il cherche sur l’objet touché, puis remonte dans ses parents.
Le panneau est une interface superposée à la vue 3D, et un clic sur son bouton d’amélioration est également une pression de souris que BuildManager détecte. Son rayon traverse le bouton jusqu’au sol derrière, et BuildManager ferme le panneau avant que le bouton de la souris ne soit relâché. EventSystem.current.IsPointerOverGameObject() vaut true lorsque le pointeur se trouve au-dessus de l’interface ; BuildManager retourne donc immédiatement et laisse ces clics aux boutons.
Défi
Moyen- Dans
TowerData, ajoute les entiers publicsmaxLevel,upgradeCostetdamagePerLevel, ainsi que le flottant publicrangePerLevel. Ajouteint DamageAt(int level)etfloat RangeAt(int level): au niveau 1, l'objet possède ses propres dégâts et sa propre portée, et chaque niveau supplémentaire ajoute la quantité par niveau. Ajouteint UpgradeCost(int level), le prix pour passer de ce niveau au suivant :upgradeCostmultiplié par le niveau. - Dans
Tower, conserve un entier privélevelqui commence à 1, accessible en lecture commepublic int Level => level;. Tire avecDamageAt(level)et vise les cibles dans une portée deRangeAt(level). Ajoutepublic void Upgrade(), qui augmente le niveau de 1. - Dans
BuildManager, un clic sur une tour la sélectionne, et un clic sur tout autre élément ne sélectionne rien (un clic sur une plateforme libre permet toujours d'y construire). LetowerPanelsérialisé s'affiche uniquement lorsqu'une tour est sélectionnée, avecArrow level 1danstowerNameText,Damage 2 > 3etRange 4.5 > 5sur deux lignes danstowerStatsText, etUpgrade 40dansupgradeLabel. AumaxLevel, les statistiques affichent uniquement les valeurs actuelles, le libellé indiqueMax leveletupgradeButtonn'est pas interactif. - Écris
public void UpgradeSelected(), appelée par le bouton Upgrade : en dessous du niveau maximal, si le GameManager peut payer l'amélioration, améliore la tour et actualise le panneau. Ignore les clics sur l'interface utilisateur dansUpdate.
Appuie sur Play, construis une tour, clique dessus et améliore-la, puis Check.
Essayez vous-même
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);
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.