Tower defense games are becoming increasingly popular, and this is not surprising - not much can be compared with the pleasure of observing your own lines of defense, destroying evil enemies! In this two-part tutorial, we will create a tower defense game on the 
Unity engine!
You will learn how to do the following:
- Create waves of enemies
- Make them follow route points.
- Build and upgrade towers, as well as teach them how to break enemies into small pixels
At the end we will get a game frame that can be developed further!
Note : you need some basic knowledge of Unity (for example, you need to know how assets and components are added, what prefabs are) and the basics of the C # language. To learn all of this, I recommend that you go through the Unity tutorials on Sean Duffy or the Beginning C # with Unity series by Brian Mockley.
I will work in the Unity version for OS X, but this tutorial is also suitable for Windows.
Through the windows of the ivory tower
In this tutorial, we will create a tower defense game in which enemies (little bugs) crawl to the cookies belonging to you and your minions (of course, these are monsters!). The player can place monsters in strategic points and improve them for gold.
The player must kill all the bugs until they get to the cookie. Every new wave of enemies is harder to beat. The game ends when you survive all the waves (victory!) Or when five enemies crawl to the cookies (loss!).
Here is a screenshot of the finished game:
Monsters, unite! Protect the cookie!Getting Started
Download this project 
stub , unpack it and open the 
TowerDefense-Part1-Starter project in Unity.
In the preparation of the project there are graphics and sound assets, ready-made animations and several useful scripts. The scripts are not directly related to the tower defense games, so I’m not going to talk about them here. However, if you want to learn more about creating 2D animations in Unity, then learn this 
tutorial on Unity 2D .
The project also contains prefabs, which we later add to create characters. Finally, there is a scene in the project with a background and a customized user interface.
Open 
GameScene , located in the 
Scenes folder, and set the Game mode to 
4: 3 aspect ratio so that all labels match the background correctly. In Game mode, you will see the following:
Authorship:- Graphics for the project is taken from the free pack of Vika Wenderlich! Other graphic works can be found on her gameartguppy site.
- Great music taken from the BenSound website, which has other amazing soundtracks!
- Thanks also to Michael Jesper for a very useful camera shake function .
.
Place marked with a cross: the location of the monsters
Monsters can only be put on dots marked with 
x .
To add them to the scene, drag 
Images \ Objects \ Openspot from the 
Project Browser to the 
Scene window. While the position for us is not important.
After selecting 
Openspot in the hierarchy, click on 
Add Component in the 
Inspector and select 
Box Collider 2D . In the Scene window, Unity displays a rectangular collider with a green line. We will use this collider to recognize mouse clicks on this place.
Similarly, add the 
Audio \ Audio Source component to 
Openspot . For the Audio Source component's 
AudioClip option, 
select the tower_place file in the 
Audio folder and turn off 
Play On Awake .
We need to create 11 more points. Although there is a temptation to repeat all these steps, there is a better solution in Unity: 
Prefab !
Drag 
Openspot from the 
Hierarchy to the 
Prefabs folder inside the 
Project Browser . His name will become blue in the Hierarchy, which means that it is attached to the prefab. Like that:
Now that we have a prefab blank, we can create as many copies as we like. Simply drag and drop 
Openspot from the 
Prefabs folder inside the 
Project Browser to the 
Scene window. Repeat this 11 times, and we will have 12 Openspot objects in the scene.
Now use the 
Inspector to set the following coordinates to these 12 Openspot objects:
- (X: -5.2, Y: 3.5, Z: 0)
- (X: -2.2, Y: 3.5, Z: 0)
- (X: 0.8, Y: 3.5, Z: 0)
- (X: 3.8, Y: 3.5, Z: 0)
- (X: -3.8, Y: 0.4, Z: 0)
- (X: -0.8, Y: 0.4, Z: 0)
- (X: 2.2, Y: 0.4, Z: 0)
- (X: 5.2, Y: 0.4, Z: 0)
- (X: -5.2, Y: -3.0, Z: 0)
- (X: -2.2, Y: -3.0, Z: 0)
- (X: 0.8, Y: -3.0, Z: 0)
- (X: 3.8, Y: -3.0, Z: 0)
When you do this, the scene will look like this:
Placing monsters
To simplify placement, there is a 
Monster prefab in the 
Prefab project folder.
Prefab Monster is ready to use.At the moment it consists of an empty game object with three different sprites and shooting animations as child elements.
Each sprite is a monster with different levels of power. Also in the prefab contains the component 
Audio Source , which will be launched to play the sound when the monster shoots a laser.
Now we will create a script that will be placed by 
Monster on 
Openspot .
In the 
Project Browser, select the 
Openspot object in the 
Prefabs folder. In the 
Inspector, click on 
Add Component , then select 
New Script and name the script 
PlaceMonster . Select 
Sharp as the 
C language and click on 
Create and Add . Since we added the script to the 
Openspot prefab, all Openspot objects in the scene will now have this script. Fine!
Double-click the script to open it in the IDE. Then add two variables:
public GameObject monsterPrefab; private GameObject monster; 
We will create an instance of the object stored in 
monsterPrefab to create a monster, and save it in 
monster so that you can manipulate it during the game.
One monster per point
To place only one monster on one point, add the following method:
 private bool CanPlaceMonster() { return monster == null; } 
