How to Create a Tower Defense Game in Unity – Part 1

In this tutorial, you’ll build a 2D tower defense game using the latest Unity engine. By Jeff Fisher.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Upgrade Those Monsters

Switch back to your IDE and add the following method to MonsterData:

public MonsterLevel GetNextLevel()
{
  int currentLevelIndex = levels.IndexOf (currentLevel);
  int maxLevelIndex = levels.Count - 1;
  if (currentLevelIndex < maxLevelIndex)
  {
    return levels[currentLevelIndex+1];
  } 
  else
  {
    return null;
  }
}

In GetNextLevel you get the index of currentLevel and the index of the highest level provided the monster did not reach the maximal level to return the next level. Otherwise, return null.

You can use this method to figure out whether upgrading the monster is possible.

Add the following method to increase a monster's level:

public void IncreaseLevel()
{
  int currentLevelIndex = levels.IndexOf(currentLevel);
  if (currentLevelIndex < levels.Count - 1)
  {
    CurrentLevel = levels[currentLevelIndex + 1];
  }
}

Here you get the index of the current level, and then you make sure it’s not the maximum level by checking if it’s smaller than levels.Count - 1. If so, set CurrentLevel to the next level.

Test Upgrade Capability

Save the file and then switch to PlaceMonster.cs in your IDE and add this new method:

private bool CanUpgradeMonster()
{
  if (monster != null)
  {
    MonsterData monsterData = monster.GetComponent<MonsterData>();
    MonsterLevel nextLevel = monsterData.GetNextLevel();
    if (nextLevel != null)
    {
      return true;
    }
  }
  return false;
}

First check whether there is a monster that you can upgrade by checking the monster variable for null. If this is the case, you get the current level of the monster from its MonsterData.

Then you test whether a higher level is available, which is when GetNextLevel() doesn’t return null. If up-leveling is possible, you return true, otherwise, you return false.

Enable Upgrading With Gold

To enable the upgrade option, add an else if branch to OnMouseUp:

if (CanPlaceMonster())
{
  // Your code here stays the same as before
}
else if (CanUpgradeMonster())
{
  monster.GetComponent<MonsterData>().IncreaseLevel();
  AudioSource audioSource = gameObject.GetComponent<AudioSource>();
  audioSource.PlayOneShot(audioSource.clip);
  // TODO: Deduct gold
}

Check whether an upgrade is possible with CanUpgradeMonster(). If yes, you access the MonsterData component with GetComponent() and call IncreaseLevel(), which increases the level of the monster. Lastly, you trigger the monster's AudioSource.

Save the file and switch back to Unity. Run the game, place and upgrade as many monsters as you like...for now.

All the monster upgrades

Upgrade all the monsters

All the monster upgrades

Pay Gold - Game Manager

Right now it’s possible to build and upgrade all the monsters immediately, but where's the challenge in that?

Let's drill down into the issue of the gold. The problem with keeping track of it is that you need to share information between different game objects.

The following image shows all the objects that want a piece of the action.

The highlighted game objects all need to know, how much gold the player owns.

The highlighted game objects all need to know, how much gold the player owns.

The highlighted game objects all need to know, how much gold the player owns.

You'll use a shared object that's accessible to other objects to store this data.

Right-click in the Hierarchy and select Create Empty. Name the new game object GameManager.

Add a C# script named GameManagerBehavior to GameManager, then open the new script in your IDE. You'll display the player's total gold in a label, so add the following line to the top of the file:

using UnityEngine.UI;

This lets you access UI-specific classes like Text, which the project uses for the labels. Now add the following variable to the class:

public Text goldLabel;

This will store a reference to the Text component used to display how much gold the player owns.

Now that GameManager knows about the label, how can you ensure the amount of gold stored in your variable and the amount displayed on the label are in sync? You'll create a property.

Add the following code to GameManagerBehavior:

private int gold;
public int Gold {
  get
  { 
    return gold;
  }
  set
  {
    gold = value;
    goldLabel.GetComponent<Text>().text = "GOLD: " + gold;
  }
}

Seem familiar? It’s similar to the CurrentLevel you defined in Monster. At first, you create a private variable, gold, to store the current gold total. Then you define a property named Gold -- creative, right? -- and implement a getter and setter.

The getter simply returns the value of gold . The setter is more interesting. In addition to setting the variable's value, it also sets the text field on goldLabel to display the new amount of gold.

How generous do you feel? Add the following line to Start() to give the player 1000 gold, or less if you feel miserly:

Gold = 1000;

Assign the Label Object to the Script

Save the file and switch to Unity.

In the Hierarchy, select GameManager. In the Inspector, click on the circle to the right of Gold Label. In the Select Text dialog, select the Scene tab and select GoldLabel.

Assign goldLabel

Run the scene and the label displays Gold: 1000.

1000 gold

Check the Player's "Wallet"

Open PlaceMonster.cs in your IDE, and add the following instance variable:

private GameManagerBehavior gameManager;

You'll use gameManager to access the GameManagerBehavior component of the scene's GameManager. To assign it, add the following to Start():

gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();

You get the GameObject named GameManager using GameObject.Find(), which returns the first game object it finds with the given name. Then, retrieve its GameManagerBehavior component and store it for later.

Note: You could have accomplished this by setting the field in Unity's editor, or by adding a static method to GameManager that returns a singleton instance from which you could get the GameManagerBehavior.

However, there's a dark horse method in the block above: Find, which is slower at runtime but convenient and ok to use sparingly.

Note: You could have accomplished this by setting the field in Unity's editor, or by adding a static method to GameManager that returns a singleton instance from which you could get the GameManagerBehavior.

However, there's a dark horse method in the block above: Find, which is slower at runtime but convenient and ok to use sparingly.

Get the Money!

You don't yet deduct gold, so add this line twice inside OnMouseUp(), replacing each of the comments that read // TODO: Deduct gold:

gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost;

Save the file and switch to Unity, upgrade some monsters and watch the Gold readout update. Now you deduct gold, but players can build monsters as long as there is space; they just get into debt.

Infinite credit

Infinite credit? Awesome! But you can't allow this. Monsters should only be placed when the player has enough gold.

Jeff Fisher

Contributors

Jeff Fisher

Author

Barbara Reichart

Author

Mitch Allen

Tech Editor

Sean Duffy

Final Pass Editor

Over 300 content creators. Join our team.