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
Medium- In
TowerData.cs, make TowerData creatable with the menu nameTower Defense/Tower Data, with the public fieldstowerName(a string),costanddamage(ints),rangeandfireRate(floats). - In
Tower, replacecost,range,damageandfireRatewith one public fielddata(a TowerData), and use the asset's values. - In
BuildManager, replacetowerPrefabwith two serialized arrays:shop(Tower prefabs) andshopButtons(Buttons, in the same order). InStart, set each button's TMP_Text child to its tower's name and cost on two lines, asArrow\n50, and make a click on the button choose that tower. The first tower, the Arrow, is chosen at the start. - 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);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.