Menu
CoddyTech

Tower Types

Lesson 11 of 18 in Coddy's Unity Game: Tower Defense course.

A second tower joins the game: the Cannon, slow and heavy. Its numbers differ from the Arrow's, and with more towers to come they move into TowerData assets, as the enemies' stats did. The prefab keeps what the tower looks like, and its Tower script points at its asset. The shop then builds itself from data: for each tower prefab, a button shows the name and the price, and a click on it chooses that tower for the next pad.

Buttons made in a loop get their listeners in the loop, with a lambda. A lambda captures variables, not their values, and a for loop has one i for all its turns. Clicked later, every button's lambda reads that same i, which has run past the end by then. A level menu with the bug:

for (int i = 0; i < levels.Length; i++)
{
    levelButtons[i].onClick.AddListener(() => Load(levels[i]));
}

Every one of those buttons throws an IndexOutOfRangeException when clicked, because i equals levels.Length once the loop is over. A local variable declared inside the loop is a new variable on every turn, so a lambda that captures it keeps its own: copy levels[i] into a local first, and use the local in the lambda.

challenge icon

Challenge

Medium
  1. In TowerData.cs, make TowerData creatable with the menu name Tower Defense/Tower Data, with the public fields towerName (a string), cost and damage (ints), range and fireRate (floats).
  2. In Tower, replace cost, range, damage and fireRate with one public field data (a TowerData), and use the asset's values.
  3. In BuildManager, replace towerPrefab with two serialized arrays: shop (Tower prefabs) and shopButtons (Buttons, in the same order). In Start, set each button's TMP_Text child to its tower's name and cost on two lines, as Arrow\n50, and make a click on the button choose that tower. The first tower, the Arrow, is chosen at the start.
  4. Tint the chosen tower's button with a serialized Color chosenColor (new Color(1f, 0.85f, 0.3f)) and the other buttons white. A free pad gets the chosen tower, for the chosen tower's cost.

The ArrowData and CannonData assets are made, and the ShopPanel at the bottom holds the two buttons. Press Play, build both kinds, then Check.

Try it yourself

using UnityEngine;
using UnityEngine.InputSystem;

public class BuildManager : MonoBehaviour
{
    [SerializeField] private GameManager game;
    [SerializeField] private Tower towerPrefab;

    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(towerPrefab.cost))
        {
            Debug.Log("Not enough money");
            return;
        }

        pad.tower = Instantiate(towerPrefab, pad.transform.position, Quaternion.identity);
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Unity Game: Tower Defense