/******************************************************************************\ * Copyright (C) Leap Motion, Inc. 2011-2014. * * Leap Motion proprietary. Licensed under Apache 2.0 * * Available at http://www.apache.org/licenses/LICENSE-2.0.html * \******************************************************************************/ using UnityEngine; using System.Collections; using Leap; /** * Detects pinches and grabs the closest rigidbody if it's within a given range. * * Attach this script to the physics hand object assinged to the HandController in a scene. */ public class MagneticPinch : MonoBehaviour { public const float TRIGGER_DISTANCE_RATIO = 0.7f; /** The stiffness of the spring force used to move the object toward the hand. */ public float forceSpringConstant = 100.0f; /** The maximum range at which an object can be picked up.*/ public float magnetDistance = 2.0f; protected bool pinching_; protected Collider grabbed_; void Start() { pinching_ = false; grabbed_ = null; } /** Finds an object to grab and grabs it. */ void OnPinch(Vector3 pinch_position) { pinching_ = true; // Check if we pinched a movable object and grab the closest one that's not part of the hand. Collider[] close_things = Physics.OverlapSphere(pinch_position, magnetDistance); Vector3 distance = new Vector3(magnetDistance, 0.0f, 0.0f); for (int j = 0; j < close_things.Length; ++j) { Vector3 new_distance = pinch_position - close_things[j].transform.position; if (close_things[j].GetComponent() != null && new_distance.magnitude < distance.magnitude && !close_things[j].transform.IsChildOf(transform)) { grabbed_ = close_things[j]; distance = new_distance; } } } /** Clears the pinch state. */ void OnRelease() { grabbed_ = null; pinching_ = false; } /** * Checks whether the hand is pinching and updates the position of the pinched object. */ void Update() { bool trigger_pinch = false; HandModel hand_model = GetComponent(); Hand leap_hand = hand_model.GetLeapHand(); if (leap_hand == null) return; // Scale trigger distance by thumb proximal bone length. Vector leap_thumb_tip = leap_hand.Fingers[0].TipPosition; float proximal_length = leap_hand.Fingers[0].Bone(Bone.BoneType.TYPE_PROXIMAL).Length; float trigger_distance = proximal_length * TRIGGER_DISTANCE_RATIO; // Check thumb tip distance to joints on all other fingers. // If it's close enough, start pinching. for (int i = 1; i < HandModel.NUM_FINGERS && !trigger_pinch; ++i) { Finger finger = leap_hand.Fingers[i]; for (int j = 0; j < FingerModel.NUM_BONES && !trigger_pinch; ++j) { Vector leap_joint_position = finger.Bone((Bone.BoneType)j).NextJoint; if (leap_joint_position.DistanceTo(leap_thumb_tip) < trigger_distance) trigger_pinch = true; } } Vector3 pinch_position = hand_model.fingers[0].GetTipPosition(); // Only change state if it's different. if (trigger_pinch && !pinching_) OnPinch(pinch_position); else if (!trigger_pinch && pinching_) OnRelease(); // Accelerate what we are grabbing toward the pinch. if (grabbed_ != null) { Vector3 distance = pinch_position - grabbed_.transform.position; grabbed_.GetComponent().AddForce(forceSpringConstant * distance); } } }