Part III. Unity Lab 3: GameObject Instances

C# is an object oriented language, and since these Head First C# Unity Labs are all about getting practice writing C# code, it makes sense that these labs will focus on creating objects.

In Chapter 3 we learned about creating objects in C#, using a class as a template to create instances of it, where each instance gets its own fields. In this Unity Lab you’ll create instances of a Unity GameObject and use them in a complete, working game.

The goal of the next two Unity Labs is to create a simple game using the familiar billiard ball from the last Lab. In this Lab, you’ll build on what you learned about C# objects and instances to start building the game. You’ll use a prefab—Unity’s tool for creating instances of GameObjects—to create lots of instances of a GameObject. And you’ll use scripts to make your GameObjects fly around your game’s 3D space.

Let’s build a game in Unity!

Unity is all about building games. So in the next two Unity Labs, you’ll use what you’ve learned about C# to build a simple game. Here’s the game that you’re going to build:

Images

So let’s get started. The first thing you’ll do is get your Unity project set up. But this time we’ll keep the files a little more organized, so you’ll create separate folders for your materials and scripts—and one more folder for prefabs (which you’ll learn about later in the Lab).

  1. Before you begin, close any Unity project that you have open. Also close Visual Studio—you’ll let Unity will open it for you.

  2. Create a new Unity project using the 3D template, just like you did for the previous Unity Labs. Give it a name to help you remember which Lab it goes with (“Unity Labs 3 and 4”).

  3. Choose the “Wide” layout so your screen matches the screenshots.

  4. Create a folder for your materials underneath the Assets folder. Right-click on the Assets folder in the Project window and choose Create >> Folder. Name it Materials.

  5. Create another folder under Assets named Scripts.

  6. Create one more folder under Assets named Prefabs.

Images

Create a new material inside the Materials folder

Double-click on your new Materials folder to open it. You’ll create a new material here.

Go to https://github.com/head-first-csharp/fourth-edition/tree/master/Unity%20Labs/Billiard_Balls and download the texture file 1 Ball Texture.png into a folder on your computer, then drag it into your Materials folder—just like you did with the downloaded file in the first Unity Lab, except this time drag it into the Materials folder you just created instead of the parent Assets folder.

Now you can create the new material. Right-click on the Materials folder in the Project window and choose Create >> Material. Name your new material 1 Ball. You should see it appear in the Materials folder in the Project window.

Images
Note

In the first Unity Lab you had Unity create a material automatically for you by dragging a texture map file onto a GameObject. This time you’re creating the material manually. Just like last time, you may need to click the Download button on the GitHub page to download the PNG image file.

Make sure the 1 Ball material is selected in the Materials window, so it shows up in the Inspector. Click on the 1 Ball Texture file and drag it into the box to the left of the Albedo label.

Images

You should now see a tiny little picture of the 1 ball texture in the box to the left of Albedo in the Inspector.

Images

Now your material looks like a billiard ball when wrapped around a sphere.

Images

Spawn a billiard ball at a random point in the scene

Create a new Sphere GameObject with a script called OneBallBehaviour:

  • Choose 3D >> Sphere from the GameObject menu to create a sphere.

  • Drag your new 1 Ball material onto it to make it look like a billiard ball.

  • Next, create a new folder under Assets in the Project window. Name your new folder Scripts. Then right-click on the new folder and create a new C# script named OneBallBehaviour.

  • Drag the script onto the Sphere in the Hierarchy window. Select the Sphere and make sure a Script component called “One Ball Behaviour” shows up in the Inspector window.

Double-click on your new script to edit it in Visual Studio. Add exactly the same code that you used in BallBehavior in the first Unity Lab, then comment out the Debug.DrawRay line in the Update method.

Your OneBallBehaviour script should now look like this:

Images

Now modify the Start method to move the sphere to a random position when it’s created. You’ll do it by setting transform.position, which changes the position of the GameObject in the scene. Here’s the code to position your ball at a random point—add it to the Start method of your OneBallBahaviour script:

Images

Use the Play button in Unity to run your game. A ball should now be circling the Y axis at a random point. Stop and start the game a few times. The ball should spawn at a different point in the scene each time.

Use the debugger to understand Random.value

