MRが楽しい

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

UnityEventを使ってInspectorビューから実行処理を指定する その2(引数の指定)

本日は Unity の技術調査枠です。
前回、UnityEventの設定方法をまとめました。
bluebirdofoz.hatenablog.com


今回はUnityEventに引数を設定する方法についてまとめます。
f:id:bluebirdofoz:20190208072017j:plain

Inspectorビューから引数を渡す

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;
    }
    public void ToChangeScale(int scale)
    {
        // オブジェクトを任意の倍率に変更
        transform.localScale = transform.localScale * scale;
    }
}

この状態で、UnityEvent の Inspector ビューから関数を検索します。
すると、以下のように引数付きの関数も一覧に表示され、選択が可能になっています。
f:id:bluebirdofoz:20190208072031j:plain

関数を指定し、Inspector ビューを改めて確認すると、以下のように引数の値を設定する欄が表示されています。
f:id:bluebirdofoz:20190208072047j:plain

ただし制限として、引数の数が1つまでの関数しか利用できません。
2つ以上の引数を利用する関数は、関数の一覧に表示されません。

引数を動的に渡す

上記の方法だと、Inspector ビューで引数の値を指定するため、引数をプログラム実行中に自由に変更できません。
動的に引数を渡したい場合は、UnityEvent クラスを継承した新規クラスを作成する必要があります。
docs.unity3d.com

連続タップの検出スクリプトをサンプルに利用します。
タップカウントの値を引数として UnityEvent を設定できるよう改修しました。

UnityEvent を継承した MyIntEvent を作成し、Invoke(int arg0) 関数で引数を指定して実行しています。
・MultiTapEvent.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// IInputClickHandler を利用するため InputModule を追加
using HoloToolkit.Unity.InputModule;

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


// 引数に Int を受け取る UnityEvent<T0> の継承クラスを作成する
// Inspector ビューに表示させるため、Serializable を設定する
[System.Serializable]
public class MyIntEvent : UnityEvent<int>
{
}


public class MultiTapEvent : MonoBehaviour,
IInputClickHandler // タップ操作検出
{
    /// <summary>
    /// グローバルリスナーの有無
    /// </summary>
    [Tooltip("グローバルリスナーの有無")]
    public bool IsGlobalListener = false;


    // 作成した継承クラスで UnityEvent を登録する
    /// <summary>
    /// 連続タップ実行処理
    /// </summary>
    [SerializeField, Tooltip("連続タップ実行処理")]
    private MyIntEvent MultiTapUnityEvent;


    /// <summary>
    /// 連続タップ許容時間(秒)
    /// </summary>
    [SerializeField, Tooltip("連続タップ許容時間(秒)")]
    private float MultTapTime = 0.5f;

    /// <summary>
    /// 連続タップカウント
    /// </summary>
    private int p_MultTapCount;

    /// <summary>
    /// 連続タップ計測開始時刻
    /// </summary>
    private float p_MultTapStart;

    /// <summary>
    /// 起動時処理
    /// </summary>
    void Start ()
    {
        if (IsGlobalListener)
        {
            // 全てのジェスチャーイベントをキャッチする
            // 本設定を有効にしてColliderオブジェクトにアタッチした場合
            // オブジェクトへのタップとグローバルのタップが
            // 別々に検出される(連続タップとなる)ので注意
            InputManager.Instance.AddGlobalListener(gameObject);
        }
    }

    /// <summary>
    /// 定期実行
    /// </summary>
    void Update ()
    {
        // 連続タップ判定
        if (p_MultTapCount > 1)
        {
            // タップカウントが 2 以上の時、連続タップの発生チェック
            if ((Time.time - p_MultTapStart) > MultTapTime)
            {
                // 連続タップ許容時間が経過していればカウントに応じて処理を実行
                if (p_MultTapCount == 2)
                {
                    // ダブルタップ処理
                    Debug.Log("DoubleTap");
                    
                    // タップカウントの値を引数に指定して UnityEvent を実行
                    MultiTapUnityEvent.Invoke(p_MultTapCount);
                    
                }
                if (p_MultTapCount == 3)
                {
                    // トリプルタップ処理
                    Debug.Log("TripleTap");
                    
                    // タップカウントの値を引数に指定して UnityEventを実行
                    MultiTapUnityEvent.Invoke(p_MultTapCount);
                    
                }
                p_MultTapCount = 0;
            }
        }
    }

    /// <summary>
    /// タップ検出
    /// </summary>
    /// <param name="eventData"></param>
    public void OnInputClicked(InputClickedEventData eventData)
    {
        Debug.Log("clicked!");

        // 現在時刻の取得
        float nowTime = Time.time;

        // 連続タップ確認
        float tapTime = nowTime - p_MultTapStart;
        if (tapTime > MultTapTime)
        {
            // 前回タップから連続タップ許容時間を超えていれば初回タップと再判定
            p_MultTapCount = 1;
        }
        else
        {
            // 前回タップから連続タップ許容時間内ならば連続タップと判定
            p_MultTapCount++;
        }
        // 連続タップ計測開始時刻を更新
        p_MultTapStart = nowTime;
    }
}

作成したスクリプトSphere オブジェクトにアタッチします。
すると、Inspector ビューに「Unity Event (Int32)」という UnityEvent の設定項目が表示されます。
f:id:bluebirdofoz:20190208072246j:plain

オブジェクトを指定し、関数一覧を開きます。
すると「Dynamic int」という項目が追加されており、そこに引数指定可能な関数が表示されます。
動的に引数を渡す関数を指定したい場合は、この「Dynamic int」に表示された関数を指定します。
f:id:bluebirdofoz:20190208072257j:plain

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

連続タップを行ったとき、ダブルタップの時は2倍、トリプルタップの場合は3倍というように、タップ回数に応じて倍率の異なる拡大処理が実行されれば成功です。
f:id:bluebirdofoz:20190208072315j:plain

UnityEventには以下の4つの抽象クラスがあり、これらを利用すると最大4つの引数までの UnityEvent の利用が可能です。
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com