Stage 8: Gold Mines and a Heavier Tower
a Gold Mine that earns gold and a heavier Cannon Tower
how to reuse your tower and shooter scripts for new units just by changing numbers
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.
- 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.
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:
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);
}
}
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.
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.
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 GameObjectGold Mine prefab
2D SpriteOpen recipe
Gold Mine prefab
2D Sprite- 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)
- 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 GameObjectCannonball prefab
2D SpriteOpen recipe
Cannonball prefab
2D Sprite- Sprite
- a round cannonball/rock sprite from your sliced tilemap
- Speed
- 6
- Damage
- 3 (an arrow was 1)
- 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 GameObjectCannon Tower prefab
2D SpriteOpen recipe
Cannon Tower prefab
2D Sprite- 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)
- 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:
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;
}
}
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.
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.
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 GameObjectTower-select Buttons (UI)
UI > Button (one per buildable)Open recipe
Tower-select Buttons (UI)
UI > Button (one per buildable)- 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
- 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
Try this
Three short experiments. Predict before you run, then test your guess.
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.
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.
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
TowerShooterandProjectile. - 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 —
TileSlotnow refuses to build whenTowerSelector.selectedToweris still null. Also confirm the Button's OnClick actually points atTowerSelector.Select. - Every button builds the same unit. Each Button needs its own
TowerSelectorwith its owntowerPrefab. 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 Rateis 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
Damageis 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.instanceexists (the GameManager object is in the Scene).