Edited at

UnityでマルチプレイVRを一番簡単に実現する方法


概要

「Unityで一番簡単に実現する方法」シリーズ第二弾です。

前回は「Unity でVRのテレポートを一番簡単な実装」ということで、VRテレポートシステムを作りました。今回はそれを引き続いて行きます。前回をやっていない方はそちらからやっていってください。

今回は前回やったVRテレポートを使って、多人数が同じ空間参加できるようにすることを実現しようと思います。多人数と言ってもMMO的な大規模ではなく、数人レベルで、かつ同じLAN内での利用を想定しています。

実装の順番としては


  1. Forge Networking インストール

  2. マッチング画面シーンのVR対応

  3. Playerオブジェクトの追従

  4. Network Contact Wizardを使ったコード自動生成

  5. Playerクラスの実装

  6. Player のPrefab化

  7. NetworkManager の修正

  8. GameLogic で Player の生成

  9. 確認

という段階を踏んでいきます。


Forge Networking インストール

ここではForge Networking というアセットを使って、マルチプレイを実現します。

f690d7de-56e1-44dc-ac61-fe2740deb2b8.jpg

Asset Store からダウンロードしてインポートしてください。


マッチング画面シーンのVR対応

スタートしていきなり多人数接続というわけにはいかず、ホストとして参加するか、そのホストにつないで参加するか、という選択画面が必要になります。それがいわゆるマッチングというものです。

マッチング画面シーンである

Assets/Bearded Man Studios Inc/Scenes/MultiplayerMenu.unity

を開いてください。このままではデスクトップ画面ですので、これをVR対応する必要があるのですが、ここでは手っ取り早く


  • 何も見えないけどボタンを押す(Connect)

  • ホストに繋がって次のシーンへ遷移する

という適当遷移として実装します。(本来であれば、ホストのIPアドレスを打って、ConnectというUI画面対応をしたほうが良いのですが、ここでは端折ります)

とりあえず、「File→Save As...」でこのシーンを「MultiplayerMenuVR.unity」とかに変更しておきましょう。

そして、

private void Start()