You’ve used the Random class in the .NET System namespace a few times already. You used it to scatter the animals in the animal match game in Chapter 1 and to pick random cards in Chapter 3. But this Random class is different—try hovering over the Random keyword in Visual Studio.

Images

You can see from the code that this new Random class is different than the one you used before. Earlier called Random.Next() to get a random value, and that value was a whole number. This new code uses Random.value, but that’s not a method—it doesn’t end with parentheses. (It’s actually a property, which you’ll learn about in Chapter 5.)

Let’s use the Visual Studio debugger to see the kinds of values that this new Random class gives you. Use the Attach to Unity button (Images) to attach Visual Studio to Unity. Then add a breakpoint to the line you added to the Start method.

Now go back to Unity and start your game. It should break as soon as you press the play button in Unity. Hover your cursor over Random.value—make sure it’s over value. Visual Studio will show you its value in a tooltip:

Images

Move your mouse cursor off of value, then go back and hove over it again. Do it a few more times. You’ll get a different random value each time. That’s how UnityEngine.Random works: it gives you a new random value between 0 and 1 each time you access its value property.

Press Continue (Images) to resume your game. It should keep running—the breakpoint was only in the Start method, which is just called once for each GameObject instance, so it won’t break again. The go back to Unity and stop the game.

Note

You can’t edit scripts in Visual Studio while it’s attached to Unity, so click the square Stop Debugging button to detach the Visual Studio debugger from Unity.

Turn your GameObject into a prefab

In Unity, a prefab is a GameObject that you can instantiate in your scene. In Chapter 2 you learned about instances, and how you can create objects by instantiating a class. Unity makes it really easy to take advantage of objects and instances, so you can build games that reuse the same GameObjects over and over again. Let’s turn your one ball GameObject into a prefab.

Go to the Hierarchy window, select your Sphere, and rename it by pressing F2 (or right-click and choose Rename). Change the name to OneBall.

Images
Note

If you try to edit your code but find that Visual Studio wouldn’t let you make any changes, that means Visual Studio is probably still attached to Unity! Press the square Stop Debugging button to detach it.

You might have noticed that the name changed in the inspector window.

Images

Now we can turn your GameObject into a prefab. Use the Project window to create a new folder under Assets called Prefabs, then drag OneBall from the Hierarchy window into the Prefabs folder.

Images

OneBall should now appear in your Prefabs folder. And notice that OneBall is now blue in the Hierarchy window. This indicates that it’s now a prefab – Unity turned it blue to tell you that an instance of a prefab is in your hierarchy. That’s fine for some games, but for this game, we want all of the instances of the balls to be created by scripts.

Right-click on OneBall in the Hierarchy window and delete the OneBall prefab. You should now only see it in the Project window, and not in the Hierarchy window or the scene.

Images
Note

Have you been saving your scene as you go? Save early, save often!

Create a script to control the game

The game needs a way to add balls to the scene (and eventually keep track of the score, and whether or not the game is over). We’ll do this by adding a script called GameController.cs to the main camera.

Right-click on the Scripts folder in the Project window and create a new script called GameController. Your new script will use two methods available in any GameObject script:

  • The Instantiate method creates a new instance of a GameObject. When you’re instantiating GameObjects in Unity, you don’t typically use the new keyword like you saw in Chapter 2. Instead, you’ll use the Instantiate method, which you’ll call from the AddABall method.

  • The InvokeRepeating method calls another method in the script over and over again. In this case, it will wait one and a half seconds, then call the AddABall method once a second for the rest of the game.

Here’s the source code for it:

Images

Attach the script to the main camera

Your new GameController script needs to be attached to a GameObject to run. Luckily, the Main Camera is just another GameObject—it happens to be one with a Camera component and an AudioListener component—so let’s attach your new script to it. Drag your GameController script out of the Scripts folder in the Project window and onto the Main Camera in the Hierarchy window.

Images

You’ll see a component for it, exactly like you would for any other GameObject.

Images

The OneBallPrefab field still says None, so we need to set it. Drag OneBall out of the Prefabs folder and onto the box next to the One Ball Prefab label.

Images

Now the GameController’s OneBallPrefab field contains a reference to the OneBall prefab:

