Introduction
Hi everyone, I'm Josh, an aspiring game developer hobbyist. I was inspired by the many developer blogs here and decided to post my own personal journey as a new VR Developer!
After having a great time playing with the many different VR devices, I decided that I have to get involved in making apps.
I believe VR is going to be the big next thing, but for that to happen, it'll need a lot of content (apps). With that, I decided to pick up Unity and learn how to make VR applications.
I currently have no experience with Unity, however I work as a Software Developer during the day so I am very familiar with programming so I'm confident in my abilities.
However, Instead of just jumping in and learn how to use Unity, I realized that I might be in the perfect position to help others follow in my foot steps and develop VR applications.
I'm familiar enough with programming that I'm confident I can figure things out, but I'm also new enough that I don't really know what I'm doing so I'll run into the many common problems other people might miss.
With that being said, I decided to document my journey from Zero to a VR developer in what I want to call my 100 Days of VR. My two goals are to:
Motivate myself to really learn how to use Unity and make VR applications
Create a series of posts that hopefully someday help someone, literally anyone get started in developing in Unity and/or VR applications.
With that being said, here's my progress for the day.
Day 1
The first step to learning VR, is learning how to use one of the game engines that supports them. In the current market, we have 2 options: Unity and Unreal Engine.
I was told that Unity was more beginners friendly so I decided to pick that up. I installed the latest version of Unity along with Visual Studio 2017 Community Edition that came bundled along with Unity.
Great! Now that we have our toolkit installed, what’s next?
The first thing I did was that I started to go through the Unity’s Roll-a-ball tutorial.a
Here’s a summary of what I learned in the tutorial:
Setting up the Game
Scene
The scene tab gives you a 3D view of the world that you can move around in. In this tab, you can directly drag and drop the positioning of the objects that you inserted into Unity
Hierarchy
The hierarchy is used to display the Unity objects that you create and added into your scene.
Positioning
Since we’re working in a 3D environment, Unity has a 3D coordinate system: (x,y,z), if we were to select the sphere that was created in the tutorial, if you look at the the inspector on the right, you can see that we can change some of the transform properties such as position, rotation, and scale.
It appears that if we imagine something lying flat on a surface:
X = Horizontal movement
Y = Height movement
Z = Vertical movement
Material
If you want to change colors of your object, we have to create a material for our Mesh Renderer component that you can see from the picture above.
If you were to select the sphere, in the inspector under the Mesh Renderer component, you can select a material to apply on our object.
In the tutorial we created a new material in the project pane and made it's color red. Then we applied it to our sphere to get the red sphere that you see above.
Roll a Ball
After the first video showed us how to setup the environment and use some of the tools available for the roll a ball tutorial, the next thing we learned is how to actually move the ball.
Rigid Body
The first thing we need to do is to add a RigidBody component to our ball object. What this does is that it makes the ball take part in Unity’s physics engine so that it’ll be affected by things such as gravity and when it collides with other properties
Looking at the code for this part of the video, we can learn a lot of information:
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {
public float speed;
private Rigidbody rb;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
}
The way scripts in Unity works is that they are attached to unity game objects that are in and we can grab any component information that’s attached to the game.
A great example is given in the example code you see above when we’re using the rigid component:
rb = GetComponent<Rigidbody>();
for when we want to access information from our RigidBody component.
Public variables
Before looking at the rest of the function, I want to point out that if you were to make a variable public in Unity script, that means you can set their value outside of the code under that script’s component in the Unity Editor.
Using the component system we can easily change the text and settings on the fly when you’re play testing your game!
Learning about Start and Update
So we have 2 functions that are being used in the code Start() and FixedUpdate(). Both of these are functions we’re inheriting from the MonoBehaviour object that controls how the game works.
Here are the more common methods I found
Start() – this is run only once when your GameObject gets created in Unity. It’s used for initializing your variables and creating the state of your GameObject when it is first created
The next parts are the updates method. Depending on what you might have worked on, the update function might take some time to wrap your mind around.
An update method is called once every time Unity renders a frame. You might have heard the term, frames per second? If we have 60 frames per second, which means our update function gets called 60 times every second.
So what’s a frame? If you have some knowledge of animation, you’ll know that an images is made of multiple images that are being replaced one after another. An image to illustrate my point is this gif:
This gif is actually made up of multiple images from a sprite map that is being looped through per scene.
From my basic understanding, this is extremely important for VR, if we want to avoid causing motion sickness, we have to make a game that achieves 90 fps
But anyways that’s a problem for the future, I don’t even know how to work with Unity! Going back to the update methods, we have:
Update() – this methods Is called every frame that the game runs in. I did my own investigation by inserting the code snippet Debug.Log("update: " + Time.deltaTime); to print out how much time has passed since the last update call and found that the time per frame isn’t consistent.
FixedUpdate() – Similar to update, but this code runs at fixed times, which is good for physics calculations which we see in the code above. Printing the deltaTime, it appears that the FixedUpdate method is called every 0.02 seconds. Forcing 50 fps
Inputs and Vectors
Finally the last part of the code is the movement code. Unity comes with a handy set of api’s that make it easy to detect when the user is hitting on the keyboard.
We used Input.GetAxis, to get the movement when we hit the arrow keys to get the direction that is being hit and store those values in a vector.
If you remember a bit of physics from High school, you might remember that a vector is just a direction. So in our code, when we say we create a vector (x,y, and z location) it means that we’re creating a force that’s going in that x,y, and z direction that we specified…
…which is exactly what you see here:
rb.AddForce (movement * speed);
Moving the Camera
So that was a lot to learn about Unity already and we’re only in 3rd video of the series! So continuing on, after learning about moving the ball around, we now see that the game tab that we run doesn’t really move or follow the ball when we roll it around.
This was resolved by using a camera object, the view that you’re seeing in the game tab is from the camera.
So a nifty way to follow the ball is to make the ball a child of our ball, by dragging our Main Camera object on the hierarchy into the Sphere we made.
By doing this, we made our camera relative to our ball’s position. Unfortunately, when we move the ball around the camera follows.
To fix this we added the provided CameraController script to our camera:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour {
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}
What was done was that we created the distance from the camera to the player in the Start() function and update our camera so that it is always that distance away in LateUpdate()
LateUpdate() acts the same way as the other update() however the difference is that it is the method that’s called when rendering a frame.
Setting up the Play Area
There wasn’t too much in this section, just learning how to setup our environment by moving around objects
Creating Collectable Objects
There also wasn’t too much here, we created collectible items that the player can roll the ball over, we created a script to make the ball rotate which we do by grabbing our GameObject’s transform component and modifying the rotation.
transform.Rotate (new Vector3 (15, 30, 45) * Time.deltaTime);
Note: Time.deltaTime is the time that elapsed since the last time we called Update()
Prefabs
However one interesting thing to note is that after we make the object we want, we can drag it from the hierarchy into the project pane on the bottom to create a prefab.
A prefab is a template or a clone of the object that you made. With this, we can create multiple instance of that same object.
The benefits of using prefab is that if you ever decide to change the components of the GameObject, instead of changing them one by one, just by changing the prefab, you can change all instance in one go.
Collecting the Pick-Up Objects
Now things are finally getting more interesting. In this section, we learned a variety of subjects involving colliders and how objects in the game interact with other objects.
From the previous video, we created these cube objects (which has their own rigid body) that we can collect, however if we were to roll our spheres into the cube, we would bounce back.
This problem will be addressed in this video.
Collider Intro
Whenever a GameObject that has a Collider component touches another GameObject with a Collider component, we call that a collision.
Unity provides many collider components that you can attach to your GameObject. These colliders all come in difference shapes and sizes. The goal is to pick a collider that matches the shape of your GameObject.
When we were to use a different collider, let’s say a square for example, the collision won’t actually occur at when something else touches the material (the red sphere), instead the collision will start when they touch the edge of the square
From my understanding, we can use a mesh collider to try and hug our object as close as possible, however the more fine grain control we need on our GameObject for collision, the more calculations will need to be done, resulting in worse performance.
The TLDR of this: only use complex colliders if you absolutely have to, otherwise we should try and use more basic shape colliders.
Using Colliders
Now back to what was taught, how do we use them?
In our PlayerController.cs we just inherit the OnTriggerEnter() function!
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
}
}
This method gets called every time our sphere bumps into another collider, we get passed a Collider object that has access to the GameObject that we collided against.
Notice how we have something called Tag? That’s how we can identify what we hit in Unity. In each GameObject in the hierarchy, you can create and attach a Tag to them. As you can tell from the code above, we can use Tags to help identify which GameObject we collided against.
After we found the object with the tag we want, we can do whatever we want with it!
Performance Optimizations
While probably not important to know this early on, something that was briefly mentioned is that there are two types of colliders, static and dynamic colliders.
Static colliders, as you expect, are objects that don’t move and dynamic are objects that do move. The important thing to remember here is that static colliders are cached by Unity so that we can get performance benefits, however if you plan to change and move a static game object, this will cause Unity to constantly cache the object, which now becomes a performance problem!
To make a GameObject be a dynamic collider is to make it impacted by Unity’s physics engine, ie adding a RigidBody component to it.
Dynamic Collider = RigidBody Component + Collider Component
Static Collider = Collider Component
Displaying the Score and Text
The game is “technically” done, but the user will never know it. In the last video of the series, we learn a bit about using Unity’s UI system.
UI
You can create a UI element like text the same way you create a GameObject in Unity by right clicking in the hierarchy pane, however one big difference is that all UI elements are made children of a Canvas GameObject.
And another thing is that the Canvas is actually directly on the screen when you’re in the Game tab and is not part of the Scene Tab… well actually it is, but it’s in a completely different scale!
The canvas covers the whole Game tab screen and for our UI GameObject, instead of Transform, we have something called Rect Transform.
In a way it’s very similar to a normal GameObject where you can still drag the object around, however a nifty trick that help position the text is to click on the square button on the top left corner of our Rect Transform component and you'll get this:
If you hold alt and click one of the square, your text will be automatically moved into one of the 9 spaces! Nifty!
How to use our UI components
Looking at the code that was created in the video:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class PlayerController : MonoBehaviour {
public float speed;
public Text countText;
public Text winText;
private Rigidbody rb;
private int count;
void Start ()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText ();
winText.text = "";
}
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ( "Pick Up"))
{
other.gameObject.SetActive (false);
count = count + 1;
SetCountText ();
}
}
void SetCountText ()
{
countText.text = "Count: " + count.ToString ();
if (count >= 12)
{
winText.text = "You Win!";
}
}
}
We created a public variable of type Text, you can assign the value by dragging and dropping the Text object in our hierarchy into the variable slot in the script’s component.
One very important thing to remember when you’re using UI gameobjects is to include:
using UnityEngine.UI;
Otherwise Unity won’t know any of the UI objects that you’re trying to reference.
The only new important part is the function SetCountText() which is where we see how we interact with a UI object:
void SetCountText ()
{
countText.text = "Count: " + count.ToString ();
if (count >= 12)
{
winText.text = "You Win!";
}
}
It looks pretty straightforward right? You get the UI object, and you set it’s text to be whatever you want it to be. Easy!
Conclusion
Phew, doing this write up summary might actually be harder than the actual learning of Unity… and it’s only day 1!
But that’s okay. We’re just starting to learn about Unity, I’m sure as we progress along we’ll start seeing things like colliders, rigid bodies, and UI again and I don’t have to do THIS again. I really hope so. I really do…
Anyways, that’s the end of day 1! I hope you learned something valuable from this!
Read from the original Day 1
Go to the 100 Days of Unity VR Development Main Page
↧