# How to Create a Tower Defense Game in Unity – Part 2

In this second and final part of the Unity tower defense tutorial, you’ll add some shooting monsters into the the mix. By Jeff Fisher.

Leave a rating/review
Save for later
Share

## How to Create a Tower Defense Game in Unity – Part 2

35 mins

Update note: This tutorial has been updated to Unity 2017.1 by Jeff Fisher. The original tutorial was written by Barbara Reichart.

Welcome to part two of How to Create a Tower Defense Game in Unity. You’re making a tower defense game in Unity, and at the end of part one, you could place and upgrade monsters. You also had one enemy attack the cookie.

However, the enemy had no idea which way to face! Also, it was a poor excuse for an attack. In this part, you’ll add enemy waves and arm your monsters so they can defend your precious cookie.

## Getting Started

In Unity, open your completed project from the first part of this tutorial series, or if you’re just joining in now, download the starter project and open TowerDefense-Part2-Starter.

Open GameScene from the Scenes folder.

## Rotate the Enemies

At the end of the last tutorial, the enemy followed the road, but appeared to have no idea which way to face.

Open MoveEnemy.cs in your IDE, and add the following method to fix this.

```private void RotateIntoMoveDirection()
{
//1
Vector3 newStartPosition = waypoints [currentWaypoint].transform.position;
Vector3 newEndPosition = waypoints [currentWaypoint + 1].transform.position;
Vector3 newDirection = (newEndPosition - newStartPosition);
//2
float x = newDirection.x;
float y = newDirection.y;
float rotationAngle = Mathf.Atan2 (y, x) * 180 / Mathf.PI;
//3
GameObject sprite = gameObject.transform.Find("Sprite").gameObject;
sprite.transform.rotation = Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}
```

`RotateIntoMoveDirection` rotates the enemy so that it always looks forward, like so:

1. It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
2. It uses `Mathf.Atan2` to determine the angle toward which `newDirection` points, in radians, assuming zero points to the right. Multiplying the result by `180 / Mathf.PI` converts the angle to degrees.
3. Finally, it retrieves the child named Sprite and rotates it `rotationAngle` degrees along the z-axis. Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.

In `Update()`, replace the comment `// TODO: Rotate into move direction` with the following call to `RotateIntoMoveDirection`:

```RotateIntoMoveDirection();
```

Save the file and switch to Unity. Run the scene; now your monster knows where he’s going.

The bug now looks where it’s going.

One single enemy? Hardly impressive. Let the hordes come. And like in every tower defense game, hordes will come in waves!

## Inform the Player

Before you set the hordes into motion, you need to let the player know about the coming onslaught. Also, why not display the current wave’s number at the top of the screen?

Several GameObjects need wave information, so you’ll add it to the GameManagerBehavior component on GameManager.

Open GameManagerBehavior.cs in your IDE and add these two variables:

```public Text waveLabel;
public GameObject[] nextWaveLabels;
```

The `waveLabel` stores a reference to the wave readout at the top right corner of the screen. `nextWaveLabels` stores the two GameObjects that when combined, create an animation you’ll show at the start of a new wave, as shown below:

Save the file and switch to Unity. Select GameManager in the Hierarchy. Click on the small circle to the right of Wave Label, and in the Select Text dialog, select WaveLabel in the Scene tab.

Now set the Size of Next Wave Labels to 2. Then assign Element 0 to NextWaveBottomLabel and Element 1 to NextWaveTopLabel the same way as you set Wave Label.

This is what your Game Manager Behavior should look like

If the player has lost the game, he shouldn’t see the next wave message. To handle this, switch back to GameManagerBehavior.cs in your IDE and add another variable:

```public bool gameOver = false;
```

In `gameOver` you’ll store whether the player has lost the game.

Once again, you’ll use a property to keep the game’s elements in sync with the current wave. Add the following code to `GameManagerBehavior`:

```private int wave;
public int Wave
{
get
{
return wave;
}
set
{
wave = value;
if (!gameOver)
{
for (int i = 0; i < nextWaveLabels.Length; i++)
{
nextWaveLabels[i].GetComponent<Animator>().SetTrigger("nextWave");
}
}
waveLabel.text = "WAVE: " + (wave + 1);
}
}
```

Creating the private variable, property and getter should be second nature by now. But again, the setter is a bit trickier.

You update `wave` with the new `value`.