{
ipAddress.text = "127.0.0.1";
portNumber.text = "15937";
:

のipAddress.text の部分のIPアドレスをホストとなるPCのIPアドレスにします。

IPアドレスは コマンドラインから ipconfig(Macならifconfig)で 調べてください。

私の場合は

    ipAddress.text = "192.168.1.12";

こんな感じになります。(皆さんそれぞれで違うはずです)

次に前回も使った

Assets/VRTK/Prefabs/CameraRig/UnityXRCameraRig/InputMappings/UnityXR.OpenVR.RightController.prefab

をシーンにD&D

Unity_2018_3_0f2_-_MultiplayerMenuVR_unity_-_MultiplayTest_-_Android__Metal_.png

そのUnityXR.OpenVR.RightControllerの中の項目を変更します。


  1. UnityXR.OpenVR.RightController>Trackpad>Press[9] を選択

  2. +ボタンをクリック

  3. シーン中の「Canvas」を空いている項目にD&D

  4. No Function から 「MultiplayMenu→Connect」に変更

Unity_2018_3_0f2_-_MultiplayerMenuVR_unity_-_MultiplayTest_-_Android__Metal_.png

これでPadボタンを押すとシーンが遷移するようになりました。

シーンを追加します。


  1. メニューから File → Build Settings...

  2. Add Open Scenes (現在開いているMultiplayMenuVRシーンを追加します)

  3. 追加したMultiplayMenuVRシーンを一番上にD&Dします。

File_と_Item-0_と_Item-0_と_Item-0_と_Item-0_と_Item-0.png


Playerオブジェクトの追従

前回作ったPlayerオブジェクトは動かしていませんでしたね。これを動かしていきましょう。

Gameシーンを再び開いてください。

プレイヤーとして作ったPlayer オブジェクトをカメラの動きに追従するスクリプトを作ります。

FollowCamera.cs というスクリプトを作って、以下のように書きます。


FollowCamera.cs

using System.Collections;

using System.Collections.Generic;
using UnityEngine;

public class FollowCamera : MonoBehaviour
{
private Transform _camTrs;

void Start()
{
_camTrs = GameObject.FindWithTag("MainCamera").transform;
}

// Update is called once per frame
void Update()
{
this.transform.position = _camTrs.position;
this.transform.rotation = _camTrs.rotation;
}
}


これをPlayerオブジェクトにD&Dします。


Network Contact Wizardを使ったコード自動生成

次に、Forge Networkingの「Network Contact Wizard」というツールを使ってNetworkで流すデータを使うためのクラス群を作っていきます。こちらのツールを使えばそれらが自動で作ってくれるので大変便利です。

メニューから Window → Forge Networking → Network Contact Wizard を選択してWizardを立ち上げます

Window_と_Item-0.png

下記画面が出るので、Createをクリックしてください。

空白_Skitch_キャンバス.png

その画面で次のように設定してください。


  1. Name にはネットワークに流すデータ取りまとめの名前を入れます。ここでは "Player" と入れます

  2. +ボタンを押して項目を追加します。2つ作ります

  3. [position , VECTOR4, Interpolate, 0.15] と、[rotation, QUATERNION, Interpolate, 0.15] を項目に代入してください

  4. 「Save & Compile」をクリックして、クラス群を作ります

空白_Skitch_キャンバス.png

ちょっとすると、

Assets/Bearded Man Studios Inc/Generated/UserGenerated/

以下に

PlayerBehavior.cs 

PlayerNetworkObject.cs

というファイルが出来ているはずです。こちらが先程のWizardで自動的に生成されたファイルです。


Playerクラスの実装

ネットワークで位置と回転を同期するためのスクリプトを書きます。

Player.cs というファイルを作って、PlayerゲームオブジェクトにD&Dしてください。

Playerクラスは以下のようなスクリプトにしてください。


Player.cs

using System.Collections;

using System.Collections.Generic;
using UnityEngine;
using BeardedManStudios.Forge.Networking.Generated;

// PlayerBehaviorは自動生成されて作られたスクリプトです。そこから継承させています。
public class Player : PlayerBehavior
{
// Update is called once per frame
void Update()
{
if (!networkObject.IsOwner)
{
// ホストじゃなければ、NetworkObjectから渡ってきたデータをそのまま渡す
this.transform.position = networkObject.position;
this.transform.rotation = networkObject.rotation;
return;
}

// NetworkObjectに位置と回転を教えてあげる
networkObject.position = this.transform.position;
networkObject.rotation = this.transform.rotation;
}
}



Player のPrefab化

Gameシーン中の、今出来上がったばかりのPlayerオブジェクトをPrefab化します。


  1. 適当なProjectの場所にD&Dすればよいだけです。

  2. Prefab化したシーン中のPlayerオブジェクトは消してしまいます。

Unity_2018_3_0f2_-_Game_unity_-_MultiplayTest_-_Android__Metal_.png


NetworkManager の修正

NetworkManagerというので、ネットワークに繋いだ際にPlayerの生成をしてくれるようです。そこにPlayerオブジェクトを登録しましょう。

Assets/Bearded Man Studios Inc/Prefabs/NetworkManager.prefab

を選択します。(Unity 2018以降の場合は「Open Prefab」クリックして中身を見ます)

このPrefabを直接いじっていきます。

そこの「Player Network Object」のSize を「1」にして、先程作ったPlayer PrefabをD&Dします。

Unity_2018_3_0f2_-_Game_unity_-_MultiplayForge_-_Android__Metal_.png


GameLogic で Player の生成

いよいよ最後のステップです。

NetworkManagerを介してPlayerオブジェクトを生成します。

「GameLogic」という空のゲームオブジェクトを作り、GameLogic.cs というスクリプトを作ります。


GameLogic.cs

using UnityEngine;

using BeardedManStudios.Forge.Networking.Unity;

public class GameLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
NetworkManager.Instance.InstantiatePlayer();
}
}


それをGameLogicゲームオブジェクトにD&Dします。

これでこのシーンに遷移したと同時にPlayerオブジェクトが生成されるということです。


確認

さあ、これで全部終わりました。

確認していきましょう。

まずはBuild & Run でOculus Go で実行しておきます。

インストールしてUnityロゴが表示されてアプリが立ち上がったら、ちょっと一旦何もせずにUnity Editorに戻りましょう。

GO02.gif

Unity Editor上でMultiplayMenuVRを開いて、Playします。

そして、UIの一番下に配置している「(h)Host(〜」をクリックします。

Unity_2018_3_0f2_-_MultiplayerMenuVR_unity_-_MultiplayTest_-_Android__Metal_.png

そして、今度はOculus Goでハンドデバイスのパッドを押して、ホストに繋ぎます。

すると、Oculus Go では普通にテレポート出来ていると思います。

GO04.gif

Unity Editorでは、Oculus Go で動いているプレイヤーの様子が第三者視点で見れるかと思います。

GO03.gif

もしOculus Go が2台ある場合は、そちらも同様に参加してみてください。

Unity Editor上に2台のプレイヤーの様子がわかるかと思います。