みどりゲーム

主にUnityについての覚え書きです。

【Unity】【LeapMotion】③左右の手を分けてジェスチャ取得(ついでにトラッキング開始/終了も)

②ではとりあえず、片手での握る/離すジェスチャができました。

今度は左右分けて、どっちが開いて閉じたかを取得したい。

ということで、前回使った
「MotionCtrl.cs」
「IMotionCallback.cs」
を改造してみる。


「MotionCtrl.cs」

using Leap;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;

public class MotionCtrl : MonoBehaviour
{
    public List<GameObject> motionCtrlObjectList;

    private List<IMotionCallback> motionCtrlList;
    private int motionCtrlCount;

    private Controller leapCtrl;
    private Frame leapFrame;
    private List<Hand> handList;
    private Hand R_Hand, L_Hand;

    private bool isTracking;
    private bool isGrabbed_R, isGrabbed_L;
    private bool lastTrackingStatus;
    private bool lastGrabbedStatus_R, lastGrabbedStatus_L;
    private Vector3 convertedValue = new Vector3(0, 0, 0);

    private Vector3 handPosition_R, handPosition_L;
    /*
    public Vector3 HandPosition
    {
        get { return handPosition; }
    }
    */
    private void Start()
    {
        // Trackingと手の状態変化を返す対象のClass.
        motionCtrlList = motionCtrlObjectList.Select(ctrlObject => ctrlObject.GetComponent<IMotionCallback>()).ToList();
        motionCtrlCount = motionCtrlList.Count - 1;

        // App起動時にLeapMotionに接続.
        leapCtrl = new Controller();
        // StartConnectionの実行は必要?
        leapCtrl.StartConnection();

        isTracking = false;
        isGrabbed_R = false;
        isGrabbed_L = false;

        lastTrackingStatus = false;
        lastGrabbedStatus_R = false;
        lastGrabbedStatus_L = false;
    }

    private void Update()
    {
        leapFrame = leapCtrl.Frame();
        handList = leapFrame.Hands;

        isTracking = (handList.Count > 0);

        if (isTracking != lastTrackingStatus)
        {
            // Trackingの開始・停止をCallbackで通知.
            if (isTracking)
            {
                for (var i = motionCtrlCount; i >= 0; i--)
                {
                    motionCtrlList[i].OnTrackingStarted();
                }
            }
            else
            {
                for (var i = motionCtrlCount; i >= 0; i--)
                {
                    motionCtrlList[i].OnTrackingStopped();
                }
                // 手の位置をリセット.
                handPosition_R.Set(0, 0, 0);
                handPosition_L.Set(0, 0, 0);
            }
            lastTrackingStatus = isTracking;
        }

        if (!isTracking)
        {
            // Tracking中でなければ手の位置などは取得しない.
            return;
        }
        for(int NumHands = 0; NumHands < handList.Count; NumHands++)
        {
            if (handList[NumHands].IsRight)
            {
                // Tracking中なら手(Hand0)の平の座標値を取得する.
                handPosition_R = ConvertToUnityVector3(handList[NumHands].PalmPosition);
                // 手を握っているか(誤検知を考慮して開いている指の本数が1以下ならTrue).
                isGrabbed_R = (handList[NumHands].Fingers.Where(finger => finger.IsExtended).Count() <= 1);
                if (isGrabbed_R != lastGrabbedStatus_R)
                {
                    if (isGrabbed_R)
                    {
                        for (var i = motionCtrlCount; i >= 0; i--)
                        {
                            motionCtrlList[i].OnRightHandGrabbed();
                        }
                    }
                    else
                    {
                        for (var i = motionCtrlCount; i >= 0; i--)
                        {
                            motionCtrlList[i].OnRightHandReleased();
                        }
                    }
                    lastGrabbedStatus_R = isGrabbed_R;
                }
            }

            if (handList[NumHands].IsLeft)
            {
                // Tracking中なら手(Hand0)の平の座標値を取得する.
                handPosition_L = ConvertToUnityVector3(handList[NumHands].PalmPosition);
                // 手を握っているか(誤検知を考慮して開いている指の本数が1以下ならTrue).
                isGrabbed_L = (handList[NumHands].Fingers.Where(finger => finger.IsExtended).Count() <= 1);
                if (isGrabbed_L != lastGrabbedStatus_L)
                {
                    if (isGrabbed_L)
                    {
                        for (var i = motionCtrlCount; i >= 0; i--)
                        {
                            motionCtrlList[i].OnLeftHandGrabbed();
                        }
                    }
                    else
                    {
                        for (var i = motionCtrlCount; i >= 0; i--)
                        {
                            motionCtrlList[i].OnLeftHandReleased();
                        }
                    }
                    lastGrabbedStatus_L = isGrabbed_L;
                }
            }
        }
    }

    private void OnApplicationQuit()
    {
        // Appの終了時は切断する.
        leapCtrl.StopConnection();
        leapCtrl.Dispose();
    }
    private Vector3 ConvertToUnityVector3(Vector originalValue)
    {
        // Leap.VectorからUnityのVector3に変換する.
        convertedValue.x = originalValue.x;
        convertedValue.y = originalValue.y;
        convertedValue.z = originalValue.z;
        return convertedValue;
    }
}

変更点は、handList[0](最初に認識した手 二番目ならhandList[1])のところをisLeft/isRightで左右に分けて、コールバックも分けたところです。それに伴い変数も増やしてforで回しています。


そしてコールバックがこちら
「IMotionCallback.cs」

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

public interface IMotionCallback
{
    void OnTrackingStarted();
    void OnTrackingStopped();
    void OnRightHandGrabbed();
    void OnLeftHandGrabbed();
    void OnRightHandReleased();
    void OnLeftHandReleased();
}

それを使うには、前回と同様に、
GetGesture.cs

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

public class GetGesture : MonoBehaviour, IMotionCallback
{
        public void OnTrackingStarted()
    {
        Debug.Log("StartTracking Hand");
    }

    public void OnTrackingStopped()
    {
        Debug.Log("StopTracking Hand");
    }

    public void OnLeftHandGrabbed()
    {
        Debug.Log("LeftHandGrabbed");
    }

    public void OnLeftHandReleased()
    {
        Debug.Log("LeftHandReleased");
    }

    public void OnRightHandGrabbed()
    {
        Debug.Log("RightHandGrabbed");
    }

    public void OnRightHandReleased()
    {
        Debug.Log("RightHandReleased");
    }
}

こんな感じで使います。
この「GetGesture.cs」のついたオブジェクトを「MotionCtrl.cs」の「motionCtrlObjectList」にポイすればOK
f:id:Green_Game:20170221000000j:plain
今回は手本体につけていた「GetGesture.cs」をCameraに移動しました。
f:id:Green_Game:20170221001219g:plain

左右でグーパーできた!!!
(人差し指の誤検知は気にしない)(誤検知多いときは部屋を暗くするといいぞ!)