Home and Learn: Games Programming Course


How to Create a Prefab in Unity

It would be a pretty easy game if you only had 1 zombie to kill. In this lesson, you'll learn how to create a prefab from our single zombie. We can then instantiate as many zombies as we want from our daddy zombie prefab.

 

What are Prefabs?

Prefabs in Unity are a way to create reusable game objects with predefined properties. Think of them as templates-once you create a prefab, you can instantiate multiple copies of it in your game without having to manually configure each one. Think of our zombie. It has lots of components attached to it. If we wanted to add a second zombie to the scene, we could create a new zombie and then add in all the same components. But that would be laborious. Instead, we can just create a prefab of the zombie we have. We can use that prefab in our code to spawn as many zombies as we want.

Why Are Prefabs Useful?

1. Efficiency - Instead of recreating objects manually, you can instantiate prefabs dynamically.
2. Consistency - Every instance of a prefab maintains the same properties, ensuring uniformity.
3. Easy Updates - If you modify the prefab, all instances automatically update.
4. Performance Optimization - Prefabs help manage memory efficiently, especially when spawning multiple objects.
5. Dynamic Instantiation - Prefabs allow you to spawn objects at runtime, such as zombies and bullets.

So let's prefab the one single zombie in our scene. There's quite a lot of work to do to get him ready!

 

Our Lonely Zombie

If you click on your zombie in the Hierarchy, then take a look at the Inspector on the right, you should see this:

A ganme object in Unity with lots of components attached

Not including the Transform, our zombie has 9 components. We can actually get rid of the Audio Source component. If we kept it, then each zombie we added to the scene would play the same sound, and at the same time. Not exactly efficient! Instead, we can play one sound in the background. When the last zombie is killed, we can also kill the sound.

So remove the Audio Source by clicking the three dots indicated by the red arrow above. You should see this menu appear:

Unity menu to remove a component from a game object

Select Remove Component from the ment to get rid of the Audio Source. We'll add a new audio source soon.

 

Zombie Following the Player

If you remember, we wrote a script to get the zombie to follow the player. We called this script, not surprisingly, ZombieFollowPlayer. We'll need to adapt this script. It's this, at the moment:

using UnityEngine;
using UnityEngine.AI;

public class ZombieFollowPlayer : MonoBehaviour
{
	private NavMeshAgent enemy;
	public GameObject player;

	void Start()
	{
		enemy = GetComponent<NavMeshAgent>();
	}

	void Update()
	{
		enemy.SetDestination(player.transform.position);
	}
}

The problem is this line:

public GameObject player;

It is a public GameObject variable. When you create public GameObject variables like this, it adds a slot in the Inspector where you can drag your game object onto it. We dragged the player from the Hierarchy into the Inspector. But, when you are creating prefabs, Unity will remove your GameObject from the slot in the Inspector. Which means you'll have to add it back in for each zombie you create. Which kind of defeats the purpose of a prefab. Instead, we can adapt our script.

Change it to this (you can copy and paste this over the one you have):

using UnityEngine;

using UnityEngine.AI;

public class ZombieFollowPlayer : MonoBehaviour
{

	private NavMeshAgent enemy;
	private GameObject player;

	void Start()
	{
		enemy = GetComponent<NavMeshAgent>();
		player = GameObject.FindWithTag("CinemachineTarget");
	}

	void Update()
	{
		enemy.SetDestination(player.transform.position);
	}
}

The new version of your script should look like this in your editor:

Unity C# script to get a game character to follow the player

Note the player GameObject is a private variable. To get the player object, we have this line:

player = GameObject.FindWithTag("CinemachineTarget");

Unity can find any object that has a Tag set up. Here, we want to find a Tag called CinemachineTarget. Once found, it will end up in the player variable. No more public GameObjects!

Save your code and go back to Unity. We now need to add a Tag called CinemachineTarget.

 

Camera Tags

When we added Unity's First-Person Character Controller, it came with cameras attached. There is an object called Player Follow Camera, which you can see in the Hierarchy if you expand your Player object:

A Player camera object in the Unity Hierarchy

Now look at the Inspector on the right. Notice that the Follow slot is filled with the Player Camera Root:

The Unity Inspector showing the Follow property highlighted

So this camera is going to track the game object called PlayerCameraRoot.

Select PlayerCameraRoot in the Hierarchy:

Unity Hierarchy with a Player camera object selected

In the Inspector on the right, notice the Tag:

The Tag property highlighted in the Unity Inspector

If yours doesn't say CinemachineTarget, click the dropdown and add a new tag:

The Tag dropdown list with the Add Tag item selected