In 
CanPlaceMonster() we can check whether the 
monster variable is still 
null . If so, then there is no monster at the point, and we can place it.
Now add the following code to place the monster when the player clicks on this GameObject:
 
This code places the monster when you click the mouse or touch the screen. How does he work?
- Unity automatically calls OnMouseUpwhen the player touches the physical collider GameObject.
- When called, this method puts a monster if CanPlaceMonster()returnstrue.
- We create a monster using the Instantiatemethod, which creates an instance of a given prefab with the specified position and rotation. In this case, we copymonsterPrefab, set the current position of the GameObject and the absence of rotation to it, transfer the result to theGameObjectand save it tomonster
- At the end, we call PlayOneShotto play a sound effect attached to theAudioSourcecomponent of the object.
Now our 
PlaceMonster script may have a new monster, but we still need to specify the prefab.
Using the right prefab
Save the file and return to Unity.
To set the 
monsterPrefab variable, first select the 
Openspot object from the 
Prefabs folder in the project browser.
In the 
Inspector, click on the circle to the right of the 
Monster Prefab field of the 
PlaceMonster (Script) component and select 
Monster in the dialog that appears.
That's all. Run the scene and create monsters in different places by clicking the mouse or touching the screen.
Fine! Now we can create monsters. However, they look like weird porridge, because all the child sprites of the monster are drawn. Now we fix it.
Raise the level of monsters
The figure below shows that as the level rises the monsters look more and more frightening.
What a sweetheart! But if you try to steal his cookies, this monster will turn into a killer.The script is used as the basis for the implementation of the system of levels of monsters. He tracks the power of the monster at each level and, of course, the current level of the monster.
Add this script.
Select the 
Prefabs / Monster prefab in the 
Project Browser . Add a new 
C # script called 
MonsterData . Open the script in the IDE and add the following code 
above the 
MonsterData class.
 [System.Serializable] public class MonsterLevel { public int cost; public GameObject visualization; } 
So we create 
MonsterLevel . It groups the price (in gold, which we will support below) and the visual representation of the monster level.
We add on top 
[System.Serializable] so that instances of the class can be changed in the inspector. This allows us to quickly change all values of the Level class, even when the game is running. This is incredibly useful for balancing the game.
Setting monster levels
In our case, we will store the specified 
MonsterLevel in 
List<T> .
Why not just use 
MonsterLevel[] ? We need the index of a particular 
MonsterLevel object several times. Although it is easy to write code for this, we still have to use 
IndexOf() , which implements the 
Lists functionality. It makes no sense to reinvent the wheel.
Reinventing a bicycle is usually a bad idea.At the top of 
MonsterData.cs, add the following 
using construct:
 using System.Collections.Generic; 
It gives us access to generalized data structures so that we can use the 
List<T> class in the script.
Note : generalizations are a powerful concept for C #. They allow you to set type-safe data structures without adhering to the type. This is useful for container classes such as lists and sets. To learn more about generalized structures, read the book Introduction to C # Generics .
Now add the following variable to 
MonsterData to store the 
MonsterLevel list:
 public List<MonsterLevel> levels; 
