Unity: Creating Game Objects at runtime using Prefabs
Now that you have understood some of the basics of working with Unity, and have made a game or two by yourself, let's try and dig in deeper, shall we? After all, we have just scraped the surface of the iceberg that is Unity!
First of all, it's time to say goodbye to Mr. Star. He's been a good friend of ours for the journey up until now, but for what we have ahead, we need something a bit more complex, and a star drawn hastily in Paint.NET in mere 13 seconds doesn't really fit that description.
So what does fit that description? This, I guess...
Now, we'll be understanding more fundamental concepts related to Unity, more focused on gameObjects and prefabs.
Understanding Prefabs and Instantiation
Okay, so the word Prefab
looks a bit scary, doesn't it? Don't worry, it's not, in fact, it's one of game designer's best friends when it comes to creating gameObjects in real-time. So what exactly is a prefab? Well, a prefab is actually a blueprint or a template for a specific gameObject. We know this is kind of confusing to understand at first, so let's take a very basic example.
Imagine we are making a basic space shooter game, and this here, little fellow, is an enemy character.
Now, if we wanted to build a game scene in Unity with our main character, and an enemy, it would look something like this:
Sure, this is perfectly fine for when you have one enemy, but what if you wanted a lot of them? Not 2 or 3, assume like 15 or 20. As a beginner learning Unity, you might be thinking something along these lines: Using the same asset, multiple times by creating copies.
Ok, that's also a viable solution, we suppose, but what if every sprite has its own AI and its own custom properties? Would you really like, going through the trouble of adding a Rigidbody and Colliders to every single sprite? What if you wanted to generate more of these enemies, during gameplay and not during the scene making process? We would seriously not recommend placing every single enemy yourself, or your game might become really predictable and boring.
What if we could define a single enemy, and have something generate copies of that enemy, since they're all the same? Well, the prefab is what solves exactly that.
A PreFab is a definition of a gameObject which we want to generate, and it produces an exact copy of the defined gameObject, whenever you need it, wherever you need it. This proves tremendously useful when you need to generate gameObjects on the fly, like bullets, aliens, coins etc, since Unity does most of the work here, making the gameObjects instantly available for us.
Using Prefab to generate Game Object at runtime
Let's put this to use. We'll start with a very simple exercise, to spawn a box every time we press the Spacebar. First of all, let's create a spawner. Now we don't really need a spawner to have graphics, just an empty gameObject will do. So, what you do is right-click in the Hierarchy, and click on Create Empty.
You should see a new GameObject appear in the Hierarchy. But nothing appears on the screen. Because this is an empty gameObject, it doesn't have any components except a Transform. Remember that a Sprite Renderer is also a component. Since this gameObject doesn't have such a component, it simply doesn't render anything. It's simply, there. Empty gameObjects are really useful for things like spawners and reference points, since they're invisible during gameplay.
You can always check where an empty gameObject is by simply clicking on the gameObject in the Hierarchy. It should then show you the location of that gameObject with a translucent circle. Anyways, let's rename our empty gameObject to Generator, just so we know what it actually is. We will leave you to find out how to rename the gameObject, it's quite simple.
Now, let's create the actual box to generate. Create a sprite using the default sprite menu we used to generate that blockade back in the previous tutorials. (It doesn't really have to be a box, you can use any sprite. We are using the default square sprite for the sake of simplicity).
Now, let's add a Rigidbody2D
to the box, just to give it weight so it falls down when it's generated. That means we won't be modifying our gravity scale. (Or if you're the persistent type, set it to any value other than zero). Hit play button to test out your box. If it falls down, you're on the right track.
Now, remember how you added Mr. Star to the scene back when you were getting started? You dragged the sprite from the Assets to the Hierarchy.
Creating a prefab is the reverse of that process. You drag an existing gameObject from the Hierarchy to the Assets. Unity then generates a prefab of that gameObject in the folder you dragged it into. So, since we want to make a template of the Box, we will just drag the box sprite from the Hierarchy into our Prefabs folder.
You should see something new appear in your Prefabs folder. It's the exact same image of the box, but it appears in a grey container. That's your prefab! Easy, wasn't it? Now, to generate an instance of this prefab whenever the Spacebar is pressed, we will need to write a tiny script for the Generator. For the sole purpose of generating a box whenever you press the Spacebar, the following code is perfect.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Generator : MonoBehaviour
{
public GameObject boxToGenerate;
void update()
{
// When spacebar is hit
if(Input.GetKeyDown(KeyCode.Space))
{
// instantiate the box object
Instantiate(boxToGenerate);
}
}
}
You remember how to create a new script and rename it, right? If not, check the last tutorial. We will also name our script as Generator
.
Note how the Start()
method is missing here. Getting rid of empty the Start()
and Update()
methods is something which you should do, and is quite recommended when developing in Unity.
- Line 7: You should be familiar with this line by now. It's a declaration to Unity to ask it for a gameObject to generate, by making that slot in the editor we saw earlier.
- Line 11: This has some interesting stuff going on. The
Input
class, as we know, contains definitions for various methods of providing input to the game. This includes mouse buttons, gamepad keys and keyboard keys.
In our case, we're using the GetKeyDown
method. This detects when a key has just been pressed. Other methods for keyboards are GetKey
(detects a keypress that is then held) and GetKeyUp
(detects the key which is just released). Inside the GetKeyDown
method, we have an enum as a parameter, the KeyCode
enum. It's basically an enumerated list of all the keys on a keyboard.
- Line 12: As you can guess, this is the main magical line, as we've been calling it. The
Instantiate
method is a method in the GameObject
class (note the capital G), which has a few overloaded variations. The main parameter across all these overloads, however, is the actual gameObject to instantiate, or, generate. Since we want to generate the box that we plug in the editor, we will supply the boxToGenerate
as the parameter. Simply save and attach this script to the Generator gameObject in the editor.
Now, to fill in the Box To Generate slot that appears in the script's properties, we will simply click on the circle-dot, and pick our box's prefab. Alternatively, you can just drag and drop the box prefab into the slot. What this is doing is telling Unity what to generate. boxToGenerate is simply the name of the gameObject variable, that variable still needs to be something.
Save your work in a new scene, and click play. If everything goes right, a new box should get generated whenever you press the Spacebar.
If you pay attention to the Hierarchy, you'll notice that you're generating a new Box(Clone) every time. Even though they fall off the screen, they're still in the hierarchy.
Here's where we should warn you to not generate too many of them, since they'll just fall indefinitely and too many of them could start lagging the program. I'll explain how to destroy objects later on.