Dev Story: How to Create Multiplayer Oculus Rift Games in Unity (Video Tutorial)
This guest post was written by Hayden Lee, Founder & Software Engineer at Convrge.
Convrge is a virtual world to hang out with your friends. Using the Oculus Rift you can get a sense of actually being with people that is unmatched across any other medium.
Activities in Convrge include watching YouTube videos, Twitch.TV, rockin’ out on the dancefloor and playing minigames, all with people from around the world.
Many people have been asking how we network players in Convrge. We’ve gone through a few iterations of different techniques ourselves and I wanted to spill the beans in this post to help other aspiring virtual reality developers be able to network their own games. One of the driving forces of creating Convrge in the beginning was the mismatch between how cool multiplayer VR experiences are and how few were actually available. Hopefully this post will help even out that mismatch, and help you add multiplayer to your virtual realities.
The tools are surprisingly easy to use:
One thing to note here is that many, many multiplayer Oculus experiences already use these same tools. The “oh cool, what are you using for networking?” conversations usually end up pretty boring because the answer is almost universally “Photon.” Photon works very similarly to the standard built-in Unity networking tools which makes it very approachable, while also having a lot of advanced features and flexibility. Currently we use their PUN+ edition which allows up to 100 people on your app concurrently for a once off price of $99. Pretty groovy.
As I’m writing this I’ve realized how much easier this tutorial would be in video form, so I’m going to write out the general bullet points of the process and record the step-by-step in a video.
Here is the video (probably worth full screening it to see the text):
Here are the bullet points:
- Import the Photon and Oculus Unity integrations.
- Drag the Oculus Player Controller prefab into your scene.
- Create a C# script to handle connecting to the network and instantiating the player, attach this to an empty GameObject (script is copied below).
- Create a C# script to handle the player synchronization (script is copied below).
- Create an empty GameObject for the player synchronization, add a photon view to this, and add the above script component to this.
- Turn this GameObject into a prefab by dragging it into the Resources folder (this is also necessary to use this prefab with the Photon instantiate call).
- Once the player prefab is instantiated we attach our own player to the CenterEyeAnchor of the Oculus Player Controller. Then we use the position/rotation of the Player controller for the global position of your avatar and the position/rotation of the CenterEyeAnchor for the local position.
- Voila. Start game.
Here are the code snippets:
using UnityEngine;
using System.Collections;
public class NetworkedPlayer : Photon.MonoBehaviour
{
public GameObject avatar;
public Transform playerGlobal;
public Transform playerLocal;
void Start ()
{
Debug.Log("i'm instantiated");
if (photonView.isMine)
{
Debug.Log("player is mine");
playerGlobal = GameObject.Find("OVRPlayerController").transform;
playerLocal = playerGlobal.Find("OVRCameraRig/TrackingSpace/CenterEyeAnchor");
this.transform.SetParent(playerLocal);
this.transform.localPosition = Vector3.zero;
// avatar.SetActive(false);
}
}
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.isWriting)
{
stream.SendNext(playerGlobal.position);
stream.SendNext(playerGlobal.rotation);
stream.SendNext(playerLocal.localPosition);
stream.SendNext(playerLocal.localRotation);
}
else
{
this.transform.position = (Vector3)stream.ReceiveNext();
this.transform.rotation = (Quaternion)stream.ReceiveNext();
avatar.transform.localPosition = (Vector3)stream.ReceiveNext();
avatar.transform.localRotation = (Quaternion)stream.ReceiveNext();
}
}
}
using UnityEngine;
using System.Collections;
public class NetworkController : MonoBehaviour
{
string _room = "Tutorial_Convrge";
void Start()
{
PhotonNetwork.ConnectUsingSettings("0.1");
}
void OnJoinedLobby()
{
Debug.Log("joined lobby");
RoomOptions roomOptions = new RoomOptions() { };
PhotonNetwork.JoinOrCreateRoom(_room, roomOptions, TypedLobby.Default);
}
void OnJoinedRoom()
{
PhotonNetwork.Instantiate("NetworkedPlayer", Vector3.zero, Quaternion.identity, 0);
}
}
Any feedback is welcome at hayden@convrge.co