Gigi Labs

Thursday, May 30, 2013

Unity3D: Space Invaders (Part 3 - Prefabs)

This article continues with the Ranch Invaders series. However, like with yesterday's article, if you haven't read the previous articles, you can simply follow along by creating a new Unity project.

In today's article, we're going to add the player's ship into the game, and allow it to shoot bullets. In doing this, we will learn what prefabs are, and how to create objects while the game is running.

From the GameObject menu, go to Create Other -> Sphere. In the Hierarchy section, select the Sphere, press F2, and rename it to "Player". Move it so that it appears in the bottom of the camera's view (you might want to select the Main Camera to see its preview while you do this).

Next, from the GameObject menu, go to Create Other -> Capsule. Rename it to "Bullet". After pressing the 'R' key to go into scaling mode, resize the bullet (capsule) so that it is much smaller than the player (sphere).

Your work so far might look something like this:

Now, from the Hierarchy panel, drag the Bullet into the Assets panel:

The result is that the Bullet is added to the Assets panel, and in the Hierarchy panel, its entry turns blue. This means that the Bullet is now a prefab.

The Player and the Alien objects are simply objects in the scene. Since the Bullet is a prefab, we can refer to it in scripts and create as many Bullets as we like through code. A great thing about prefabs is that you can customise the prefab once (e.g. make a bullet with a yellow material), and all instances of that prefab will have the same features. Let's see how this works in practice.

In the Assets panel, right click somewhere, and in the context menu, select Create -> Material. Name it "Bullet". In the Main Color property, select whichever colour you think is best for a bullet (e.g. yellow). Drag the material onto the Bullet object either in the Hierarchy panel or in the world view:

Right click the Assets panel and Create -> C# Script. Name it "Bullet". Drag the script onto the Bullet object. Double-click the script to launch MonoDevelop.

In the Bullet class, add a public variable to represent the speed:

public float speed = 1.0f;

When you expose a public variable like this, it appears in the Inspector in the section where the script is:

You can now change this variable as you like through the Inspector, and when you Play the game in Unity, that value will be used. Note, however, that if you change such variables while Playing, changes will be reverted once you stop playing.

Now, we need to write a script that will take care of the bullet's movement. Since we're doing Sp-- sorry, Ranch Invaders, we're looking to do something like this:

The bullet starts at the player's position, and is shot upwards where the Aliens will be. In code, we can do this as follows:

Remember that we're going to have the Player create (shoot) bullets. When the bullets are created, they will be at the Player's position. We want the bullets to go upwards, so we define a target that is a certain distance away (e.g. 20 units). By adding a Vector3(0, 20, 0) that simply points directly upwards, to the initial bullet position, we can set a destination for the bullet that is directly above its starting position.

In the Update() method, we use Vector3.MoveTowards() which works pretty much like Lerp (see yesterday's article). Except that instead, we are moving the Bullet from its current position towards the target in steps of speed * Time.deltaTime. Time.deltaTime is a measure of frame time, so the bullet will move a short length upwards with every frame. We multiply speed to be able to control the speed.

From the Unity editor, press the Play button and watch the bullet move upwards. If you think it's too fast or too slow, tweak the speed by selecting the Bullet and changing the speed value in the Inspector.

You can now delete the Bullet from the scene. Since it's among our Assets, we can create it at runtime. Create a new C# script called "Player" and drag it onto the Player object. Double-click the Player script to open it in MonoDevelop.

In the Player class, add the following public variable:

public GameObject bullet;

Save the script. Back in Unity, select the Player object, and in the Inspector, under the Player Script, notice that there is now a slot for the bullet game object:

From the Assets panel, drag the Bullet prefab into the appropriate slot in the Inspector, where it currently says "None (Game Object)".

Now, from the Player script, we can make instances of this prefab. In the Update() method of the Player script, just add the following:

So all we're doing here is that when the player presses the Space key, we use the Instantiate() method to create a bullet. We give it the object we want to instantiate (in this case the bullet prefab), and its starting position and orientation (rotation). I'm not going to go into quaternions here, but Quaternion.identity simply means that the bullet isn't rotated.

You can now press Play to try out the game. Press Space to watch bullets move like sausages in the sunset:

If it doesn't work, don't worry! :) Depending on how you carried out the steps above, it is possible that the bullet prefab wasn't saved correctly. In my case, for example, I found that the Bullet script was missing. Since a prefab is really just a template for an object, you need to make sure that any changes to it apply to all the objects that use that template. So in the case of the missing script, once you drag the Bullet script onto a Bullet object in the scene, you need to click "Apply" at the top of the Inspector in order to apply the changes to all affected objects.

Great! We can now shoot sausage-like bullets to our heart's content. We still have some work left to do, though: we need more aliens, the player's ship needs to move sideways, bullets need to destroy aliens, etc. We'll handle some of these things in the next article. Until then, au revoir! :)