noobtuts

Unity 2D Plants vs. Zombies Tutorial

Unity Plants vs. Zombies

Today we will make a Plants vs. Zombies clone with Unity's 2D features. To keep things simple, we will ignore all the fancy things like the menu, multiple levels or cut-scenes and focus on fighting Zombies in the backyard. The Tutorial will be really long and detailed, but the end result will be less than 130 lines of code!

Here is a preview of the game:
Unity Plants vs. Zombies

Requirements

Knowledge

This Tutorial does not require any advanced knowledge. A basic understanding of the Unity engine is still required. Feel free to read our easier Unity Tutorials like Unity 2D Pong Game to get used to the engine.

Unity Version

We will use Unity 5.0.1f1 in this Tutorial. Newer versions should work fine as well, older versions may or may not work. The free version of Unity 5 now comes with all the engine features, which makes it the recommended version.

Project Setup

Let's start working on the game. We will start Unity and select New Project:
Unity New Project

We will name it plants, select any location like C:\, select 2D and click Create Project:
Unity Create new 2D Project

If we select the Main Camera in the Hierarchy then we can set the Background Color to black, adjust the Size and the Position like shown in the following image:
Camera Properties

Creating the Grass

We will use a tool like Paint.NET or Photoshop to create a grass tile:
Grass Tiles
Note: right click on the image, select Save As..., navigate to the project's Assets folder and save it in a new Sprites folder.

Let's select the grass tile in the Project Area:
Grass in Project Area

And then modify the Import Settings in the Inspector:
Grass Import Settings
Note: a Pixels to Unit value of 32 means that 32 x 32 pixels will fit into one unit in the game world. We will use this value for all our textures.

Afterwards we can add the image to the game by dragging it from the Project Area into the Scene:
Drag Grass into Scene

We will position it at (0, 0) so it's at the bottom left of our game:
Grass Position in Inspector

Adding a Sorting Layer

We are making a 2D game, so we can't use the third dimension as depth effect, or to distinguish between background and foreground easily. Instead we will use a Sorting Layer to tell Unity which elements it should draw first. For example, our background should be drawn first and the plants should be drawn afterwards (hence on top of the background).

We can change the grass Sorting Layer if we take a look at the Sprite Renderer component in the Inspector:
Grass SpriteRenderer with default Sorting Layer

Let's select Add Sorting Layer.. from the Sorting Layer list, add a Background layer and move it to the top like shown below:
Add Background Sorting Layer

Afterwards we select the grass again and assign the previously created Background Sorting Layer:
Grass SpriteRenderer with Background Sorting Layer
Note: Unity draws the layers from top to bottom, hence whatever should be in the background will be at the top of the list.

Now the grass will always be drawn behind the plants and the zombies.

Making the Grass clickable

Later on when working on the build menu we will need a way to find out if a grass tile was clicked. There are all kinds of different ways to do this in Unity, but the easiest one is to just use the OnMouseUpAsButton function that is automatically called by Unity if the grass was clicked.

Now there is one thing to keep in mind here: Unity only does this if the GameObject has a Collider. So let's select Add Component->Physics 2D->Box Collider 2D in the Inspector and enable the Is Trigger option:
Grass with Collider
Note: enabling Is Trigger means that the grass will receive all kinds of collision information, but things won't actually collide with. So if a Zombie walks into a grass tile, it won't collide with it.

Duplicating the Grass

Right now we only have one grass tile in our game. Let's right click it in the Hierarchy, select Duplicate and then position it at (1, 0). Then we will duplicate it again and position it at (2, 0). We will keep duplicating it until we have 10 * 5 grass tiles where the bottom-left tile is at (0, 0) and the top-right tile is at (9, 4):
Duplicated Grass Tiles
Note: it's important that all the tiles have rounded positions like (2, 3) and never (2.01, 3.023).

The Health Script

The Zombies should be able to attack the Plants, and the Firing Plant should be able to deal damage to the Zombies. We will stick with Unity's component based nature and create only one Health script for all entities.

We can create a new Script by right clicking in the Project Area and then selecting Create->C# Script:
Create Script

We will name it Health and then move it into a new Scripts folder:
Health Script in Project Area

We can open and then modify the Script by double clicking it:

using UnityEngine;
using System.Collections;

public class Health : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

We won't need the Start or the Update function, so let's remove both of them. Instead we will add a int variable that keeps track of the current health and add a function that decreases that variable. If the current health drops below 0 then the entity should be destroyed:

using UnityEngine;
using System.Collections;

public class Health : MonoBehaviour {
    // Current Health
    [SerializeField]
    int cur = 5;

    public void doDamage(int n) {
        // Subtract damage from current health
        cur -= n;

        // Destroy if died
        if (cur <= 0)
            Destroy(gameObject);
    }
}

