Skip to main content

Stage 8: Gold Mines and a Heavier Tower

Course progressStage 8 of 10
~50 min
Build

a Gold Mine that earns gold and a heavier Cannon Tower

Learn

how to reuse your tower and shooter scripts for new units just by changing numbers

Ship

three buildable units with real trade-offs

The big idea

Right now you can build one kind of tower, and gold only trickles in on its own. A real tower-defense game gives the player choices: a cheap fast tower, a slow heavy hitter, a building that earns money. Those choices are what make the game a game.

Here's the part that surprises people. You don't write a new script for every new unit. Your TowerShooter and Projectile scripts already do the work — they fire a thing at an interval and deal damage. A Cannon Tower is just those same scripts with different numbers: more damage, slower fire rate. The behavior is code; the personality is data — the values you type into the Inspector. One script, many units.

To let the player pick which unit to place, we need two new small scripts. GoldMine earns gold on a timer. TowerSelector remembers which unit the player clicked in a menu, so a tile knows what to build when you click it.

New words
Data vs. code
Code is the behavior (a script). Data is the numbers that tune it (Inspector values). Same code + different data = a different unit.
Static field
A variable that belongs to the class itself, not to one object. There's exactly one copy, so any script can read it — perfect for 'which tower is selected right now'.
UI Button OnClick
A list on a Button that calls a method when the button is clicked. We wire it to TowerSelector.Select.
Before you start

Finish Stage 7 — you need working TileSlot, GameManager, TowerShooter, and Projectile scripts, and at least one tower you can already place.

Build it

Step 1 — Build a Gold Mine

The Gold Mine is a building the player places to earn extra gold over time. It's the same idea as the GameManager trickle, but the player chooses to invest in it. We build the script in three passes.

Pass 1 — prove the timer runs. Add the script to a new GameObject and start with a heartbeat:

using UnityEngine;

public class GoldMine : MonoBehaviour
{
public int goldPerTick = 10;
public float interval = 3f;

void Start()
{
InvokeRepeating(nameof(Payout), interval, interval);
}

void Payout()
{
Debug.Log("Gold Mine payout");
}
}

Press Play. Every 3 seconds the Console prints Gold Mine payout. That tells you InvokeRepeating is calling Payout on a schedule. Stop.

Pass 2 — actually pay out. Now hand that gold to the GameManager. Replace the body of Payout:

Script anatomy

The full script, line by line

The finished Gold Mine: it pays gold into the shared GameManager on a repeating timer.

using UnityEngine;

public class GoldMine : MonoBehaviour
{
public int goldPerTick = 10;
public float interval = 3f;

void Start()
{
InvokeRepeating(nameof(Payout), interval, interval);
}

void Payout()
{
if (GameManager.instance != null)
GameManager.instance.AddGold(goldPerTick);
}
}
  1. Lines 4–5Two tuning knobs

    goldPerTick is how much each payout is worth; interval is how many seconds between payouts. Both are public, so a fast-but-stingy mine and a slow-but-rich mine are the same script with different numbers.

  2. Line 9InvokeRepeating schedules the timer

    It calls Payout once after 'interval' seconds, then every 'interval' seconds after that. nameof(Payout) is just the method's name as text, which is safer than typing a string.

  3. Lines 14–15Null check before paying

    If there's no GameManager in the Scene, GameManager.instance is null. We check first so the game never crashes trying to add gold to nothing.

Press Play and watch your gold counter climb in steps. Pass 3 — tune it. While it plays, change interval to 1 and goldPerTick to 5. Same script, totally different feel: now it drips small amounts quickly. Pick values that feel like a fair investment.

Build this GameObject

Gold Mine prefab

2D Sprite
Open recipe
Sprite
a coin/chest-style building sprite from your sliced tilemap
Gold Per Tick
10
Interval
3
Order in Layer
2 (in front of the courtyard)
Components to add
  • Sprite Renderer
  • GoldMine

Make it a prefab the same way you did your tower: drag it from the Hierarchy into the Project panel, then delete the one in the Scene. The player will place it on a tile.

Step 2 — Build a Cannon Tower with no new code

Here's the big payoff. A Cannon Tower is slower than your archer tower but hits much harder. You will not write a single new line of code for it — you'll reuse TowerShooter and Projectile and just change numbers.

First make a heavier projectile. Duplicate your arrow projectile, swap its sprite for a cannonball, and raise its damage.

Build this GameObject

Cannonball prefab

2D Sprite
Open recipe
Sprite
a round cannonball/rock sprite from your sliced tilemap
Speed
6
Damage
3 (an arrow was 1)
Components to add
  • Sprite Renderer
  • Rigidbody2D (Kinematic)
  • Collider2D (Is Trigger)
  • Projectile

Same Projectile.cs as your arrow. The only difference is the sprite and a bigger Damage value — that's data, not code.

Now make the tower that fires it. It's your existing tower with a different sprite, the Cannonball assigned, and a slower fire rate.

Build this GameObject

Cannon Tower prefab

2D Sprite
Open recipe
Sprite
a bulkier cannon/turret sprite from your sliced tilemap
Projectile Prefab
your Cannonball prefab
Fire Point
a child transform at the muzzle
Fire Rate
1.5 (the archer was ~0.5 — slower)
Components to add
  • Sprite Renderer
  • TowerShooter

Same TowerShooter.cs as your archer tower. Higher Fire Rate = longer wait between shots. Make it a prefab. NEW UNIT, NO NEW CODE — the trade-off lives entirely in the numbers.

