Lab 1: Intro to Unity
The goal of this lab is to get you started with Unity and familiarizing yourself with the editor and the game engine. We will be completing the first part of the Roll-a-Ball tutorial on Unity Learn.
You can follow along with the instructor, or the steps below. If you need to reference them later, the Unity Learn page has full videos walking through the entire project.
Create a new project
Open Unity Hub and create a new project. You can reference the steps from HW 1 if you need a refresher. Remember to set the project type to 3D Core.
Name this project "Roll-a-ball
" and put it in a safe location (you'll need it again for HW2!).
Orienting around the editor
You'll see four main areas in the default layout for the editor. If yours looks different, you can reset it in the menu by going to Window → Layouts → Default. You should see views marked Scene, Hierarchy, Inspector, and Project. Let's take a look at what each of these does.
Scene
This shows you a view of your project's current "scene". You can think of scenes like individual levels or stages in a video game. Each scene contains a number of GameObjects that represent the world.
You can select objects in the Scene view, or move around the view to get a better look at objects in the world:
- To select objects, use the Left Button on your mouse.
- To pan the view around, click and drag the Middle Button on your mouse (or use Win: Ctrl+Alt+Left Button | Mac: Option+Cmd+Left Button).
- To rotate the view, hold the Right Button on your mouse and drag to look around.
- To fly around, hold Right Button and press the Up Left Down Right keys (or the W A S D keys).
Hierarchy
A list of all the GameObjects in the scene is shown here in the Hierarchy. Just like the name suggests, GameObjects can have a hierarchy, where objects can have parents and children. A child object (shown as nested in the Hierarchy) will move, rotate, and scale with its parent.
More about GameObjects
From the Unity Documentation:
Every object in your game is a GameObject, from characters and collectible items to lights, cameras and special effects. However, a GameObject can’t do anything on its own; you need to give it properties before it can become a character, an environment, or a special effect.
Inspector
When you select an object in the Scene view or the Hierarchy, the Inspector will update to show you the attributes of that object. These include the GameObject's Transform (aka its position, rotation, and scale) and any Components that are attached to the object.
Project / Assets
The Project view will show you the different scenes, scripts, textures, models, sounds, etc. that you have imported into your Unity project. Think of it like a palette—you can add items from the Project view into your scene.
Create the floor
We will start by creating a floor for our play area. Unity comes with a number of primitives, which are simple shapes that you can use for simple prototyping. Right-click on an empty space in the Hierarchy and go to 3D Object
→ Plane
. You can also use the GameObject menu at the top of the editor.
In the Hierarchy, rename your new GameObject from Plane
to Ground
. Select your plane in the Hierarchy or the Scene view by clicking on it. You should see the Inspector update to show the attributes of that plane.
The position of the plane is all weird! Reset the Transform by clicking on the three vertical dots on the upper-right of the Transform, then click Reset
. This will set the position back to the origin of the world, at X: 0, Y: 0, Z: 0
.
Now, scale the plane to be twice as big. You can select the Scale Tool in the upper left corner of the Scene view, or by pressing the R key.
You can drag each of the handles to scale a GameObject in that respective axis, or drag the gray handle in the center to scale it uniformly across all axes. You can also directly type values into the Scale fields in the Inspector. Make the scale X: 2, Y: 2, Z: 2
aka (2, 2, 2)
.
Notation
I will use (X, Y, Z)
notation from now on to specify the X, Y, and Z components of a 3-dimensional vector. This applies to position, rotation, and scale. For instance, a position of (1, 0, 2.5)
refers to the components X: 1, Y: 0, Z: 2.5
.
Create the player
Let's add the player ball into the scene. In the Hierarchy, right-click in the empty space and then select 3D Object
→ Sphere
. Rename this new GameObject to "Player
". Reset the Transform of Player
just like you did with the plane.
Right now, the sphere is buried inside the floor. We need to raise it up. Select the Player
object either in the Hierarchy or in the Scene view. You can use the Move Tool and drag the sphere just like using the Scale Tool, but this time, let's use the Inspector.
Set the Y-component of the position to 0.5
so that the position is (0, 0.5, 0)
.
Info
By default, Unity represents all its units in meters. So a position of (0, 0.5, 0)
means that the center of the sphere is half a meter above the ground.
Create the walls
Now, let's add four walls around the ground.
In the Hierarchy, create an empty GameObject by right-clicking on empty space and then clicking "Empty" in the menu that pops up (or use the GameObject menu at the top of the editor and click "Create Empty"). Now you have an empty GameObject. Rename this GameObject to "Walls
". Reset the Transform of Walls
back to position (0, 0, 0)
.
Why do this? Well, empty GameObjects are often used for grouping objects, or running scripts that aren't attached to a visible object in the scene. In our case, we will use it to group the four walls of our play area.
Let's create a wall. We want to make it a child of the Walls
GameObject, so right-click Walls
in the Hierarchy and click 3D Object
→ Cube
. Rename this cube to West Wall
. You should see it "nested" underneath the Walls
object, like below. If not, click and drag West Wall
and then drop it on top of Walls
to make it a child.
Now, let's resize and move West Wall
to fit one side of the play area. Set the scale to (0.5, 2, 20.5)
and the position to (-10, 0, 0)
.
Great! Let's add the other three walls. Instead of creating new cubes, let's just duplicate the existing wall. Right-click West Wall
in the Hierarchy, then click Duplicate
. Rename this new wall to East Wall
and set its position to (10, 0, 0)
.
Tip
You can also select any GameObject and then press Ctrl+D (or Cmd+D on Mac) to duplicate it.
Duplicate East Wall
and rename the new object to North Wall
. Set its position to (0, 0, 10)
. Now we just need to rotate it! In the editor, Unity represents rotations as degrees rotated clockwise along each axis. Rotate the wall 90 degrees against the Y-axis so that its rotation is (0, 90, 0)
.
Duplicate North Wall
and rename the new object to South Wall
. Position this wall opposite the North wall so that your play area is completely enclosed.
Your scene should look like the image above. Press Ctrl+S (or Cmd+S) on your keyboard to save your changes to the scene. Save often!
Adding materials
Let's add some color to your GameObjects to distinguish them from one another. We will create some colored materials, which represent, well, the material that makes up each of our objects. Typically in video games, materials are made with complex textures, but we'll just use simple colors.
In the Project view, make sure you have the Assets
folder open. You should see a single Scenes
folder. Right-click anywhere inside the empty space in the folder, then go up to Create
→ Folder
. Rename this new folder to "Materials
".
Double-click the folder to open it. Right-click anywhere inside the folder then go to Create
→ Material
. Rename this new material to "Background
".
Select the Background
material and then go to the Inspector. You should see Albedo
and then a white bar to the right of it. Click on that white bar to open the color picker.
Note
This part is slightly different from the Unity Learn tutorial, since we are using a 3D core project with the standard built-in renderer instead of the URP renderer, which is what the tutorial uses.
Here, we change the Albedo
color instead of the Base Map
color due to the different shader used.
Drag the sliders and change the color to whatever you'd like the floor to be. I'll use a pale gray here to match the Unity Learn tutorial. You can also adjust the Metallic
and Smoothness
values to change the shininess of the material.
Once you are happy with the color, drag the material from the Project view to the Ground
object in the Scene and drop it there. This will "paint" your object with that material.
Create two more materials, called "Player
" and "Walls
". Adjust these to the colors of your liking, then apply the Player
material to the Player
GameObject and the Walls
material to each of your four walls.
At this point, you should have something like the above image!
Adding components
Now, let's add physics to the ball so that we can make it roll around. Select the Player
GameObject. In the Inspector, go to the very very very bottom and click on Add Component
. In the window that pops up, search for "rigidbody
" and click on the Rigidbody
component.
More about Components
A component is a reusable property or behavior that can be added to GameObjects. The Rigidbody
component makes a static GameObject into a dynamic object that responds to physics and collisions. The big idea here is that we can write our own components that are reusable.
You don't need to write code to implement physics for every single object; instead, you just add the Rigidbody
component to a GameObject and *poof* that object now has physics!
From the Unity Documentation:
GameObjects are the fundamental objects in Unity that represent characters, props and scenery. They do not accomplish much in themselves but they act as containers for Components, which implement the functionality.
To give a GameObject the properties it needs to become a light, or a tree, or a camera, you need to add components to it. Depending on what kind of object you want to create, you add different combinations of components to a GameObject.
Unity has lots of different built-in component types, and you can also make your own components using the Unity Scripting API.
Now, we need to install the Unity Input Manager. At the top of the editor, go to the Window
menu, then select Package Manager
. In this dialog window, click on the Packages: In Project
dropdown menu in the upper-left. Select Unity Registry
.
Using the dialog, search for a package called "Input System
" and install it. If you are prompted to enable the native platform backends, click Yes
. Make sure to save the scene if it prompts you to do so. The editor should restart.
Now, select your Player
GameObject. In the Inspector, select Add Component
, then search for and select the component named Player Input
. Inside the Player Input
component on your Player
, click the Create Actions...
button. Save the file with the default name and location when it asks you to.
Moving the player
Select Add Component
again on your Player
GameObject. This time, click New script
, then name the script PlayerController
and click Create and Add
. In the Project view, if you navigate back to the Assets
folder, you should see a new PlayerController.cs
file. Go ahead and create a new folder called "Scripts
" and put this new script inside it. Open the Scripts
folder and double-click on the PlayerController.cs
file. This will open it in Visual Studio.
You should see some pre-generated code that looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
This is a C# file. The syntax is very close to Java, so it should feel familiar to you already! You can see some small differences, such as the using
keyword instead of import
and the colon (:
) to denote inheritance instead of extends
. We will modify this script to control the ball when the user presses certain keys on the keyboard.
MonoBehaviour
Almost all of your scripts will extend the MonoBehaviour
base class. It is technically a special sub-class of Component
that gives you inherited methods and variables to help you write behaviors for GameObjects
. You can read more in the Unity Documentation or this blog article.
For this script, we need to model the behavior of the player movement. Let's get the input from the player first. Add a fourth using
statement with using UnityEngine.InputSystem;
as shown below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
We need to add two instance variables to store the X and Y movement from the user. Inside the class (just like Java), create two instance variables of type float
, called movementX
and movementY
.
public class PlayerController : MonoBehaviour
{
private float movementX;
private float movementY;
// Start is called before the first frame update
void Start()
Now, add a new method at the bottom of the class, called OnMove
:
public class PlayerController : MonoBehaviour
{
...
private void OnMove(InputValue movementValue)
{
}
}
This method will be automatically called whenever the user tries to move the ball by pressing the WASD or arrow keys on the keyboard. The movementValue
parameter holds the user's directional input. Lets get those values and then store them in our instance variables:
private void OnMove(InputValue movementValue)
{
Vector2 movementVector = movementValue.Get<Vector2>();
movementX = movementVector.x;
movementY = movementVector.y;
}
In order to move the ball with realistic physics, we need to access that Rigidbody
component we added earlier. First, let's add a few instance variables to our class:
public class PlayerController : MonoBehaviour
{
public float speed = 0;
private Rigidbody rb;
private float movementX;
private float movementY;
Inside the Start()
method, let's get that Rigidbody
component and store it. We do this once in Start()
so we don't have to re-get the component each single frame. Getting a component actually takes some time, so storing it this way is more performant. Add the following line inside the Start()
method:
rb = GetComponent<Rigidbody>();
Every single frame (by default, Unity runs at 60 frames per second), we need to move the player in the direction of the user's input. You typically would do this in the Update()
method, which Unity will call once per frame. However, for code pertaining to physics, Unity recommends we put code in a FixedUpdate()
method. Let's add that at the bottom of our class:
...
private void FixedUpdate()
{
Vector3 movement = new Vector3(movementX, 0.0f, movementY);
rb.AddForce(movement * speed);
}
}
So here, we are taking the user's input, converting it into a direction in 3D space (aka a Vector3
), and applying that as a force to the Rigidbody
, multiplied by some speed. It's like we're pushing it little by little in a direction! You may notice that we set the speed to 0. Let's take a look at why.
But first, your PlayerController.cs
script should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Let's start a good convention. At the top of your file, add a simple header:
// Name: <YOUR NAME>
// Version: <DATE>
// This work complies with the JMU Honor Code.
//
// Description:
// This script moves the object based on user input.
Save your file and go back to the Unity editor.
Testing the movement
Select your Player
GameObject and scroll down to the "Player Controller" component in the Inspector. You should see a new field for Speed
. Any public instance variables will show up as properties in the Inspector. These are great, because they let us easily change their values without needing to dig into the code!
Set the Speed
to 1
and save your scene. Now click the Play button above the Scene view.
This will switch Unity to the Game view, where your game is up and running! Try pressing the arrow keys or the WASD keys on your keyboard to move the ball. If it's moving too slowly, press the Play button again to stop the game, then go back and change the speed to something higher.
Submission
Submit your PlayerController.cs
file to Gradescope for credit.