夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Hololens用のオリジナルUIを作成する。 ~スイッチレバー その③~  上下左右の動きの検知

MRTKを基にHoloLensで使用できるオリジナルのUIを作成します。

過去にSFチックのUIを作成していました。 今回はシリーズ続編としての第三回です。

〇第一弾

redhologerbera.hatenablog.com

〇第二弾

redhologerbera.hatenablog.com

本シリーズで作成したものは以下でMITライセンスで公開しています。(自由に使ってください)

github.com

今回第三弾はレバー(stick)型のUIを作っています。前回まででユーザーがレバーを『握ったことの検知』、『上下左右の動きの検知』の二つの機能を実装しました。

〇ユーザーが『握っている』ときに『上下左右の動きを検知』するようにする

ユーザーが握っているときというアクションの検知はMixedRealityToolKitの機能によって行っています。

上下左右の動きの検知は独自でスクリプトを書きました。

これらを連動させユーザーが握っているときに上下左右の動きを検知するようにします。


現在のコード
public class Switchlever : MonoBehaviour
{
    
    //Hold Status
    public bool _ActionEnebled = false;

    Vector3 dpos;

    public void Update()
    {
        dpos = this.gameObject.transform.localPosition;

        float yaxisparm = System.Math.Abs(dpos.y);
        float xaxisparm = System.Math.Abs(dpos.x);

        bool result = yaxisparm > xaxisparm;
        bool resulty = dpos.y > 0;
        bool resultx = dpos.x > 0;
        bool resultabsy = yaxisparm > 0;
        bool resultabsx = xaxisparm > 0;

        Debug.Log(resultabsx);

        if (!resultabsx && !resultabsy)
        {
            //  UpdateStatus(false, false, false, false);
        }

        if (result && resulty && resultabsy)
        {
            Debug.Log("+Y Axis");
        }

        if (result && !resulty && resultabsy)
        {
            Debug.Log("-Y Axis");
        }

        if (!result && resultx && resultabsx)
        {
            Debug.Log("+X Axis");
        }

        if (!result && !resultx && resultabsx)
        {
            Debug.Log("-X Axis");
        }
    }
    public void leverHoldStat()
    {
        Debug.Log("leverActionStart");
        _ActionEnebled = true;
    }
    public void leverHoldEnd()
    {
        Debug.Log("leverActionEnd");
        _ActionEnebled = false;
    }

}

MRTKの[Interactable.cs]とそれを拡張する[InteractableReceiver.cs]を使用して握ったことを検知した時[leverActionStart()]が発火します。

その際にbool型のActionEnabledをTrueに変えているのでActionEnebledがTrueの時現在のUpdate関数の処理を実行すことにします。

    public void Update()
    {
        if (_ActionEnebled)//追加
        {
            dpos = this.gameObject.transform.localPosition;

            float yaxisparm = System.Math.Abs(dpos.y);
            float xaxisparm = System.Math.Abs(dpos.x);
               ...
         }    
    }

これでユーザーがレバーを握っている間上下左右の検知が行われるようになりました。

〇レバーの動きによって実行するイベントを実装する

これでその①で定義した要件

①ユーザーが握ってレバーを前後左右に倒せる。

②レバーの倒れ方によって前後左右の入力に相当するイベントが発火する

③レバーを動かすのをやめたらリセットされる。(終了のイベントが発火)

から①と②の入力の検知は完了しました。(見た目的にまだレバーではないのですがね・・・)

UIとして入力に対してリアクションが発生するようにイベントを実装します。

次のようにスクリプトに追加します。

public class Switchlever : MonoBehaviour
{
    //Event
    public UnityEvent OnUpdateRightAxisEvent;//追加

    public UnityEvent OnUpdateLeftAxisEvent;//追加

    public UnityEvent OnUpdateUpAxisEvent;//追加

    public UnityEvent OnUpdateDownAxisEvent;//追加


    //Hold Status
    public bool _ActionEnebled = false;

    Vector3 dpos;

    ...

 }

UnityEventはUnityで用意されているクラスでコード内で記述しなくてもUnityのinspectorウィンドウからイベントを行いたいコンポーネントをアタッチして、行いたいメソッドを指定することでイベントが発火させることができる便利な機能です。

docs.unity3d.com

ここでは上・下・左・右の4つのイベントを用意しました。

またUnityEventを使用するためには[UnityEngine.Events]のネームスペースが必要です。

これでUnityのinspectorからイベントを追加できるようにしました。

f:id:Holomoto-Sumire:20200609093444j:plain

追加したイベントを上下左右の動きに合わせて発火するようにします。

    void reslutRightAxisEvent()
    {
        OnUpdateRightAxisEvent.Invoke();
    }

    void resultLeftAxisEvent()
    {
        OnUpdateLeftAxisEvent.Invoke();
    }

    void reslutUpperAxisEvent()
    {
        OnUpdateUpAxisEvent.Invoke();
    }

    void reslutDownAxisEvent()
    {
        OnUpdateDownAxisEvent.Invoke();
    }

UnityEventはUnityEvent.Invole()と記述することでイベントを発火することができます。

各関数を検知したタイミングに呼びます。

完成したスクリプトは以下になります。

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


public class Switchlever : MonoBehaviour
{
    //Event
    public UnityEvent OnUpdateRightAxisEvent;

    public UnityEvent OnUpdateLeftAxisEvent;

    public UnityEvent OnUpdateUpAxisEvent;

    public UnityEvent OnUpdateDownAxisEvent;


    //Hold Status
    public bool _ActionEnebled = false;

    Vector3 dpos;

    public void Update()
    {
        if (_ActionEnebled)
        {
            dpos = this.gameObject.transform.localPosition;

            float yaxisparm = System.Math.Abs(dpos.y);
            float xaxisparm = System.Math.Abs(dpos.x);

            bool result = yaxisparm > xaxisparm;
            bool resulty = dpos.y > 1.0;
            bool resultx = dpos.x > 1.0;
            bool resultabsy = yaxisparm > 1.0;
            bool resultabsx = xaxisparm > 1.0;

            Debug.Log(resultabsx);

            if (!resultabsx && !resultabsy)
            {
                //  UpdateStatus(false, false, false, false);
            }

            if (result && resulty && resultabsy)
            {
                reslutUpperAxisEvent();
            }

            if (result && !resulty && resultabsy)
            {
                reslutDownAxisEvent();
            }

            if (!result && resultx && resultabsx)
            {
                reslutRightAxisEvent();
            }

            if (!result && !resultx && resultabsx)
            {
                resultLeftAxisEvent();
            }
        }
    }

    void reslutRightAxisEvent()
    {
        OnUpdateRightAxisEvent.Invoke();
    }

    void resultLeftAxisEvent()
    {
        OnUpdateLeftAxisEvent.Invoke();
    }

    void reslutUpperAxisEvent()
    {
        OnUpdateUpAxisEvent.Invoke();
    }

    void reslutDownAxisEvent()
    {
        OnUpdateDownAxisEvent.Invoke();
    }
    public void leverHoldStat()
    {
        Debug.Log("leverActionStart");
        _ActionEnebled = true;
    }
    public void leverHoldEnd()
    {
        Debug.Log("leverActionEnd");
        _ActionEnebled = false;
    }

}

以上でターゲットを動かして動きに応じてイベントを引き起こすことが出来ました