Press Play, place the Cannon, and watch: it fires rarely, but each hit takes a big bite out of a slime. That's a real trade-off the player has to think about.

Step 3 — Let the player choose with a TowerSelector

You now have two towers and a mine, but a tile can only build one fixed thing. We fix that with a tiny script that remembers the player's choice. Build it in two passes.

Pass 1 — log the selection. Make the script and prove the button calls it:

using UnityEngine;

public class TowerSelector : MonoBehaviour
{
public GameObject towerPrefab;
public int cost = 50;

public void Select()
{
Debug.Log("Selected a unit");
}
}

Pass 2 — set the static fields. Now store the choice where any tile can read it:

Script anatomy

The full script, line by line

The finished selector: clicking a menu button stores which unit (and its cost) is currently chosen.

using UnityEngine;

public class TowerSelector : MonoBehaviour
{
public static GameObject selectedTower;
public static int selectedCost;
public GameObject towerPrefab;
public int cost = 50;

public void Select()
{
selectedTower = towerPrefab;
selectedCost = cost;
}
}
  1. Lines 5–6Static = one shared answer

    selectedTower and selectedCost are static, so there's a single copy for the whole game. Any TileSlot can ask 'what's selected right now?' without holding a reference to the menu.

  2. Lines 7–8Per-button data

    towerPrefab and cost are normal public fields. You'll put one TowerSelector on each menu button and set these to that button's unit.

  3. Lines 12–13Select copies data into the static slots

    When the button is clicked, Select() copies that button's unit and cost into the shared static fields. Now the next tile click builds this unit.

Add one menu Button per buildable unit (Archer, Cannon, Gold Mine). Put a TowerSelector on each button, set its towerPrefab and cost, and wire the Button's OnClick to call that TowerSelector.Select.

Build this GameObject

Tower-select Buttons (UI)

UI > Button (one per buildable)
Open recipe
Sprite
the unit's icon on the button (optional)
Tower Prefab
the unit this button builds (Archer / Cannon / Gold Mine)
Cost
50 archer / 100 cannon / 75 mine (tune these)
OnClick
this same object → TowerSelector.Select
Components to add
  • Button
  • TowerSelector

Three buttons, three TowerSelectors, three sets of numbers. The OnClick list calls Select() with no arguments. Right-click the Hierarchy → UI → Button to create each one inside the Canvas.

Finally, switch TileSlot to build whatever is selected instead of a fixed tower. Replace the body of OnMouseDown:

void OnMouseDown()
{
if (occupied) return;
if (TowerSelector.selectedTower == null) return;
if (GameManager.instance.SpendGold(TowerSelector.selectedCost))
{
Instantiate(TowerSelector.selectedTower, transform.position, Quaternion.identity);
occupied = true;
}
}

Press Play. Click a menu button to pick a unit, then click an empty tile to build it. Pick a different button and build a different unit on the next tile.

Understand it

The lesson of this stage is data, not code. Your archer and your cannon run the identical TowerShooter and Projectile scripts — the only difference is the numbers in the Inspector and the sprite. This is how real games ship dozens of weapons or enemies without dozens of scripts. When you find yourself about to copy a whole script just to change a couple of values, stop: make those values public fields and tune them instead.

We used a static field for the selection on purpose. The alternative is wiring every tile to the menu by hand, which breaks the moment you add a tile. A static field is a single shared answer the whole game can read, which is exactly right for "what is selected." Use static sparingly — it's global state — but "the one current selection" is a textbook fit.

Try this

Learning beat

Try this

Three short experiments. Predict before you run, then test your guess.

Predict first

You set the Cannon's Fire Rate to 1.5 and Damage to 3. Before you play, decide: against a fast slime that crosses in 2 seconds, will one Cannon alone be enough, or will the slow fire rate let some slip past? Run it and watch.

Compare

Build an all-archer defense, then an all-cannon defense, against the same wave. Which holds the line better? There's no single right answer — that's the point of a trade-off. Note which one feels better to play.

Connect

You just added a third buildable (the mine) by reusing the selection system, not by editing TileSlot. What other unit could you add — a wall? a slow trap? — using only a new prefab and a new button?

Test your stage

  • The Gold Mine raises your gold counter in steps while playing.
  • You can place both an Archer Tower and a Cannon Tower, and they behave differently (fast/light vs. slow/heavy).
  • Clicking a menu button changes which unit a tile builds.
  • You did not write a new shooting script for the Cannon — it reuses TowerShooter and Projectile.
  • Design check. Read your three units' costs and stats out loud. Does each one have a reason to exist? If two units feel the same, change a number until one is clearly the cheap option and one the heavy option.

If it breaks

  • Clicking a tile builds nothing. Make sure you clicked a menu button first — TileSlot now refuses to build when TowerSelector.selectedTower is still null. Also confirm the Button's OnClick actually points at TowerSelector.Select.
  • Every button builds the same unit. Each Button needs its own TowerSelector with its own towerPrefab. If they all share one selector or point at the same prefab, they'll all build the same thing.
  • The Cannon fires too fast / like an archer. Its Fire Rate is probably still the archer's value. Higher Fire Rate means a longer wait. Bump it up.
  • The Cannon does no extra damage. You likely assigned the arrow projectile to it. Assign the Cannonball prefab, and confirm the Cannonball's Damage is higher than the arrow's.
  • Gold never goes up from the mine. Check the mine is actually placed in the Scene during Play and that GameManager.instance exists (the GameManager object is in the Scene).