Building Your First Vr Game
May, 2021
Hello!!! đ After developing 2D games for 2 years, I finally decided to add a 3rd dimension. And instead of making a simple 3D game, I decided I should make a VR Game! This was a great ideaâŠ
Nonetheless, here's how I made my first VR Game using the Unity Game Engine! In tutorial form, so you can follow along! đ
PS: (This article assumes you have basic Unity 3D knowledge)
PPS: (Here is the finished game we are building)
By @nampoh on Unsplash.com
đ Project Setup đ
After creating a new 3D Unity project, your gonna want to head over to the Unity Asset Store and find the Oculus Integration package. Click the blue âAdd to My Assetsâ button on the right, and head back over to your unity project.
Back in Unity, open the package manager window and select: âMy Assetsâ in the drop-down menu.
The Oculus Integration package should now be visible.
If you navigate over to the Oculus Integration in the top left of the Package Manager and select it. You can import it into your project by pressing the âImportâ button in the bottom right corner of the window.
Once it is imported, search in the project tab for âOVRCameraRigâ and drag it into the hierarchy and reset its position to (0, 0, 0). The Oculus Integration automatically handles all the position and rotation calculations between the real headset and the virtual camera rig. Your project is now set up and we are ready to go!
đź Game Scripting đź
Adding Swords đȘ
first step is finding sword models to add to your game! I found these weapon models itch.io for free, but you can find yours anywhere, as long as the models are in OBJ format.
Import your sword models into Unity, and add each sword under their corresponding hand anchors under the OVRCameraRig game object.
Give both of these swords a Mesh Collider and check off Convex and Is Trigger as options. This will allow collision detection further on!
Create a new tag for your swords called âSwordâ and add it to each one.
The final step is to add a new script named: Sword to both your swords. The Sword script will handle playing a sound whenever we slice a cube.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sword : MonoBehaviour {
public AudioSource sliceAudio;
public void PlaySliceSound() {
sliceAudio.pitch = Random.Range(0.7f, 1.5f); // randomize pitch
sliceAudio.Play(); // play sound
}
}
After the script is added, add an AudioSource component to the swords, and drag in any audio clip. The clip will be played every time a cube is sliced.
Score Management đ
Create a new UI>Text-TextMeshPro in the Hierarchy, and import the TMPro essentials package from the pop-up.
Select your newly created text, and create a new script called: âScore Managerâ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class ScoreManager : MonoBehaviour {
public TextMeshProUGUI scoreText; // reference to self
public static int score; // static to make it easy to access accross all scripts & scenes
void Start() {
scoreText = GetComponent<TextMeshProUGUI>(); // self reference
score = 0; // reset score
}
void Update() {
scoreText.text = "Score: " + score; // update score display every frame
}
}
Select the newly created Canvas, and change the render mode from âScreen Space - Overlayâ to âWorld Spaceâ. Move it to a new position in front of the player to make it easier to read.
Death Platform đ
Create a new 3D Object>Plane and a new tag called âDieâ. Tag your new plane with Die, check Convex & Is Trigger on the Mesh Collider and add a Rigidbody component with Is Kinematic checked.
This platform will destroy any cubes that come in contact with it, so reset its position, and move it down to -3 on the y axis.
Sliceable Cubes đ§
Create a new 3D cube object in the Hierarchy, and drag it into the project view to create a new prefab. Add a Rigidbody component to it, and create a new script called âShapeâ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Shape : MonoBehaviour {
public bool sliced; // used to see if the object has been cut at all
public bool cut; // used to make sure if you hit the same shape with 2 swords at the same time, it doesn't summon double the amount of shapes
public int score = 5; // base score at a full size
public float size = 1; // base start size
public float sizeDivider = 2; // how much should the size of the shape be divided by every time a player slices it
public int scoreMultiplier = 2; // how many more points should a player get for slicing smaller cubes
void Start() {
GetComponent<Rigidbody>().mass = size; // assign objects mass equal to it's size
cut = false;
}
// Update is called once per frame
void Update() {
transform.localScale = new Vector3(size, size, size); // reset size
if(size < 0.125f) { // destroy the game object if it gets too small to slice
MinSizeReached();
}
}
private void OnTriggerEnter(Collider other) {
if (other.CompareTag("Sword")) { // check if we collide with an object with a sword tag
if(cut == false) { // check if it's been cut before? This stops it from summoning more shapes than it should
other.GetComponent<Sword>().PlaySliceSound(); // play the sound from the sword script
Sliced();
}
cut = true;
}
else if(other.CompareTag("Die")) { // check if we collide with an object with a die tag
if(sliced == true) { // if the cube has been cut at all, then nothing happens and we can just destroy the cube
MinSizeReached();
} else { // if not, the player has missed a cube, and must restart the level
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
}
void Sliced() {
sliced = true;
ScoreManager.score += score; // add score
GameObject offcut1 = Instantiate(this.gameObject, transform.position, Quaternion.identity); // create smaller versions
SetOffcutVariables(offcut1); // set variables
GameObject offcut2 = Instantiate(this.gameObject, transform.position, Quaternion.identity); // repeat
SetOffcutVariables(offcut2);
Destroy(this.gameObject);
}
void SetOffcutVariables(GameObject offcut) { // apply all the multipliers
offcut.GetComponent<Shape>().size = size / sizeDivider;
offcut.GetComponent<Shape>().score *= scoreMultiplier;
offcut.GetComponent<Rigidbody>().velocity = new Vector3(Random.Range(-1, 1 + 1), Random.Range(3, 7 + 1), Random.Range(-1, 1 + 1)); // makes the offcuts go in a slightly random direction
offcut.GetComponent<Shape>().sliced = true;
}
void MinSizeReached() {
Destroy(this.gameObject);
}
}
Shape Spawner đŸ
Create a new Empty GameObject and set its location right above the death platform. Create a new script called âSpawnerâ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour {
public GameObject[] shapes; // list of shapes the spawner can spawn
public float startTimeBtwSpawns = 3;
float timeBtwSpawns; // current time before another shape
[Header("Start Velocities")]
public float XminStartVelocity = -0.2f;
public float XmaxStartVelocity = 0.2f;
[Space]
public float YminStartVelocity = 7;
public float YmaxStartVelocity = 10;
[Space]
public float ZminStartVelocity = -0.2f;
public float ZmaxStartVelocity = -2;
private void Start() {
timeBtwSpawns = startTimeBtwSpawns; // reset time at start
}
void Update() {
timeBtwSpawns -= Time.deltaTime; // remove time from timer
if(timeBtwSpawns <= 0) {
timeBtwSpawns = startTimeBtwSpawns;
SummonObject();
}
}
void SummonObject() {
startTimeBtwSpawns *= 0.99f; // shorten time btw spawns to make game harder over time
GameObject curOBJ = Instantiate(shapes[Random.Range(0, shapes.Length)], transform.position, Quaternion.identity); // summon object
curOBJ.GetComponent<Rigidbody>().velocity = new Vector3(Random.Range(XminStartVelocity, XmaxStartVelocity+1), Random.Range(YminStartVelocity, YmaxStartVelocity+1), Random.Range(ZminStartVelocity, ZmaxStartVelocity+1)); // make it go in a random direction
}
}
Environment đČ
You can download forest environment models off of itch.io or the unity asset store to build a nicer-looking environment. As a bare minimum, I recommend creating a new 3D Object>Plane above the spawner as a barrier between the player and the appearing cubes. This will make it look as if the cubes are passing right through the ground.
𧱠Building Your Game đ§±
Open your build settings under File>Build Setting and switch to an android build. Plugin your headset to your computer through a USB cable, and with developer mode enabled on the headset (check out this article if developer mode isnât enabled), press build and run, and play your game! Youâre done! Good job!
Hopefully, this article helped you build your first VR Game! đ If you have any questions or feedback for this article, please contact me by commenting on this article! See you soon with another project! đ