Click the plus button. Add a new tag with the name CinemachineTarget: (Make sure you spell it correctly.)

Setting up a new tag in Unity

Click back on PlayerCameraRoot in the Hierarchy. Select your new Tag from the list.

 

Creating the Prefab

Now we are ready to create the prefab. This is easy to do.

Create a folder for yourself in the Projects area at the bottom of Unity. Select your zombie in the Hierarchy. Now drag and drop your zombie into your new folder (if you get a message box popping up, select Original Prefab):

A prefab showing in the folder area of Unity

And that's it - one zombie prefab created!

With the prefab selected in your folder, notice the Inspector on the right:

A prefab showing in the Unity Inspector

If all went well, it should say Prefab Asset at the top. You should also have the prefab model displayed at the bottom.

You can make changes to your prefab here, if you need to.

You can also add other prefabs. If you were to drag a new zombie into your prefab folder, you'll get a message box like this one:

A prefab message box in Unity

If you want a new zombie prefab, select the first option, Original Prefab. If you just want a variant of the prefab you have, select Prefab Variant. (You might have added a new component to the zombie in the Hierarchy, for example. This would then be a variant.)

 

Zombie Scripts to Instantiate more Zombies in your Game

We'll need to add two more scripts. These will be a script to manage our zombies, and a script to spawn the zombies in the game.

In the Hierarchy on the left, create two new empty game objects (right click in the Hierarchy and select Create Empty from the menu that appears). Call one of them ZombieManager and the other ZombiesSpawn: (It doesn't actually matter what you call them.)

Two empty game objects showing in the Unity Hierarchy

Select just your ZombieManager empty game object in the Hierarchy. In the Inspector on the right, click the Add Component button. Add an Audio Source. Just like before, select one of your zombie sounds for the Audio Resource. Uncheck Play on Awake, but check Loop. This will be the sound that plays for all zombies, a kind of generic zombie groaning. We'll stop this sound when the last zombie is killed.

Click the Add Component button again. This time, add a New Script. Call the script ZombieManager. The Inspector will then look like this:

A game object with a script and an audio source

Now double click the name of the script in the Inspector. This will open it up in your coding editor. Select all the default code. Delete it and replace it with this:

using UnityEngine;

public class ZombieManager : MonoBehaviour
{
	private AudioSource backgroundSounds;
	public static ZombieManager instance;
	public static int zombieCount ;

	private void Awake()
	{
		backgroundSounds = GetComponent<AudioSource>();

		instance = this;

		backgroundSounds.Play();
	}

	public void RegisterZombie()
	{
		zombieCount++;
		Debug.Log("ZOMBIES IN SCENE = " + zombieCount);
}

	private void Update()
	{
		if (zombieCount <= 0)
		{
			backgroundSounds.Stop();
		}

	}

	public void ZombieKilled()
	{
		zombieCount--;
		Debug.Log("ZOMBIES LEFT = " + zombieCount);
	}
}

Your code editor should look like this:

C# script to manage a game object in Unity

The script has four methods: Awake, Update, RegisterZombie, and ZombieKilled. What we're doing here is keeping track of how many zombies are in the scene. We do this with the zombieCount variable. It's a public static variable that we can access in our next script. (We're also playing the zombie audio sound here, as well.)

Save your work and go back to Unity.

 

Zombie Spawner Script

In the Hierarchy on the left, select your ZombiesSpawn empty game object. In the Inspector on the right, click the Add Component button. Add a New Script. Call it ZombieSpawner. Double click the name of your new script to open it up in your code editor.

Once your code opens, delete the default code. Replace it with this:

using UnityEngine;

public class ZombieSpawner : MonoBehaviour
{
	public GameObject zombiePrefab; 

	private void Start()
	{
		SpawnZombies();
	}

	void SpawnZombies()
	{
		Vector3[] spawnPositions = {
			new(-5, 0, -27),
			new(27, 0, -24),
			new(14, 0, -30),
			new(58, 0, -27),
			new(37, 0, -57),
			new(5, 0, -75),
			new(50, 0, -75)
		};

		foreach (Vector3 pos in spawnPositions)
		{
			_ = Instantiate(zombiePrefab, pos, Quaternion.identity);
			ZombieManager.instance.RegisterZombie();
		}
	}
}

In the code above, we set up a public GameObject called zombiePrefab. The start method is just calls our one method, which is SpawnZombies. This is the method that does the work of creating zombies for us.

The variable spawnPositions in the code above is an array. It's an array of type Vector3. A Vector 3 needs three values, one for X, one for Y, and one for Z. For us, these values will be the positions of each zombie in the scene. We could have created random numbers for these positions, but this would be no good. If we did that, there's a very good chance you'd create a zombie that ends up inside of the church and won't be able to get out, or you might spawn one inside of a wall!

Instead of random spawning zombies, we've hard-coded ours. So, the first zombie will be placed at position -5 for its X Transform, 0 for its Y Transform (it's on the ground), and -27 for the Y Transform.

However, your zombies might not be good in these hard-coded positions. To get your own numbers for the spawnPositions array, go back to Unity. Click on your zombie in the Hierarchy. Note its position in the scene. If you like the position of this zombie, have a look at the Inspector on the right:

The Unity Inspector showing the Transform postion of a game object

Note the Transform section and the positions. This zombie has the following values:

Position X: 40
Position Y: 0
Position Z: -53

Now go back to your code. In your array, you can change the values. Your first line would then be this:

new(40, 0, -53),

Go back to Unity again. Move your zombie around to get a second position, and three new Vector 3 values. Go back to your code and enter the new numbers. Keep doing this until all your array values have the Vector 3 values you want.

Incidentally, you don't have to have 7 new Vector 3 values. You can add as many as you want, or even just a few. If you are adding more, don't forget to add a comma after the new Vector 3, unless it's the last one, where you don't need a comma at all.

One last thing about this script - note the for each loop:

foreach (Vector3 pos in spawnPositions)
{

_ = Instantiate(zombiePrefab, pos, Quaternion.identity);
ZombieManager.instance.RegisterZombie();

}

We're looping through each of the slots in the spawnPositions array (there's one slot for each Vector 3 position you added).