Thanks to generalizations, we can guarantee that the 
List from 
level will contain only 
MonsterLevel objects.
Save the file and switch to Unity to configure each level.
Select 
Prefabs / Monster in the 
Project Browser . The 
Inspector now displays the 
Levels field of the 
MonsterData (Script) component. Set the 
size parameter to 
3 .
Next, set the 
cost for each level:
- Element 0 : 200
- Element 1 : 110
- Element 2 : 120
Now assign the values of the visual display fields.
Deploy the 
Prefabs / Monster in the Project browser to see its children. Drag a child 
Monster0 into the 
visualization Element 0 field.
Next, set 
Element 1 to 
Monster1 , and 
Element 2 to 
Monster2 . The GIF shows this process:
When you select 
Prefabs / Monster , the prefab should look like this:
Setting current level
Go back to 
MonsterData.cs in the IDE and add another variable to 
MonsterData .
 private MonsterLevel currentLevel; 
In the private variable 
currentLevel we will store the current level of the monster.
Now we will set 
currentLevel and make it visible for other scripts. Add the following lines to 
MonsterData along with the declaration of the instance variables:
 
Quite a big piece of C # code, right? Let's sort it out in order:
- Set the property of the private variable currentLevel. By setting a property, we can call it like any other variable: either asCurrentLevel(inside the class) or asmonster.CurrentLevel(outside). We can define any behavior in a getter or setter method, and by creating only a getter, setter, or both, we can control the characteristics of the property: read-only, write-only, and write / read.
- In the getter, we return the currentLevelvalue.
- In the setter, we assign the currentLevelnew value. Then we get the index of the current level. Finally, we loop through all levels and turn on / off the visual display depending on thecurrentLevelIndex. This is great because when you change thecurrentLevelsprite is updated automatically. Properties is a very handy thing!
Add the following 
OnEnable implementation:
 void OnEnable() { CurrentLevel = levels[0]; } 
Here we set the 
CurrentLevel when placing. This ensures that only the desired sprite will be shown.
Note : It is important to initialize the property in OnEnable , and not in OnStart , because we call ordinal methods when creating prefab instances.
OnEnable will be called immediately when creating a prefab (if the prefab was saved in the enabled state), but OnStart not called until the object starts to run as part of the scene.
We need to verify this data before placing the monster, so we initialize it to OnEnable .
Save the file and return to Unity. Run the project and position the monsters; they now display the correct sprites of the lowest level.
Monster upgrade
Return to the 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 we get the 
currentLevel index and the highest level index; if the monster has not reached the maximum level, the next level is returned. Otherwise, it returns 
null .
You can use this method to find out if monster upgrades are possible.
To increase the level of the monster, add the following method:
 public void IncreaseLevel() { int currentLevelIndex = levels.IndexOf(currentLevel); if (currentLevelIndex < levels.Count - 1) { CurrentLevel = levels[currentLevelIndex + 1]; } } 
Here we get the index of the current level, and then we are convinced that this is not the maximum level, checking that it is less than 
levels.Count - 1 . If so, then assign the 
CurrentLevel value to the next level.
Checking upgrades functionality
Save the file and return to 
PlaceMonster.cs in the IDE. Add a 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 we check if there is a monster that can be improved by comparing the 
monster variable with 
null . If this is true, then we get the current level of the monster from its 
MonsterData .
Then we check if the next level is available, that is, whether 
GetNextLevel() returns a 
null value. If elevation is possible, then we return 
true ; otherwise, return 
false .
Implement improvements for gold
To enable the upgrade option, add an 
else if branch to 
OnMouseUp :
 if (CanPlaceMonster()) {  
Check for upgradeability with 
CanUpgradeMonster() . If possible, we access the 
MonsterData component using 
GetComponent() and call 
IncreaseLevel() , which increases the monster level. Finally, we run the monster's 
AudioSource .
Save the file and return to Unity. Start the game, place and improve 
any number of monsters (but this is for now).
Pay Gold - Game Manager
While we can immediately build and improve any monsters, but will it be interesting in the game?
Let's look at the question of gold. The problem with tracking it is that we have to transfer information between different game objects.
The figure below shows all the objects that should take part in this.
All selected game objects must know how much gold the player has.To store this data, we will use a shared object that other objects can access.
Right-click on the 
Hierarchy and select 
Create Empty . Name the new 
GameManager object.
Add a new 
C # script to 
GameManager called 
GameManagerBehavior , and then open it in the IDE. We will display the total amount of player gold in the label, so add the following line at the top of the file:
 using UnityEngine.UI; 
This will allow us to access UI classes like 
Text , which is used for labels. Now add the following variable to the class:
 public Text goldLabel; 
It will contain a link to the 
Text component used to display the amount of gold the player has.
Now that 
GameManager knows about the label, how do we synchronize the amount of gold stored in a variable and the value displayed in the label? We will 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; } } 
Does he seem familiar? The code is similar to 
CurrentLevel , which we set in 
Monster . First we create a private variable 
gold to store the current amount of gold. Then we set the 
Gold property (unexpectedly, right?) And implement the getter and setter.
Getter simply returns the value of 
gold . Setter is more interesting. In addition to setting the value of a variable, it also sets the 
text field for 
goldLabel to display the new gold value.
How generous will we be? Add the following line to 
Start() to give the player 
1000 gold, or less if you feel sorry for the money:
 Gold = 1000; 