Note: we used SerializeField to let Unity know that we want to be able to modify the cur variable in the Inspector. Usually this is done by making it public, but in this case we don't want other Scripts to be able to access the cur variable. Instead they should always use the doDamage function.

The Script will be added to all Plants and Zombies later on.

Creating a Sunflower Plant

Drawing the Animation

Since we are developing a 2D game, animations are very easy to make with our drawing tool of choice and a few hours of time.

For our sunflower we will only need an idle animation where its head slightly moves. Here is what we came up with:
Pixel Art Sunflower Plant
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

Let's select the sunflower image in the Project Area and then modify the Import Settings in the Inspector:
Sunflower ImportSettings

The Filter Mode and Format influence the looks. Setting the Sprite Mode to Multiple tells Unity that there are several sunflower parts (also known as Tiles) in one image.

Importing the Animation

Now we have to tell Unity where those tiles are in the image. We can open the Sprite Editor by pressing the Sprite Editor button in the Inspector (it can be seen in the above image).

Afterwards we can see our Sunflower in the Sprite Editor:
Sunflower in Sprite Editor

All we have to do here is open the Slice menu, set the type to Grid and the pixel size to 32 x 32. Afterwards we press the Slice button:
Sunflower Sprite Editor Slicing

Let's press Apply and then close the Sprite Editor.

If we take a look in the Project Area then we can see that our Sunflower now has 2 children (the slices):
Sunflower Project Area Slices

Creating the Animation

Creating a Unity Animation from those 2 slices is incredibly easy. All we have to do is select them in the Project Area and then drag them right into the Scene:
Create Sunflower Animation

Once we drag it into the scene, Unity asks us where to save the Animation. We can create a new SunflowerAnimation folder in our Project Area and then save it as idle.anim.

Unity then creates two files for us:
Sunflower Animation Files

This is what our animation looks like if we press Play:
Animated Sunflower
Note: we can modify the animation speed by double clicking the sunflower_0 file in the SunflowerAnimation folder, selecting the idle state and then changing the speed in the Inspector.

Physics, Tags and Health

Our plant should be part of the physics world, which means that we have to assign a Collider to it. A Collider makes sure that things will collide with the plant and that the plant will collide with other things.

Let's select the plant and then press Add Component->Physics 2D->Box Collider 2D in the Inspector:
Plants Collider

We will also need to find out if a certain GameObject is a Plant, a Zombie or something completely different. This is what Unity's Tag system is for. If we take a look in the Inspector, we can see that the current tag is Untagged:
Plants untagged

We can assign the Plant tag by selecting Add Tag... in the Tag list, then adding the Plant tag to the list of available tags, selecting the plant again and then assigning the Tag from the Tag list:
Plants Tagged

Finally we will select Add Component->Scripts->Health in the Inspector, so the Zombies can deal damage to the plant later on:
Health Script in Inspector

Note: our Sunflower was just placed somewhere randomly in the Scene. We will keep it in there for now as long as we are working on the sun spawns in the next step. Proper positioning on a grass tile will be implemented later on.

Spawning Suns

Drawing the Sun

The Sunflower plant is supposed to spawn a new sun every few seconds, so let's start by drawing one:
Pixel Art Sun
Note: right click on the image, select Save As... and save it in the project's Assets/Sprites folder.

We will use the following Import Settings:
Sun ImportSettings

The Foreground Layer

We want the sun to be drawn in front of the background and in front of the plants. Let's click on Add Sorting Layer.. again and create another Sorting Layer, name it Foreground and move it to the bottom of the list:
Add Foreground Sorting Layer

Afterwards we can select the sun again and assign the Foreground Sorting Layer to it:
Sun Sorting Layer

Creating the Prefab

Let's drag the sun into the Hierarchy (or into the Scene) once in order to create a GameObject from our texture:
Creating the Sun GameObject

Now we take a look at the Inspector where we rename it to SunPrefab and press the Add Component button where we select Physics 2D->Circle Collider 2D. A Collider allows us to do some physics stuff with the Sun later on:
Sun Prefab in Inspector

Note: In the original Plants vs. Zombies game the Sun doesn't really collide with the plants or the zombies. We can achieve this behavior by selecting Is Trigger in the Circle Collider 2D. This means that the sun receives collision information, but never really collides with anything. The zombies will be able to walk right through it, instead of colliding with it.

Afterwards we drag it from the Hierarchy into a new Prefabs folder in the Project Area to create a Prefab:
Create Sun Prefab

Now we can delete it from the Hierarchy.

Note: the sun will later be loaded into the Scene by using the Instantiate function. We can't just use the Sun Texture because we really do need a GameObject with Colliders and everything.

