Feel Physics Backyard

HoloLensの出張授業をする会社で、教材を開発しています

シェアリングのPrefabSpawnManagerの設置のしかた

HoloLensのシェアリングでプレハブを生成したいときは、MRTKにそのためのスクリプトが入っています。PrefabSpawnManagerスクリプトです。このスクリプトを使うと、シェアリングをしている各HoloLensの世界に同時にプレハブを、シェアリングによる位置合わせもして生成することができます。

なお、この記事は以下の記事の続きですが、読まなくても大丈夫です:

www.weed.nagoya

1. PrefabSpawnManagerスクリプトをアタッチ

まず、PrefabSpawnManagerスクリプトをSharingプレハブにアタッチします。

2. SyncSpawnedMagnetスクリプトの作成

「Magnet」の部分は適宜読み替えて下さい。SyncSpawnedObjectクラスを継承して作成します。

//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
//

using HoloToolkit.Sharing.Spawning;
using HoloToolkit.Sharing.SyncModel;

namespace HoloToolkit.Sharing.Tests
{
    /// <summary>
    /// Class that demonstrates a custom class using sync model attributes.
    /// </summary>
    [SyncDataClass]
    public class SyncSpawnedMagnet : SyncSpawnedObject
    {
        [SyncData]
        public SyncBool showsMagneticForceLines;
    }
}

3. SyncSpawnedMagnetクラスの登録

PrefabSpawnManagerコンポーネントに、先ほど作成したSyncSpawnedMagnetクラスを登録します。

f:id:weed_7777:20180502133125p:plain

4. MagnetSpawnerスクリプトの作成

コードを書きます。

using HoloToolkit.Sharing;
using HoloToolkit.Sharing.Spawning;
using HoloToolkit.Sharing.Tests;
using UnityEngine;

namespace Education.FeelPhysics.MySharingTest
{
    /// <summary>
    /// 自分がシェアリングサーバに参加したときに、磁石を生成する
    /// </summary>
    public class MagnetSpawner : MonoBehaviour
    {
        /// <summary>
        /// PrefabSpawnManagerへの参照を取るためのフィールド
        /// </summary>
        [SerializeField]
        private PrefabSpawnManager spawnManager;

        /// <summary>
        /// ユーザーID
        /// </summary>
        private long userId;

        /// <summary>
        /// シェアリングサーバーに接続するのを待つ
        /// </summary>
        private void Start()
        {
            // SharingStage should be valid at this point, but we may not be connected.
            if (SharingStage.Instance.IsConnected)
            {
                this.Connected();
            }
            else
            {
                SharingStage.Instance.SharingManagerConnected += this.Connected;
            }
        }

        /// <summary>
        /// シェアリングサーバに接続すると呼ばれる
        /// ここからさらにユーザが参加するのを待つ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Connected(object sender = null, System.EventArgs e = null)
        {
            SharingStage.Instance.SharingManagerConnected -= this.Connected;

            SharingStage.Instance.SessionUsersTracker.UserJoined += this.UserJoinedSession;
            SharingStage.Instance.SessionUsersTracker.UserLeft += this.UserLeftSession;
        }

        /// <summary>
        /// 新しいユーザが、現在のセッションから退出すると呼ばれる
        /// </summary>
        /// <param name="user">現在のセッションから退出したユーザ</param>
        private void UserLeftSession(User user)
        {
            this.DeleteMyMagnets();
        }

        /// <summary>
        /// 新しいユーザが、現在のセッションに参加すると呼ばれる
        /// </summary>
        /// <param name="user">現在のセッションに参加したユーザ</param>
        private void UserJoinedSession(User user)
        {
            this.userId = SharingStage.Instance.Manager.GetLocalUser().GetID();

            // 他のユーザが参加したときは磁石の更新は行わない
            if(user.GetID() == this.userId)
            {
                this.DeleteMyMagnets();

                this.CreateMagnet(this.userId);
            }
        }

        /// <summary>
        /// 新たに参加したユーザのユーザIDの磁石がない場合、PrefabSpawnManagerを使ってSpawnする
        /// </summary>
        /// <param name="userId"></param>
        private void CreateMagnet(long userId)
        {
            Vector3 position = new Vector3(0, 0, 1.5f);
            Quaternion rotation = Quaternion.identity;
            var spawnedObject = new SyncSpawnedMagnet();
            this.spawnManager.Spawn(spawnedObject, position, rotation, null, "SpawnedMagnet", true);
        }

        /// <summary>
        /// ユーザがセッションから退出した際に磁石を削除する
        /// </summary>
        /// <param name="remoteMagnetObject"></param>
        private void RemoveRemoteMagnet(GameObject remoteMagnetObject)
        {
            Object.DestroyImmediate(remoteMagnetObject);
        }

        /// <summary>
        /// セッション参加が複数回起きて自分が生成した磁石が複数になった場合のために、
        /// 自分が生成した磁石をすべて削除する
        /// </summary>
        private void DeleteMyMagnets()
        {
            var magnets = GameObject.FindGameObjectsWithTag("Magnet");
            foreach (var magnet in magnets)
            {
                var syncModelAccessor = magnet.GetComponent<DefaultSyncModelAccessor>();
                if (syncModelAccessor != null)
                {
                    var syncSpawnObject = (SyncSpawnedObject)syncModelAccessor.SyncModel;
                    if (syncSpawnObject.OwnerId ==
                        SharingStage.Instance.Manager.GetLocalUser().GetID())
                    {
                        // 磁石のOnDestroyを走らせる
                        Object.DestroyImmediate(magnet);

                        this.spawnManager.Delete(syncSpawnObject);
                    }
                }
            }
        }
    }
}

作成したスクリプトは適当なオブジェクトにアタッチします。

5. Spawn ManagerフィールドにSharingオブジェクトをドラッグする

Unity上で、先ほど作成したMagnetSpawnerスクリプトのSpawn Managerフィールドに、PrefabSpawnManagerスクリプトをアタッチしたオブジェクト(Sharingなど)をドラッグします。

これで終了です。