Inside the loop, we instantiate a new zombie:

_ = Instantiate(zombiePrefab, pos, Quaternion.identity);

This just says, instantiate a zombie prefab at the position in the array. The Quaternion.identity part just makes sure it keeps the zombie's rotation.

The other line is this:

ZombieManager.instance.RegisterZombie();

This line accesses our ZombieManager script. We need to call our RegisterZombie method. This is the method that keeps track of how many zombies are in the scene.

 

Save your script and go back to Unity.

You should see an empty slot under your script name called Zombie Prefab. This is because of this line in the code:

public GameObject zombiePrefab;

It's a public GameObject. This will create the empty slot in the Inspector.

In your Prefab folder, drag and drop your prefab zombie onto the slot:

A prefab added as a value for the C# script to spawn zombies

 

Kill Zombie Script

One last thing to do and that's to tweak our KillZombie script. This script is attached to the zombie prefab. It's this, at the moment:

using UnityEngine;

public class KillZombie : MonoBehaviour
{

	private Animator enemy_anim;

	private void OnTriggerEnter(Collider other)
	{
		if (other.CompareTag("Bullet"))
		{
			enemy_anim = GetComponent<Animator>();

			enemy_anim.Play("Die");

			Destroy(gameObject, 2.5f);
		}
	}
}

Double click the name of this script from your zombie prefab. When it opens up in your code editor, delete the whole script. Replace it with this code:

using UnityEngine;

public class KillZombie : MonoBehaviour
{
	private Animator zombieAnimator;

	private void OnTriggerEnter(Collider other)
	{
		if (other.CompareTag("Bullet"))
		{
			Destroy(other);

			zombieAnimator = GetComponent<Animator>();
			zombieAnimator.Play("Die");

			Destroy(gameObject, 0.5f);

			ZombieManager.instance.ZombieKilled();
		}
	}
}

It should look like this in your editor:

A C# script to kill and destroy game objects in Unity

We've changed the name of the private Animator to zombieAnimator. The first line in the OnTriggerEnter code is now this:

Destroy(other);

This destroys the bullet object when it hits the zombie. If we didn't do this, it might register 2 kills instead of 1.

We've also reduced the time for the zombie to die to 0.5f (half a second).

The final line calls our ZombieManager script:

ZombieManager.instance.ZombieKilled();

We need to use our ZombieKilled method to register that fact there is one less zombie in the world.

 

Save your code and go back to Unity.

One last thing you can do before trying it out is to delete the zombie in the scene as you don't need it anymore.

Finally, after all that hard work, it's time to try it out. Here's a video of ours:

 

End Notes

One issue is that all the zombies look the same. But, now that you know how to create prefabs, you could create a new zombie prefab, make him faster, more deadly, put different animations on him, then instantiate that zombie in the script as well. However, we'll wrap it up there. Obviously, there's a great deal more that can be done to the game itself, such as adding a respawn point for when the player dies, player dying animations, game over screens, etc. But we'll move on as we've covered these things in other tutorials.

<--Back to the Unity 3D Course Contents Page

 


Email us: enquiry at homeandlearn.co.uk