Creating the Spawn Script

We want the sunflower to spawn a new sun every few seconds. This kind of behavior can be implemented with Scripting. Let's select our sunflower and then click on Add Component->New Script:
New Script

We will name it SunSpawn, select CSharp as the language and then move it into our Scripts folder in the Project Area. Afterwards we will open it:

using UnityEngine;
using System.Collections;

public class SunSpawn : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

We will add a public GameObject variable that allows us to specify the Prefab later on in the Inspector:

public class SunSpawn : MonoBehaviour {
    public GameObject prefab;
    ...

The Instantiate function allows us to load a Prefab into the Scene. The InvokeRepeating function allows us to call a certain function repeatedly, starting at some time in the future. For example, if we would want to spawn something the first time in 1 second and then repeat that every 2 seconds, we would use InvokeRepeating("Spawn", 1, 2). We want the first sun to be spawned in 10 seconds and then keep spawning more suns every 10 seconds, so here is our code:

using UnityEngine;
using System.Collections;

public class SunSpawn : MonoBehaviour {
    public GameObject prefab;

    // Use this for initialization
    void Start() {
        // Spawn first Sun in 10 seconds, repeat every 10 seconds
        InvokeRepeating("Spawn", 10, 10);
    }
   
    void Spawn() {
        // Load prefab into the Scene
        // -> transform.position means current position
        // -> Quaternion.identity means default rotation
        Instantiate(prefab,
                    transform.position,
                    Quaternion.identity);
    }
}

Now we can save the Script and take a look at the Inspector again. The Script has a Prefab property because our prefab variable was public. Let's drag our SunPrefab from the Project Area into the Prefab slot of the Script:
Sunflower SunSpawn Script Prefab

If we press Play then we can see a new Sun spawn every 10 seconds.

Sun Movement

After a sun spawned it should slowly fade away towards the top of the screen. We will use a Rigidbody2D for that. A Rigidbody is usually used for everything in the physics world that is supposed to move around.

Let's select the sun in the Project Area and then click on Add Component->Physics2D->Rigidbody2D in the Inspector. We will assign the following properties to it:
Sun Rigidbody

Now all we have to do is give the Rigidbody some velocity (which is movement direction * speed). The following image shows the different vectors needed for certain movement directions:
Vector3 Directions

We will create another C# Script, name it DefaultVelocity and then use it to set the velocity all the time:

using UnityEngine;
using System.Collections;

public class DefaultVelocity : MonoBehaviour {
    // The Velocity (can be set from Inspector)
    public Vector2 velocity;

    void FixedUpdate () {
        GetComponent<Rigidbody2D>().velocity = velocity;
    }
}

Note: we set it in each FixedUpdate call so that whatever has this script attached to it will try to keep moving no matter what happens. This is useful for the Zombies that might not be able to keep moving when running into a plant, but our Script will make sure that they start moving again as soon as the plant was destroyed.

Afterwards we select the sun prefab again and then add the Script to it by clicking on Add Component->Scripts->Default Velocity. We will also assign a velocity that goes upwards (into the y direction):
Sun DefaultVelocity Script

If we press Play then we can now see the sun spawn and move upwards afterwards:
Sun moving upwards

Collecting Sun

The last thing we have to do when it comes to the sun is to allow the player to collect it. We will need one global score that keeps track of how many suns were collected, and we will need to increase that score whenever the player clicks on a sun.

Unity comes with a OnMouseDown function that allows us to find out if our GameObject was clicked. So let's create a new C# Script, name it SunCollect and then use the OnMouseDown function:

using UnityEngine;
using System.Collections;

public class SunCollect : MonoBehaviour {
    // Global score
    public static int score = 100;

    void OnMouseDown() {
        // Increase Score
        score += 20;

        // Destroy Sun
        Destroy(gameObject);
    }
}

Note: we have to use static in order to make the score variable global. This means that it can be accessed by other scripts with SunCollect.score any time. The initial score value is 100 so the player has some sun to start building plants with.

Once we added the Script to the sun Prefab we can press Play, wait for a sun to spawn and then collect it by clicking on it.

Cleaning Up the Hierarchy

Right now the Sunflower is still in the Hierarchy, but we don't want it to be in there from the beginning. The player is supposed to build it manually later on. So let's create a Prefab from it by dragging it into the Project Area:
Sunflower Prefab

The Firing Plant

The Image

Alright let's create one more plant, the type that is able to shoot at the Zombies.

. . .

Premium Tutorial

Enjoyed this preview? Become a Premium member and access the full Unity 2D Plants vs. Zombies Tutorial!

All Tutorials. All Source Codes & Project Files. One time Payment.
Get Premium today!