ネットワークを介したマルチプレイの、シンプルな実装です。
概要
MRは、身の回りの現実に仮想のモノやヒトを投入しますーーそうなると、仮想現実をその場にいる人たち(家族・友人・仲間)と共有したい、という要望も出てきますよね。
そのためには、MRの利用者が仮想現実と相互作用する結果を、それぞれの利用者に、リアルタイムに反映させる必要があります。
これは、ネットワークを介した同期技術で実現できますがーーUnity にはその目的に使えるライブラリが複数あり、とくに公式にサポートされている同期技術に「Netcode 」があります。
実装
ここでは、Netcode を使った、とてもシンプルな実装を試しますーー
複数の利用者が、シーンにある自身のオブジェクト(ここではキューブ)を左右に移動させる、という単純なマルチプレイです。[※1]
まず、ネット同期のためのパッケージを追加します:
window > package manager > add package: com.unity.netcode.gameobjects
シーンに、ネット管理とプレイヤ管理の空のオブジェクトをそれぞれ追加し、その役割のためのコンポーネント(スクリプトふくむ)を付与します:
hierarchy > SCENE > NETWORK_MANAGER (GameObject) > add component: NetworkManager > add component: NetCtl (Script) > NetworkManager > unity transport (<- select transport) > PLAYER (Cube: GameObject) > add component: NetworkObject > add component: NetworkTransform > add component: PlyCtl (Script)
プレイヤ管理のオブジェクトは、プレハブ化します(シーンからは削除)。そしてネット管理のオブジェクトから、それをプレイヤとして指定します:
project > assets > PLAYER (<- hierarchy > SCENE > PLAYER) hierarchy > SCENE > NETWORK_MANAGER > NetworkManager > player prefab: PLAYER
コードはそれぞれ、次のようになります:
- ・
- NetCtl.cs
using UnityEngine; using Unity.Netcode; public class NetCtl: MonoBehaviour { void OnGUI() { GUILayout.BeginArea(new Rect(0, 0, 100, 100)); if (GUILayout.Button("H")) {NetworkManager.Singleton.StartHost();} if (GUILayout.Button("S")) {NetworkManager.Singleton.StartServer();} if (GUILayout.Button("C")) {NetworkManager.Singleton.StartClient();} GUILayout.EndArea(); } }
- ・
- PlyCtl.cs[※2]
using UnityEngine; using Unity.Netcode; public class PlyCtl: NetworkBehaviour { public float u = 0.01f; void Update() { if (IsOwner) { if (Input.GetKey(KeyCode.RightArrow)) { Mov_ServerRpc( u); } if (Input.GetKey(KeyCode.LeftArrow)) { Mov_ServerRpc(-u); } } } [ServerRpc] void Mov_ServerRpc(float n) { Vector3 v; v = new Vector3(n, 0, 0); transform.position = transform.position + v; } }
アプリをビルドし、複製して複数個に増やし、ぜんぶを起動します。それぞれの画面で、ひとつをサーバ(「S 」)に、そのほかをクライアント(「C 」)にするよう、ボタンを押します。
クライントの画面では、左右のキーを使い、プレイヤのオブジェクト(キューブ)を動かしますーーすべてのアプリの画面に、結果がリアルタイムに反映されることを確認できるはずです。[※3][※4]
- ※1
- 参考:
- ・
- https://docs-multiplayer.unity3d.com/netcode/current/tutorials/get-started-ngo/
- ・
- https://qiita.com/mrt/items/e2a971260479385cd928
- ※2
- このコードの「[ServerRpc] 」以降は、クライアントからサーバに要求する、ネットワーク通信(RPC )の内容を記述する箇所ですーークライアントは、サーバがもつオブジェクトを操作するよう、データともに依頼します。サーバはそのデータをもとに、自身がもつオブジェクト群を依頼どおりに操作します(なおサーバに依頼するための関数は、「〜ServerRpc 」という名前で終わらせる必要があります)。
- ※3
- ボタン「H 」を押すと、そのアプリは<ホスト>になりますーーホストは、サーバ兼クライアントです。運用で使うことはほとんどないと思いますが、アプリを(ビルドせずに)エディタから試験をするのに利用できます(単体のアプリで、サーバとクライアントの動作を確認できる)。
- ※4
- この実装では物理的なネットワークを介していませんが、動作そのものは、インターネット標準のプロトコル(TCP/IP)に準じていますーーサーバは、ローカルループバックアドレス(127.0.0.1 )のポート(7777)で要求を待ち受け、クライアントは、そのポートに要求を送っています(ただUI上はそうみせていても、実装上はローカルなプロセス間通信を使っているかもしれませんがーーUNIXならドメインソケット、Windows なら名前つきパイプ、など)。
補足
それぞれの利用者が勝手に行動するのでなく、利用者の行動が、シーンに影響を与えるようにしてみます。
シーンに物理演算をほどこしたオブジェクトを追加し、プレイヤのオブジェクトが、それに作用する(押せる)ようにします:
hierarchy > SCENE > PLANE (Plane: GameObject) > Transform: y: -0.5 > TARGET_OBJECT (Capsule: GameObject) > Transform: x: 1 > add component: Rigidbody project > assets > PLAYER > add component: Rigidbody > Rigidbody > use gravity: <nil> > is kinematic: <yes>
実行すると、どのプレイヤからも、ターゲットのオブジェクトに作用する(押せる)ことを確認できるはずですーー単純な協力プレイの実現ですね。