Assigning a Label Object to a Script
Save the file and return to Unity. In the 
Hierarchy, select the 
GameManager . In the 
Inspector, click on the circle to the right of the 
Gold Label . In the 
Select Text dialog box, select the 
Scene tab and select 
GoldLabel .
Run the scene and 
Gold: 1000 appears in the label.
Check the player's wallet
Open the 
PlaceMonster.cs script in the IDE and add the following instance variable:
 private GameManagerBehavior gameManager; 
We will use the 
gameManager to access the 
GameManagerBehavior component of the 
GameManagerBehavior object. To set it, add the following to 
Start() :
 gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>(); 
We get a GameObject called GameManager using the 
GameObject.Find() function, which returns the first found game object with that name. Then we get its 
GameManagerBehavior component and save it for the future.
Note : you can do this by specifying a field in the Unity editor or by adding a static method to GameManager , which returns a singleton instance from which we can get GameManagerBehavior .
However, in the block of code shown above, there is a dark horse: the Find method, which works slower during the execution of an application; but it is convenient and can be used in moderation.
Take my money!
We are not subtracting gold yet, so we 
OnMouseUp() add this line to 
OnMouseUp() twice , replacing each of the comments 
// TODO: :
 gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost; 
Save the file and return to Unity, upgrade a few monsters, and look at updating the Gold value. Now we subtract gold, but players can build monsters as long as they have enough space; they just borrow money.
Infinite credit? Fine! But we cannot allow it. The player must be able to put monsters, as long as he has enough gold.Gold check for monsters
Switch to IDE with 
PlaceMonster.cs and replace the contents of 
CanPlaceMonster() following:
 int cost = monsterPrefab.GetComponent<MonsterData>().levels[0].cost; return monster == null && gameManager.Gold >= cost; 
MonsterData placement price of the monster from 
levels in its 
MonsterData . Then we check that 
monster not 
null , and that 
gameManager.Gold greater than this price.
The task for you is to add a 
CanUpgradeMonster() to 
CanUpgradeMonster() yourself if the player has enough gold.
Solution insideReplace the line:
 return true; 
on this:
 return gameManager.Gold >= nextLevel.cost; 
She will check if the player has more 
Gold than the upgrade price.
 Save and run the scene in Unity. Now try-how to add unlimited monsters!
