MRが楽しい

MRやVRについて学習したことを書き残す

HoloLensでファイル変更イベントを検出する その1(UnityEditor上のデバッグ)

本日は Unity と HoloLens の技術調査枠です。
UWPアプリでファイル変更イベントを検出する方法をまとめます。
f:id:bluebirdofoz:20190305091613j:plain

UWPにおけるファイル変更イベント

UWPアプリでファイル変更イベントを取得する場合、StorageFileQueryResult を利用します。
docs.microsoft.com

しかし本クラスは UnityEditor 上では利用できないため、動作確認はビルドして行うことになります。
イベント検出後の動作検証を UnityEditor 上でも行いたいので、今回はまず UnityEditor 上でファイル変更イベントの検出を実装します。

UnityEditorでのファイル変更イベント

UnityEditorでファイル変更イベントを取得する場合、FileSystemWatcher が利用可能です。
docs.microsoft.com

プロジェクトとシーンの準備

以下の記事を元にHoloLens(WindowsMR)プロジェクトを作成します。

2019/3/5現在、MRTK 2017 の最新バージョンは 2017.4.3.0 です。
bluebirdofoz.hatenablog.com
f:id:bluebirdofoz:20190305091754j:plain

また、今回は UnityEditor 上でファイル変更イベントを検出するディレクトリとして、Assets/SteamingAssets フォルダを利用します。
Assets 配下に StreamingAssets フォルダを作成しておきます。
f:id:bluebirdofoz:20190305091814j:plain

FileSystemWatcherを用いたサンプルコード

以下の処理を行うサンプルコードを作成しました。
1.Assets/SteamingAssetsフォルダにTXTファイルが作成/削除/変更されたイベントを検出します。
2.イベントを検出すると、UnityEventで指定された関数を実行します。

・FileChangeWatcher.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// UnityEvent を利用するため Events を追加
using UnityEngine.Events;

public class FileChangeWatcher : MonoBehaviour
{
    /// <summary>
    /// ファイル検出時実行処理
    /// </summary>
    [SerializeField, Tooltip("ファイル検出時実行処理")]
    private UnityEvent FileChangeEventUnityEvent;

    /// <summary>
    /// ファイル変更イベント検出フラグ
    /// </summary>
    private bool p_ChangedFlg;

    /// <summary>
    /// 初期化処理
    /// </summary>
    private void Start()
    {
        // 検出フラグOFF
        p_ChangedFlg = false;

        // ファイル監視初期化
        FileSystemWatcher_Init();
    }

    /// <summary>
    /// 定期実行
    /// </summary>
    private void Update()
    {
        if (p_ChangedFlg)
        {
            // ファイル変更を検出すればUnityEvent実行
            FileChangeEventUnityEvent.Invoke();
            // 検出フラグをOFF
            p_ChangedFlg = false;
        }
    }

    /// <summary>
    /// ファイル監視インスタンス
    /// </summary>
    private System.IO.FileSystemWatcher fileSystemWatcher = null;

    /// <summary>
    /// ファイル監視初期化
    /// </summary>
    private void FileSystemWatcher_Init()
    {
        // 監視用インスタンスの作成
        fileSystemWatcher = new System.IO.FileSystemWatcher();

        // 監視ディレクトリの指定(本例はAssets/SteamingAssetsフォルダ)
        fileSystemWatcher.Path = UnityEngine.Application.streamingAssetsPath;

        // 最終アクセス日時、最終更新日時、ファイル名を監視
        fileSystemWatcher.NotifyFilter =
            (System.IO.NotifyFilters.LastAccess
            | System.IO.NotifyFilters.LastWrite
            | System.IO.NotifyFilters.FileName);

        // ".txt"の拡張子を持つファイルを監視
        // 全てのファイルを監視する場合は""を指定する
        // 複数の拡張子を監視する場合は"*.txt|*.jpg"のように指定する
        fileSystemWatcher.Filter = "*.txt";

        // イベントハンドラの追加
        // Changed: ファイル変更、Created: ファイル作成、Deleted: ファイル削除、Renamed: ファイル名変更
         fileSystemWatcher.Changed += new System.IO.FileSystemEventHandler(FileSystemWatcher_Changed);
        fileSystemWatcher.Created += new System.IO.FileSystemEventHandler(FileSystemWatcher_Changed);
        fileSystemWatcher.Deleted += new System.IO.FileSystemEventHandler(FileSystemWatcher_Changed);
        fileSystemWatcher.Renamed += new System.IO.RenamedEventHandler(FileSystemWatcher_Renamed);

        // 監視を開始する
        fileSystemWatcher.EnableRaisingEvents = true;
    }

    /// <summary>
    /// ファイル変更イベントコールバック関数
    /// </summary>
    private void FileSystemWatcher_Changed(System.Object source, System.IO.FileSystemEventArgs e)
    {
        // ファイル変更イベント発生時の処理
        // 検出フラグONに変更する
        // UnityEventの実行はMainThreadで行う
        p_ChangedFlg = true;
    }

    /// <summary>
    /// ファイル名変更イベントコールバック関数
    /// </summary>
    private void FileSystemWatcher_Renamed(System.Object source, System.IO.RenamedEventArgs e)
    {
        // ファイル名変更イベント発生時の処理
        // 今回は処理無し
    }
}

UnityEvent で呼び出す処理に以前作成した、オブジェクトの拡大関数を指定します。
・ChangeScale.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeScale : MonoBehaviour {
    public void ToDouble()
    {
        // オブジェクトを2倍の大きさに変更
        transform.localScale = transform.localScale * 2.0f;
    }
}

作成した2つのスクリプトSphere オブジェクトにアタッチします。
f:id:bluebirdofoz:20190305091845j:plain

FileChangeWatcher.cs の UnityEvent に Sphere オブジェクト自身を指定します。
呼び出し関数として、オブジェクトの拡大関数を設定します。
f:id:bluebirdofoz:20190305091832j:plain

これで設定完了です。

試してみる

「再生」ボタンをクリックして動作を確認してみます。
f:id:bluebirdofoz:20190305091859j:plain

Assets/SteamingAssets フォルダにファイルをドラッグして追加してみます。
f:id:bluebirdofoz:20190305091909j:plain

ファイル追加に合わせて、オブジェクトの拡大関数が呼び出されました。
イベントの検出に成功しました。
f:id:bluebirdofoz:20190305091924j:plain

イベントのトリガーについて

どのファイルが追加、削除、変更されたか(イベントのトリガーとなったか)の情報は System.IO.FileSystemEventArgs 引数から取得可能です。

void OnChanged(System.Object source, System.IO.FileSystemEventArgs e)
{
     // Specify what is done when a file is changed, created, or deleted.
     WatcherChangeTypes wct = e.ChangeType;
     Console.WriteLine("File {0} {1}", e.FullPath, wct.ToString());
}

docs.microsoft.com

必要ならば以下のUnityEventの引数追加を利用すれば呼び出し関数に情報を渡せます。
bluebirdofoz.hatenablog.com

以前、紹介したテキスト読み込みの機能などと組み合わせると、色々なファイル処理が実現できます。
bluebirdofoz.hatenablog.com

次はUWPアプリで動作するコードを作成します。
bluebirdofoz.hatenablog.com