Welcome to the third and final part of this Unity mini-series! In this tutorial, you’ll learn all about Components in Unity while you give your hero free reign to blast the landscape with bullets!
This tutorial continues on from the previous tutorial, Unity Games, Part 2: GameObjects.
At this point, you’ve accomplished your goal of having all the main actors ready, but it’s essentially an empty stage. Sure, you might win some avant-garde awards for a poignant play on the lack of free will, but that’s not going to pay the bills.
In this tutorial, you’ll add some interactivity to your game through the use of Components, which are fundamental to Unity game development. If you were to think of a GameObject as a noun, then a component would be a verb: a component does something on behalf of a GameObject.
You’ll learn about several types of components, including the Rigidbody component, the script component, and more. By the end of this tutorial, your marine will be running and gunning!
Getting Started
You can continue on with your completed project from the last tutorial, or if you would prefer to start over fresh, you can download the starter project for this tutorial here.
Currently, the space marine only knows how to stand like a statue. He needs to move around if he’s going to avoid being some alien’s snack.
The first thing you’ll add is a Rigidbody component, which opts the GameObject into the physics engine. By adding it, you’ll enable the GameObject to collide with other GameObjects.
You’ll learn much more about rigidbodies and collisions when you reach the chapter on physics. For now, just take it at face value and move forward.
Adding the Rigidbody Component
In the Hierarchy, select the SpaceMarine GameObject and click the Add Component button in the Inspector.
You’ll see many different categories. When you know which component you need, you can simply search by name. Otherwise, select one of the categories and pick the best option.
Click the Physics category then select Rigidbody.
You’ll see that a Rigidbody component was attached to the GameObject. Congratulations! You’ve added your first component.
Each component has its own set of properties, values and so forth. These properties can be changed in the Inspector or in code. Components also have their own icon to make it easy to determine their type at a glance.
You’ll notice a couple of icons in the right-hand corner of each component, like this:
The first icon is the Reference icon. Click it. It’ll open another window with the documentation page for that component. If you installed the documentation, this page is on your computer, and yes, the search bar works.
You’ll also see a gear icon. Click it and you’ll see the following dialog:
Here are the most important options:
- Reset will reset the component to its default values.
- Move to Front and Move to Back are for adjusting the ordering of sprites in 2D games.
- Remove Component will delete the component from the GameObject — you can undo this action.
- Copy Component allows you to copy a component from one GameObject and paste it onto another.
- Paste Component as New will paste a copied component to a GameObject.
- Paste Component Values allows you to overwrite the values of the current component from a copied component. Specifically, you can copy the values of a component while your game is being played. When you stop the game, you can paste those values onto another component. This is quite useful because sometimes it’s useful to tweak things as you play to see what works in practice.
By adding the Rigidbody component to the space marine, you’ve made it so that he now can respond to collision events and respond to gravity. However, you don’t want him bouncing off enemies or walls. You definitely want to know about those collisions events, but you don’t want the hero to fly out of control just because he bumped into a column.
In the Rigidbody component, check the IsKinematic checkbox. Also, uncheck the Use Gravity option.
The isKinematic
property tells the physics engine that you’re manually controlling the marine, rather than letting the physics engine move the marine for you. But the physics engine is still aware of where the marine is and when it collides with something. This is helpful so that when the marine collides with an alien, the physics engine will notify you so you can make something happen — like the space marine getting chomped!
By unchecking the Use Gravity
option, the space marine won’t be affected by gravity. Again, you don’t need this because you’ll be moving the marine manually and are only using the Rigidbody for collision detection.
Now comes the fun part: it’s time to make that marine dance! Or move. That’s fine too.
Unity provides some built-in components to make movement easy, and you’ll use them in Chapter 4, “Physics”. But for learning purposes, in this tutorial you’ll do everything manually through the power of scripting.
Introducing Scripting
For the non-programmer, at best scripting is a small barrier to entry. At worse, scripting is the devil that never sleeps.
Coming from an arts background, I can say that scripting is not as hard as you might imagine. Like anything, it just requires some time and patience to get.
In this book, you’ll write scripts in C#, which is a popular language developed by Microsoft that works for both mobile and desktop apps. It’s feature-rich and fully versatile. Unfortunately, I can’t teach it all within the covers of this book.
Thankfully, you can learn C# at raywenderlich.com where there’s a free course that teaches the language from the ground up, for complete beginners.
It’s designed for non-programmers and taught within the context of Unity. If you’re a beginner to programming, I’d recommend you have a go at this course before you dive deep into scripting.
If you’re an experienced developer in another language, or a particularly brave beginner, feel free to continue along since everything in this book is presented in easy-to-follow steps. But you may encounter some things that will trip you up without a C# primer.
Believe it or not, Unity supports other programming languages such as JavaScript and Boo. Some people consider JavaScript to be “easy” to learn, so you may wonder why we chose C#.
The truth of the matter is that Unity’s implementation of JavaScript IS NOT JavaScript. It’s actually called UnityScript and considerably different than the JavaScript widely used on the web. While you can certainly be productive with it in Unity, there are no viable use cases for it outside of the engine.
C#, on the other hand, is completely compatible with the outside world. Skills that you learn in Unity can easily be applied outside of game development. For instance, if you find yourself disliking game development (or having a hard time making a living) but enjoying the language, you can transition those skills into a C# development job, creating desktop or mobile apps, or even developing backend server apps.
Finally, most professional Unity developers write in C#, so by taking the time to learn it, you’ll be in a better position to take advantage of game development opportunities as they come up.
The way coding works in Unity is that you create scripts. Scripts are simply another type of component that you attach to GameObjects; ones you get to write the code for.
A script derives from a class called MonoBehavior, and you can override several methods to get notified upon certain events:
-
Update(): This event occurs at every single frame. If your game runs at sixty frames per second,
Update()
will be called sixty times per second. Needless to say, you don’t want to do any heavy processing in this method. - OnEnable(): This is called when a GameObject is enabled, and also when an inactive GameObject suddenly reactivates. Typically, you deactivate GameObjects when you don’t need them for a while but will have a need at a later point in time.
- Start(): This is called once in the script’s lifetime and before Update() is called. It’s a good place to do set up and initialization.
- Destroy(): This is called right before the object goes to the GameObject afterlife. It’s is a good place to do clean up such as shutting down network connections.
There are many other events that you’ll discover throughout this book. To see a complete listing, check out the MonoBehavior
reference on Unity’s site:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.html
Creating Your First Script
It’s showtime!
You have many options for creating a script. You _could_ click the Add Component button and then select New Script.
But I’d like you to try it this way: select the Scripts folder in the Project Browser, and then click the Create button. Select C# Script from the drop-down and name it PlayerController.
You’ll see your new script in the Scripts folder. Drag it from the Scripts folder onto the SpaceMarine GameObject.
You should now see the script listed as one of the components on the Space Marine:
You’ve added your first custom component! Granted, it doesn’t do anything…yet.
You’ll change that in just a moment, but before you do, you need to learn about the Input Manager.
Managing Input
Inputs are the game’s controls, and if you’re developing a game for a desktop computer, your users will expect the ability to rebind keys. Unity’s Input Manager makes this easy, and is the preferred way for your game to deal with user input.
To get access to the Input Manager, click Edit\Project Settings\Input.
The Inspector will look pretty empty. Click the disclosure triangle next to the word Axes.
Once expanded, you’ll see all the pre-configured inputs that are available to you.
The first property is Size, and it’s the number of inputs your game uses. You can decrease the number to decrease the amount and increase it if you want more inputs. The current amount of inputs is more than enough for this game.
Click the disclosure triangle next to Horizontal. Here you can configure the input for the horizontal axis, i.e., left or right.
Here’s a breakdown of the key fields:
- Horizontal is the name Unity gives the input, but you can name it anything you like. This is also the name you reference in code, which you’ll see in a moment.
- Descriptive Name and Negative Name are the names presented to the user in the Unity game launcher if they want to remap the keys. You can disable the Unity game launch and provide your own key mapping interface if you’d like, so these aren’t required properties.
-
Negative and Positive Buttons are the actual keys being used. Unity allows buttons to have negative or opposite keys. For instance, the
right
arrow key is positive while theleft
arrow key is negative. You don’t need to provide a negative for all keys — it wouldn’t make sense to provide a negative key for a use action. -
Alt Negative and Alt Positive Buttons are alternative keys. In this case, instead of left and right arrow keys, you enable the
a
andd
keys.
The other fields mostly relate to the functionality of analog sticks. For simplicity, this game will only use keyboard input. If you wanted to make the game a bona fide twin-stick shooter, these are the options you’d tweak to create a tight control scheme.
Accessing input from code
Now to actually implement the control scheme. In the Project Browser, double-click the PlayerController script to launch the editor.
However, you can use other editors. If you’re running Unity on Windows and want to run with Visual Studio, check out the chapter “Unity and Visual Studio” in the appendix. If you’re on a Mac, or you’re happy using MonoDevelop and would like to learn more about how it works, read through the chapter “Unity and MonoDevelop” also found in the appendix.
When the code editor opens, you’ll see your first script. Every new script contains empty implementations for Start()
and Update()
.
Look for a blank line below the first {
(aka “curly bracket”) — that’s the class definition. Add the following code there:
public float moveSpeed = 50.0f; |
If your script throws an error, carefully review the code to make sure you didn’t miss, forget or mess up any of your code.
moveSpeed
is a variable that determines how fast the hero moves around in the arena. You set it to a default value of 50
that you can change later in Unity’s interface.
Now, to write the actual moving code. In Update()
, add the following:
Vector3 pos = transform.position; |
This bit of code simply gets the current position of the current GameObject — in this case, the space marine, since that is what this script is attached to — and stores it in a variable named pos
. In Unity, a Vector3
encapsulates the x, y and z of a GameObject, i.e., the object’s point in 3D space.
Now comes the tricky part. Add the following after the previous line:
pos.x += moveSpeed * Input.GetAxis("Horizontal") * Time.deltaTime; pos.z += moveSpeed * Input.GetAxis("Vertical") * Time.deltaTime; |
When you move the object, it’ll only be on z- and x-axes because y represents up and down. Because there are two different input sources (Horizontal for left and right, and Vertical for up and down), you need to calculate values for each axis separately.
Input.GetAxis("Horizontal")
retrieves a value from the Horizontal component of the Input Manager. The value returned is either 1
or -1
, with 1
indicating that a positive button in the Input Manager is being pressed.
According to the settings you saw defined earlier, this is either the right
arrow or d
keys. Similarly, a value of -1
indicates that a negative button is being pressed, meaning it was either the left
arrow or a
key.
Whatever the returned value may be, it’s then multiplied by the moveSpeed
and added to the current x
position of the GameObject, effectively moving it in the desired direction.
The same thing happens with Input.GetAxis("Vertical")
, except it retrieves a value from the vertical component of the Input Manager (indicating the s
, down
, w
or up
keys), multiplies this (1
or -1
) value by the moveSpeed
and adds it to the z
position of the GameObject.
So what’s with Time.deltaTime
? That value indicates how much time has passed since the last Update()
. Remember, Update()
is called with every frame, so that time difference must be taken into account or the space marine would move too fast to be seen.
TL;DR: Time.deltaTime
ensures movement is in sync with the frame rate.
By default, Unity considers 1 point to be equal to 1 meter, but you don’t have to follow this logic. For instance, you may be making a game about planets, and that scale would be way too small. For the purposes of simplicity in this book, we have sized our models to follow Unity’s default of one point per meter.
Now that you’ve altered the location, you have to apply it to the space marine. Add the following after the previous line:
transform.position = pos; |
This updates the space marine’s position with the new position.
Save the script and switch back to Unity. You may be tempted to run your game, but there’s a slight problem. The camera is not positioned correctly.
In the Hierarchy, select the Main Camera, and in the Inspector, set Position to (X:-9.7, Y:53.6, Z:-56.1)
and Rotation to (X:30, Y:0, Z:0)
. I figure out these values by manually moving the camera around and looking at the Camera preview in the lower right until I was happy with the result.
In the Camera component, set Field of View to 31. This effectively “zooms in” the view a bit.
Now it’s time to give your game a test run. Look for the play controls at the center-top of the editor. Click the play button.
Now, look at the Game window and move your character by pressing the arrow keys or WASD keys. Behold…life!
The Game window is where you actually play the game. There are two life-and-death details to keep in mind as you play.
First, when you start playing, the interface becomes darker to give a visual queue that you’re in play mode.
Second, when you play your game you can change anything about it (including changing values on components in the inspector), but when you stop playing the game, all your changes will be lost. Let me repeat that — all your changes will be lost. This is both a blessing and a curse. The blessing is that you have the ability to tweak the game without consequence. The curse is that sometimes you forget you’re in play mode, continue working on your game, then for some reason the game stops. Poof! Buh-bye changes!
Thankfully, you can (and should) make play mode really obvious. Select Edit\Preferences on PC or Unity\Preferences on Mac to bring up a list of options.
Select the Colors section. Here you can change the colors used throughout the editor. Look for Playmode tint. Click the color box next to it, and then give it an unmistakable color — I prefer red. Now play your game to see if it’s conspicuous enough.
Camera movement
There’s only one problem with the space marine’s movement: he will slip off the screen. You want the camera to follow the hero around the arena, so he doesn’t get away from you.
With a little scripting, you can keep the marine in focus.
In the Hierarchy, click the Create button and select Create Empty. Name it CameraMount.
The basic idea is you want CameraMount to represent the position the camera should focus on, and have the camera be relative to this position.
Initially you want the camera to focus where the space marine is, so let’s configure the CameraMount to be at the exact same position as the space marine.
To do this, select the space marine, click on the gear button to the upper right of the Transform component, and select Copy Component:
Then select the CameraMount, click on the gear button to the upper right of the Transform component, and select Paste Component Values:
Next, drag the Main Camera GameObject into the CameraMount GameObject.
Great! Now as you move the player around, you can move the CameraMount to move with the player, and the camera will track the player. You just need to write a script to do this.
With the CameraMount selected, click the Add Component button in the Inspector and select New Script. Call it CameraMovement and set the language to C Sharp.
Drag your new file from the top level of the assets folder into the Scripts folder.
Double-click the CameraMovement script to open it in your code editor. Underneath the class definition, add the following variables:
public GameObject followTarget; public float moveSpeed; |
followTarget
is what you want the camera to follow and moveSpeed
is the speed at which it should move. By creating these as public variables, Unity will allow you to set these within the Unity editor itself, so you can set the followTarget
to the space marine and fiddle with the moveSpeed
to your heart’s content, as you’ll see shortly.
Now add the following to Update()
:
if (followTarget != null) { transform.position = Vector3.Lerp(transform.position, followTarget.transform.position, Time.deltaTime * moveSpeed); } |
This code checks to see if there is a target available. If not, the camera doesn’t follow.
Next, Vector3.Lerp()
is called to calculate the required position of the CameraMount.
Lerp()
takes three parameters: a start position in 3D space, an end position in 3D space, and a value between 0 and 1 that represents a point between the starting and ending positions. Lerp()
returns a point in 3D space between the start and end positions that’s determined by the last value.
For example, if the last value is set to 0
then Lerp()
will return the start position. If the last value is 1
, it returns the end position. If the last value is 0.5
, then it returns a point half-way between the start and end positions.
In this case, you will supply the camera mount position as the start and the player position as the end. Finally, you multiply the time since the last frame rate by a speed multiplier to get a suitable value for the last parameter. Effectively, this makes the camera mount position smoothly move to where the player is over time.
Save your code and return to Unity. If you look in the Inspector now, you’ll see two new fields named Follow Target and Move Speed. As mentioned earlier, these were automatically derived by Unity from the public
variables you just added to the script. These variables need some values.
With the CameraMount still selected in the Hierarchy, drag SpaceMarine to the Follow Target field and set the Move Speed to 20.
Play your game to see what’s changed.
The marine is a real superstar now, complete with a personal camera crew. Granted, he can’t turn, and he walks right through objects just like Kitty Pryde, but these are easily solvable issues that you’ll tackle in Chapter 4.
Adding Gunplay
Unfortunately, the finer parts of diplomacy are lost on the flesh-eating antagonists of this game. It’s best you give the hero some firepower so he can protect himself on his terribly relaxing (terrible?) vacation.
First, you need to create a bullet. In the Hierarchy, click the Create button. From the drop-down, select 3D Object\Sphere to create a sphere in the Scene view.
Give it the name Projectile. With it still selected, check out the Inspector. You’ll notice a bunch of new components.
The three new components are:
- The Mesh Filter is a component that contains data about your model’s mesh and passes it to a renderer.
- The Mesh Renderer displays the mesh. It contains a lot of information about lighting, such as casting and receiving shadows.
- Finally, you’ll notice the sphere contains a Sphere Collider. This component serves as the GameObject’s boundaries. You’ll learn cover colliders in Chapter 4.
Since you want the bullet to participate in Unity’s physics, it needs a rigidbody.
Luckily, you’ve done this before. Click the Add Component button, and select Rigidbody from the Physics category. Make sure to uncheck Use Gravity.
Since the marine will burn through lots of projectiles, drag it from the Hierarchy to the Prefabs folder in the Project Browser. Delete the projectile from the Hierarchy because you don’t need it now that it’s gone on to be a prefab.
At this point, you need to create a script to launch the projectile. In the Project Browser, select the Scripts folder then click the Create button. Choose C# Script and name it Gun. Double-click the file to launch the code editor.
This file needs a few properties underneath the class definition. Add the following:
public GameObject bulletPrefab; public Transform launchPosition; |
Again when you create a public variable on a script, Unity exposes these variables in the editor. You will set the bulletPrefab
to the bullet prefab you just created, and you will set the launchPosition
to the position of the barrel of the Space Marine’s gun.
Next, add the following method:
void fireBullet() { // 1 GameObject bullet = Instantiate(bulletPrefab) as GameObject; // 2 bullet.transform.position = launchPosition.position; // 3 bullet.GetComponent<Rigidbody>().velocity = transform.parent.forward * 100; } |
Let’s review this section by section:
-
Instantiate()
is a built-in method that creates a GameObject instance for a particular prefab. In this case, this will create a bullet based on the bullet prefab. SinceInstantiate()
returns a type ofObject
, the result must be cast into aGameObject
. - The bullet’s position is set to the launcher’s position — you’ll set the launcher as the barrel of the gun in just a moment.
- Since the bullet has a rigidbody attached to it, you can specify its velocity to make the bullet move at a constant rate. Direction is determined by the transform of the object to which this script is attached — you’ll soon attach it to the body of the space marine, thus ensuring the bullet travels in same the direction as the marine is facing.
Save and switch back to Unity.
In the Hierarchy, expand the SpaceMarine GameObject and select the BobbleMarine-Body GameObject. In the Inspector, click the Add Component button and near the bottom of the list of components, select Scripts. From the list of scripts, choose Gun.
You’ll see that your Gun script component has been added to the body of the marine. You’ll also notice there are two new fields: Bullet Prefab and Launch Position. Do those sound familiar?
Click the circle next to Bullet Prefab. Select Projectile from the resulting asset list. Now you have loaded the bullet and just need to set the launch position.
In the Hierarchy, hold the Alt key on PC or Option on Mac and click the disclosure triangle next to the BobbleMarine-Body. You’ll see a large list of child GameObjects. Look for Gun.
Select that GameObject and click the Create button. Choose Create Empty Child and rename it to Launcher. This new GameObject lives in the center of the gun’s barrel and represents where bullets will spawn from – feel free to move it around in the scene editor if you’d like to tweak the spawn position.
Keep all the GameObjects expanded and select BobbleMarine-Body so that the Inspector shows all the components. Drag the new Launcher GameObject into the Gun
component’s Launch Position field.
Notice that when you add the GameObject to a transform field, Unity finds and references the attached transform.
It’s official! The marine’s gun is locked and loaded. All that’s left is the firing code. Thankfully, it’s pretty easy.
Switch back to your code editor and open Gun.cs.
The gun should fire when the user presses the mouse button and stop when the user releases it.
You could simply check to see if the button is pressed in Update()
and call fireBullet()
if so, but since Update()
is called every frame, that would mean your space marine would shoot up to 60 times per second! Our space marine can shoot fast, but not that fast.
What you need is a slight delay between when you shoot bullets. To do this, add the following to Update()
:
if (Input.GetMouseButtonDown(0)) { if (!IsInvoking("fireBullet")) { InvokeRepeating("fireBullet", 0f, 0.1f); } } |
First, you check with the Input Manager to see if the left mouse button is held down.
1
, and for the middle mouse button, you’d pass in 2
.
If the mouse is being held down, you check if fireBullet()
is being invoked. If not, you call InvokeRepeating()
, which repeatedly calls a method until you call CancelInvoke()
.
InvokeRepeating()
needs a method name, a time to start and the repeat rate. InvokeRepeating()
is a method of MonoBehaviour
.
After that bit of code, add the following:
if (Input.GetMouseButtonUp(0)) { CancelInvoke("fireBullet"); } |
This code makes it so the gun stops firing once the user releases the mouse button. Save your work and return to Unity, then play the game.
Hold down the mouse button. You have bullets for days!
Where to Go From Here?
You can download the completed project from this chapter here.
At this point, you should be feeling more comfortable with Unity. You have a walking space marine with a functioning weapon.
As you made these two things happen, you learned about:
- Components and how they give your GameObjects behavior.
- Scripting and how to use scripts to create custom behavior.
- The Input Manager and how to access it from code.
- The Game window and how to test your games.
This was a thick, heavy tutorial, but you made it to the end. Congratulations! You’ve come a long way.
There’s still a lot more to do. Your poor marine is a sitting duck because he can’t turn around to see what’s sneaking up behind him. At the same time, he has nothing to worry about because there are no aliens hordes attacking him.
If you’ve enjoyed this tutorial series and want to learn how to finish off your game (and build more amazing games in Unity), check out Unity Games by Tutorials.
The book teaches you everything you need to know about building games in Unity, whether you’re a beginner or a more experienced game developer. In the book, you’ll build four great games:
- A 3D twin-stick shooter
- A classic 2D platformer
- A 3D tower-defense game (with virtual reality mode!)
- A first-person shooter
The book is still in development, but here’s a preview of what’s inside:
If you have questions or comments on this tutorial, please leave them in the discussion below!
The post Unity Tutorial Part 3: Components appeared first on Ray Wenderlich.