Menu
CoddyTech

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.

challenge icon

Défi

Moyen
  1. Dans TowerData, ajoute les entiers publics maxLevel, upgradeCost et damagePerLevel, ainsi que le flottant public rangePerLevel. Ajoute int DamageAt(int level) et float 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. Ajoute int UpgradeCost(int level), le prix pour passer de ce niveau au suivant : upgradeCost multiplié par le niveau.
  2. Dans Tower, conserve un entier privé level qui commence à 1, accessible en lecture comme public int Level => level;. Tire avec DamageAt(level) et vise les cibles dans une portée de RangeAt(level). Ajoute public void Upgrade(), qui augmente le niveau de 1.
  3. 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). Le towerPanel sérialisé s'affiche uniquement lorsqu'une tour est sélectionnée, avec Arrow level 1 dans towerNameText, Damage 2 > 3 et Range 4.5 > 5 sur deux lignes dans towerStatsText, et Upgrade 40 dans upgradeLabel. Au maxLevel, les statistiques affichent uniquement les valeurs actuelles, le libellé indique Max level et upgradeButton n'est pas interactif.
  4. É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 dans Update.

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);
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Jeu Unity : défense de tours