Then you check that the game is not over. If so, you iterate over all labels in nextWaveLabels — those labels have an Animator component. To trigger the animation on the Animator you set the trigger nextWave.

Lastly, you set `waveLabel`‘s `text` to the value of `wave + 1`. Why the `+1`? – Normal human beings do not start counting at zero. Weird, I know :]

In `Start()`, set the value of this property:

```Wave = 0;
```

You start counting at `Wave` number 0.

Save the file, then run the scene in Unity. The Wave readout properly starts at 1.

For the player everything starts with wave 1.

## Waves: Spawn, Spawn, Spawn

It sounds obvious, but you need to be able to create more enemies to unleash the hordes — right now you can’t do that. Furthermore, you shouldn’t spawn the next wave once the current wave is obliterated — at least for now.

So, the games must be able to recognize whether there are enemies in the scene, and Tags are a good way to identify game objects.

### Set Enemy Tags

Select the Enemy prefab in the Project Browser. At the top of the Inspector, click on the Tag dropdown and select Add Tag.

Create a Tag named Enemy.

Select the Enemy prefab. In the Inspector, set its Tag to Enemy.

### Define Enemy Waves

Now you need to define a wave of enemies. Open SpawnEnemy.cs in your IDE, and add the following class implementation before `SpawnEnemy`:

```[System.Serializable]
public class Wave
{
public GameObject enemyPrefab;
public float spawnInterval = 2;
public int maxEnemies = 20;
}
```

Wave holds an `enemyPrefab`, the basis for instantiating all enemies in that wave, a `spawnInterval`, the time between enemies in the wave in seconds and the `maxEnemies`, which is the quantity of enemies spawning in that wave.

This class is Serializable, which means you can change the values in the Inspector.

Add the following variables to the `SpawnEnemy` class:

```public Wave[] waves;
public int timeBetweenWaves = 5;

private GameManagerBehavior gameManager;

private float lastSpawnTime;
private int enemiesSpawned = 0;
```

This sets up some variables for spawning that are quite similar to how you moved the enemies along waypoints.
You’ll define the game’s various waves in `waves`, and track the number of enemies spawned and when you spawned them in `enemiesSpawned` and `lastSpawnTime`, respectively.

Players need breaks after all that killing, so set `timeBetweenWaves` to 5 seconds

Replace the contents of `Start()` with the following code.

```lastSpawnTime = Time.time;
gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
```

Here you set `lastSpawnTime` to the current time, which will be when the script starts as soon as the scene loads. Then you retrieve the `GameManagerBehavior` in the familiar way.

Add this to `Update()`:

```// 1
int currentWave = gameManager.Wave;
if (currentWave < waves.Length)
{
// 2
float timeInterval = Time.time - lastSpawnTime;
float spawnInterval = waves[currentWave].spawnInterval;
if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
timeInterval > spawnInterval) &&
enemiesSpawned < waves[currentWave].maxEnemies)
{
// 3
lastSpawnTime = Time.time;
GameObject newEnemy = (GameObject)
Instantiate(waves[currentWave].enemyPrefab);
newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
enemiesSpawned++;
}
// 4
if (enemiesSpawned == waves[currentWave].maxEnemies &&
GameObject.FindGameObjectWithTag("Enemy") == null)
{
gameManager.Wave++;
gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
enemiesSpawned = 0;
lastSpawnTime = Time.time;
}
// 5
}
else
{
gameManager.gameOver = true;
GameObject gameOverText = GameObject.FindGameObjectWithTag ("GameWon");
gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}
```

Go through this code step by step:

1. Get the index of the current wave, and check if it’s the last one.
2. If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases. If it’s the first enemy in the wave, you check whether `timeInterval` is bigger than `timeBetweenWaves`. Otherwise, you check whether `timeInterval` is bigger than this wave’s `spawnInterval`. In either case, you make sure you haven’t spawned all the enemies for this wave.
3. If necessary, spawn an enemy by instantiating a copy of `enemyPrefab`. You also increase the `enemiesSpawned` count.
4. You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave. You also give the player 10 percent of all gold left at the end of the wave.
5. Upon beating the last wave this runs the game won animation.
Jeff Fisher

## Contributors

Jeff Fisher

Author

Barbara Reichart

Author

Mitch Allen

Tech Editor

Sean Duffy

Final Pass Editor