Now we can build only a limited number of monsters.Tower politics: enemies, waves and waypoints
It is time to “pave the way” to our enemies. Enemies appear on the first point of the route, move to the next and repeat the process until they reach the cookie.
You can make the enemies move like this:
- Ask the way for the enemies to walk
- Move the enemy along the way
- Turn the enemy so that he looks forward
Creating a road from route points
Right-click on the 
Hierarchy and select 
Create Empty to create a new empty game object. Call it 
Road and position it at 
(0, 0, 0) .
Now right-click on the 
Road in 
Hierarchy and create another empty game object as a child of the Road. Call it 
Waypoint0 and place it at 
(-12, 2, 0) - from here the enemies will begin their movement.
Similarly, create five more route points with the following names and positions:
- Waypoint1: (X: 7, Y: 2, Z: 0)
- Waypoint2: (X: 7, Y: -1, Z: 0)
- Waypoint3: (X: -7.3, Y: -1, Z: 0)
- Waypoint4: (X: -7.3, Y: -4.5, Z: 0)
- Waypoint5: (X: 7, Y: -4.5, Z: 0)
The screenshot below shows the route points and the resulting path.
Making enemies
Now create several enemies so that they can move along the road. In the 
Prefabs folder 
there is an 
Enemy prefab. Its position is 
(-20, 0, 0) , so new instances will be created off-screen.
Otherwise, it is configured in much the same way as the Monster prefab, has an 
AudioSource and a child 
Sprite , and we will be able to rotate this sprite without turning the health bar.
Move the enemies along the way
Add a new 
C # script called 
MoveEnemy to the 
Prefabs \ Enemy prefab . Open the script in the IDE and add the following variables:
 [HideInInspector] public GameObject[] waypoints; private int currentWaypoint = 0; private float lastWaypointSwitchTime; public float speed = 1.0f; 
A copy of the route points is stored in the 
waypoints in the array, and the 
[HideIn inspector ] above the 
waypoints ensures that we cannot accidentally change this field in the 
Inspector , but still will have access to it from other scripts.
currentWaypoint keeps track of where in the route the enemy is heading at the current time, and the 
lastWaypointSwitchTime keeps 
lastWaypointSwitchTime the time when the enemy has passed through it. In addition, we keep the 
speed enemy.
Add this line to 
Start() :
 lastWaypointSwitchTime = Time.time; 
So we initialize 
lastWaypointSwitchTime with the current time value.
To make the enemy move along the route, add the following code to 
Update() :
 
Let's sort the code step by step:
- From the array of route points we get the starting and ending positions of the current route segment.
- We calculate the time required to travel the entire distance using the formula time = distance / speed , and then we determine the current time on the route. Using Vector2.Lerp, we interpolate the current enemy position between the starting and ending exact segments.
- Check whether the enemy has reached endPosition. If yes, then we process two possible scenarios:
 - The enemy has not yet reached the last point of the route, so we increase the value of currentWaypointand updatelastWaypointSwitchTime. Later we will add a code to rotate the enemy so that he looks in the direction of his movement.
- The enemy has reached the last point of the route, then we destroy it and launch the sound effect. Later we will add a code that reduces the player’s health.
 
Save the file and return to Unity.
We inform the enemy the direction of movement
In their current state, the enemies do not know the order of the route points.
Select 
Road in the 
Hierarchy and add a new 
C # script called 
SpawnEnemy . Open it in the IDE and add the following variable:
 public GameObject[] waypoints; 
We will use 
waypoints to store links to the waypoint in the scene in the correct order.
Save the file and return to Unity. Select 
Road in the 
Hierarchy and set the 
Size of the 
Waypoints array to 
6 .
Drag each of the Road children into the fields by inserting 
Waypoint0 into 
Element 0 , 
Waypoint1 into 
Element 1, and so on.
Now we have an array containing the route points in the correct order - note, the enemies never retreat, they persevere in a sweet reward.
Checking how it all works.
Open the 
SpawnEnemy IDE and add the following variable:
 public GameObject testEnemyPrefab; 
It will contain a link to the 
Enemy testEnemyPrefab in 
testEnemyPrefab .
To create an enemy when the script starts, add the following code to 
Start() :
 Instantiate(testEnemyPrefab).GetComponent<MoveEnemy>().waypoints = waypoints; 
So we will create a new copy of the prefab stored in 
testEnemy , and assign it a route to follow.
Save the file and return to Unity. Select the 
Road object in 
Hierarchy and select the 
Enemy prefab for the 
Test Enemy parameter.
Run the project and see how the enemy is moving along the road (in GIF for greater clarity, the speed is increased by 20 times).Noticed that he does not always look where he goes? It's funny, but we're trying to make a professional game. Therefore, in the second part of the tutorial we will teach the enemies to look ahead.Where to go next?
We have already done a lot and are moving quickly to create our own game in the tower defense genre.Players can create a limited number of monsters, and the enemy is running along the road, heading for our cookie. Players have gold and they can upgrade monsters.Download the finished result from here .In the second part, we consider the creation of huge waves of enemies and their destruction. See you!