Images

Now back to the code and look closely the AddABall method. It passes the OneBallPrefab field to Instantiate. You just set that field so that it contains your prefab. So every time GameController calls its AddABall method, it will create a new instance of the OneBall prefab.

Press play to run your code

Your game is all ready to run. The GameController script attached to the Main Camera will wait 1.5 seconds, then instantiate a OneBall prefab every second. Each instantiated OneBall’s start method will move it to a random position in the scene, and its Update method will rotate it around the Y axis every 2 seconds using OneBallBehaviour fields (just like in the last Lab). Watch as the play area slowly fills up with rotating balls:

Images
Note

Unity calls every GameObject’s Update method before each frame. That’s called the update loop.

Note

When you instantiate GameObjects in your code, they show up in the Hierarchy window when you run your game.

Watch the live instances in the Hierarchy window

Each of the balls flying around the scene is an instance of the OneBall prefab. Each of the instances has its own instance of the GameController class. You can use the Hierarchy window to track all of the OneBall instances—as each one is created, a “OneBall(Clone)” entry is added to the Hierarchy.

Images

Click on any of the OneBall(Clone) items to view it in the Inspector. You’ll see its Transform values change as it rotates, just like in the last Lab.

Note

We’ve included some coding exercises in the Unity Labs. They’re just like the exercises in the rest of the book – and remember, it’s not cheating to peek at the solution.

Use the Inspector to work with GameObject instances

Run your game. Once a few balls have been instantiated, click the pause button—the Unity editor will jump back to the Scene view. Click one of the OneBall instances in the Hierarchy window to select it. The Unity editor will outline it in the Scene window to show you which object you selected. Go to the Transform component in the Inspector window and set its Z scale value to 3 to make the ball stretch.

Images

Start your simulation again—now you can track which ball you’re modifying. Try changing its DegressPerSecond, XRotation, YRotation, and ZRotation fields like you did in the last lab.

While the game is running, switch between the Game and Scene views. You can use the Gizmos in the scene view while the game is running, even for GameObject instances that were created using the Instantiate method (rather than added to the Hierarchy window).

Try clicking the Gizmos button at the top of the toolbar to toggle them on and off. You can turn on the Gizmos in the Game view, and you can turn it off in the Scene view.

Images

Use physics to keep balls from overlapping

Did you notice that occasionally some of the balls overlap each other?

Unity has a powerful physics engine that you can use to make your GameObjects behave like they’re real, solid bodies—and one thing that solid shapes don’t do is overlap each other. So to prevent that overlap, you just need to tell Unity that your OneBall prefab is a solid object.

Stop your game, then click on the OneBall prefab in the Project window to select it. Then go to the Inspector and scroll all the way down to the bottom to the Add Component button.

Images
Images

Click the button to pop up the Component window. Choose Physics to view the physics components, then select Rigidbody to add the component.

Images

Run your game again—now you won’t see balls overlap. Occasionally one ball will get created on top of another one. When that happens, the new ball will knock the old one out of the way.

Let’s run a little physics experiment to prove that the balls really are rigid now. Start your game, then pause it as soon as there are two balls created. Go to the hierarchy window. If it looks like this:

Images

Then you’re editing the prefab—click the Images button in the top right corner of the Hierarchy window to get back to the scene (you may need to expand SampleScene again).

  • Select the first OneBall instance and use its Transform component in the Inspector to set its position to (0, 0, 0).

  • Select the second OneBall instance and set its position to (0, 0, 0) as well.

  • Select all of the other instances, right-click, and choose Delete to delete them from the scene so only the two overlapping balls are left.

  • Unpause your game—the balls can’t overlap now, so instead they’ll be rotating next to each other.

Note

You can use the Hierarchy window to delete GameObjects from your scene while the game is running.

Images
Note

Stop the game in Unity and Visual Studio and save your scene. Save early, save often!

Get creative!

You’re halfway done with the game! You’ll finish it in the next Unity Lab. In the meantime, this is a great opportunity to practice your paper prototyping skills. We gave you a description of the game at the beginning of this Unity Lab. Try creating a paper prototype of the game. Can you come up with ways to make it more interesting?

Images