MLAPIをHoloLensでつかう その4 (物体操作をHost, Clientの両方で行う)
今回は前回の続きです。
xr-physics-work-etc.hatenablog.com
前回では、物体操作はHostからしか行えませんでした。
このままでは都合が悪いことも多いので、誰でも操作できるように、Clientからも物体の操作を行えるようにします。
物体の操作を管理する
MLAPIには、物体の操作権限を委譲するメソッドNetworkObject.ChangeOwnership
を用いることで、各ユーザに操作権限を与えることができます。
しかし、この関数はServer(Host)からしか実行できないため、Client側から操作権限を直接取得することができません。
そのため、Client側から操作権限を取得するには、Host側にChangeOwnership
の実行を依頼する必要があります。
Clientから情報を共有する方法として、NetworkVariable
があります。
そのため、ChangeOwnership
の引数であるnewOwnerClientId
を共有し、値の変更をトリガにServer(Host)側に権限変更を実行させようと思います。
権限変更を依頼するスクリプトを作成します。
ついでに、権限変更の可否を管理する変数も用意しました。
- NetworkSharingObject.cs
クリックで展開
using MLAPI; using MLAPI.NetworkVariable; public class NetworkSharingObject : NetworkBehaviour { /// <summary> /// 更新対象のネットワークID /// 全ユーザ変更可能 /// </summary> NetworkVariableULong newOwnerClientId = new NetworkVariableULong(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone }); /// <summary> /// 操作権限委譲可否 /// 全ユーザ変更可能 /// </summary> /// <returns></returns> NetworkVariableBool enableChangeOwner = new NetworkVariableBool(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone }, true); void OnEnable() { // OnChangeOwnerイベント設定 newOwnerClientId.OnValueChanged += OnChangeOwner; } void OnDisable() { // OnChangeOwnerイベント設定解除 newOwnerClientId.OnValueChanged -= OnChangeOwner; } // Start is called before the first frame update void Start() { if (IsOwner) { // Spawn時のオーナ情報を取得 newOwnerClientId.Value = OwnerClientId; } } // Update is called once per frame void Update() { } /// <summary> /// オーナーシップ変更処理 /// </summary> /// <param name="oldValue"></param> /// <param name="newValue"></param> void OnChangeOwner(ulong oldValue, ulong newValue) { // サーバでしか実行できないため、サーバで実施 if (IsServer) { // オーナーシップ変更可能な場合 if (enableChangeOwner.Value == true) { // オーナーシップ変更を実施 NetworkObject.ChangeOwnership(newValue); } else { // 変更不可の場合はこれまでの値に戻す newOwnerClientId.Value = oldValue; } } } /// <summary> /// オーナーシップ取得依頼 /// </summary> public void TryGetOwnership() { // 自分のクライアントIDを設定 newOwnerClientId.Value = NetworkManager.LocalClientId; } /// <summary> /// 操作権限変更不可設定 /// </summary> public void SwitchDisableChangeOwner() { // 操作権限を持っている場合 if (IsOwner) { // 権限変更不可に設定 enableChangeOwner.Value = false; } } /// <summary> /// 操作権限変更可能設定 /// </summary> public void SwitchEnableChangeOwner() { // 操作権限を持っている場合 if (IsOwner) { // 権限変更可能に設定 enableChangeOwner.Value = true; } } }
作成したNetworkSharingObject
コンポーネントを前回作成したCubeにアタッチします。
Object Manipulator
に操作権限変更のための設定を行います。
操作開始時に、権限取得依頼と権限変更停止、操作終了時に権限変更再開を行うことで、誰かが操作している際には操作できないようにします。
Spawn処理を修正する
次に、ClientからもCubeをSpawnできるように、前回作成したNetworkSpawn.cs
を修正します。
NetworkVariableBool
を用いて、各ユーザ(Host, Client)がtrue
にした際にServer(Host)側でSpawnを実行し、false
に戻します。
- NetworkSpawn.cs
クリックで展開
using UnityEngine; using MLAPI; using MLAPI.NetworkVariable; public class NetworkSpawn : NetworkBehaviour { /// <summary> /// Spawnさせるプレハブ /// </summary> [SerializeField] private GameObject spawnPrefab; /// <summary> /// Spawnスイッチ /// 全ユーザ変更可能 /// </summary> /// <returns></returns> NetworkVariableBool isSpawn = new NetworkVariableBool(new NetworkVariableSettings { WritePermission = NetworkVariablePermission.Everyone }, false); // 追加 void OnEnable() // 追加 { // OnStartSpawnイベント設定 isSpawn.OnValueChanged += OnStartSpawn; } void OnDisable() // 追加 { // OnStartSpawnイベント設定解除 isSpawn.OnValueChanged -= OnStartSpawn; } public void SpawnObject() { isSpawn.Value = true; // 変更 } void OnStartSpawn(bool oldValue, bool newValue) // 追加 { // サーバかつisSpawnがTrueの場合実施 if (IsServer && isSpawn.Value == true) { // Spawnされる場所は、自オブジェクトの1m奥、1m上に設定。 Vector3 spawnPosition = this.transform.position + new Vector3(0f, 1f, 1f); // ローカルでSpawn GameObject spawnObject = Instantiate(spawnPrefab, spawnPosition, Quaternion.identity); // ほかのユーザでもSpawn実施 spawnObject.GetComponent<NetworkObject>().Spawn(); // フラグを下げる isSpawn.Value = false; } } }
NetworkVariable
にはNetworkObject
コンポーネントが必要なため、Spawn用のボタンにアタッチします。
ボタンは動的にSpawnしないオブジェクトのため、NetworkManager
に登録する必要はありません。
動作確認
今回も前回と同様にHoloLens側でConnect Host、PC側でConnect Clientボタンを押して共有を開始しました。
これで、PCのClient側からのSpawnや、他人がSpawnしたオブジェクトを別の人が操作できることを確認できました。
最低限物体共有を行うための機能ができました。