
ネットワークを介したマルチプレイの、シンプルな実装です。

概要
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>
実行すると、どのプレイヤからも、ターゲットのオブジェクトに作用する(押せる)ことを確認できるはずですーー単純な協力プレイの実現ですね。


