156 lines
5.9 KiB
C#
156 lines
5.9 KiB
C#
using UnityEngine;
|
|
|
|
namespace Passer.Humanoid {
|
|
|
|
public class PinchInteraction : MonoBehaviour {
|
|
protected HandTarget handTarget;
|
|
protected Socket pinchSocket;
|
|
public bool pinching;
|
|
public static float pinchDistance = 0.04F;
|
|
|
|
// TODO: add phalanges.tip to the list of bones
|
|
private static Vector3 GetTipPosition(HumanoidTarget.BoneTransform bone, Vector3 outward) {
|
|
Vector3 tip = bone.transform.position + bone.targetRotation * outward * 0.02F; // bone.length?
|
|
return tip;
|
|
}
|
|
|
|
#region Start
|
|
protected virtual void Start() {
|
|
if (handTarget == null)
|
|
handTarget = GetComponent<HandTarget>();
|
|
if (handTarget == null)
|
|
return;
|
|
|
|
if (handTarget.humanoid.isRemote)
|
|
// Remote avatars cannot interact
|
|
return;
|
|
|
|
SocketCheck();
|
|
}
|
|
|
|
protected void SocketCheck() {
|
|
HumanoidTarget.BoneTransform handBone = handTarget.hand.bone;
|
|
// How to we distinguish between pinch and palm socket later????? by name?
|
|
pinchSocket = handBone.transform.GetComponentInChildren<Socket>();
|
|
if (pinchSocket != null)
|
|
// Pinch Socket is already present
|
|
return;
|
|
|
|
GameObject socketObj = new GameObject(handTarget.isLeft ? "Left Pinch Socket" : "Right Pinch Socket");
|
|
Transform socketTransform = socketObj.transform;
|
|
socketTransform.parent = handTarget.hand.bone.transform;
|
|
socketTransform.position = handTarget.hand.target.transform.TransformPoint(0.1F, -0.035F, 0.03F);
|
|
socketTransform.rotation = handTarget.hand.bone.targetRotation * Quaternion.Euler(355, 190, 155);
|
|
|
|
pinchSocket = socketObj.AddComponent<Socket>();
|
|
}
|
|
#endregion
|
|
|
|
#region Update
|
|
// sentinel.
|
|
// TODO: implement thread-safe sentinel
|
|
protected bool pinchChecking = false;
|
|
|
|
protected virtual void FixedUpdate() {
|
|
pinching = IsPinching(handTarget);
|
|
|
|
if (handTarget.grabbedObject != null && pinchSocket.attachedTransform != null)
|
|
// We are pinching an object
|
|
PinchDropCheck(handTarget, pinchSocket);
|
|
|
|
else {
|
|
// We are not pinching an object
|
|
if (handTarget.touchedObject == null || handTarget.grabbedObject != null)
|
|
return;
|
|
|
|
if (!pinchChecking) {
|
|
pinchChecking = true;
|
|
PinchCheck(handTarget, pinchSocket, handTarget.touchedObject);
|
|
pinchChecking = false;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Pinch Grab
|
|
public void PinchCheck(HandTarget handTarget, Socket pinchSocket, GameObject obj) {
|
|
if (IsPinching(handTarget) && handTarget.CanBeGrabbed(obj))
|
|
Pinch(handTarget, obj);
|
|
}
|
|
|
|
public static bool IsPinching(HandTarget handTarget) {
|
|
// other fingers need to be open
|
|
float handCurl = handTarget.HandCurl();
|
|
if (handCurl > 1)
|
|
return false;
|
|
|
|
float distance = GetPinchDistance(handTarget);
|
|
return distance < pinchDistance;
|
|
}
|
|
|
|
public static bool IsNotPinching(HandTarget handTarget) {
|
|
float distance = GetPinchDistance(handTarget);
|
|
return distance > pinchDistance + 0.02F;
|
|
}
|
|
|
|
protected static float GetPinchDistance(HandTarget handTarget) {
|
|
HumanoidTarget.BoneTransform thumbDistalBone = handTarget.fingers.thumb.distal.bone;
|
|
HumanoidTarget.BoneTransform indexDistalBone = handTarget.fingers.index.distal.bone;
|
|
// We need finger tips for pinch to work
|
|
if (thumbDistalBone.transform == null || indexDistalBone.transform == null)
|
|
return float.PositiveInfinity;
|
|
|
|
Vector3 thumbTip = GetTipPosition(thumbDistalBone, handTarget.outward);
|
|
Vector3 indexTip = GetTipPosition(indexDistalBone, handTarget.outward);
|
|
|
|
//Debug.DrawLine(thumbTip, indexTip, Color.yellow);
|
|
|
|
float distance = Vector3.Distance(thumbTip, indexTip);
|
|
return distance;
|
|
}
|
|
|
|
public static void Pinch(HandTarget handTarget, GameObject obj) {
|
|
Handle handle = obj.GetComponentInChildren<Handle>();
|
|
if (handle != null) {
|
|
if (handle.socket != null) {
|
|
Debug.Log("Grab from socket");
|
|
handle.socket.Release();
|
|
}
|
|
}
|
|
handTarget.pinchSocket.Attach(obj.transform);
|
|
handTarget.grabbedObject = obj;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Pinch Drop
|
|
public static void PinchDropCheck(HandTarget handTarget, Socket pinchSocket) {
|
|
bool isDropping = IsPinchDropping(handTarget);
|
|
bool pulledLoose = PulledLoose(handTarget, pinchSocket);
|
|
if (isDropping || pulledLoose)
|
|
PinchDrop(handTarget, pinchSocket);
|
|
}
|
|
|
|
protected static bool IsPinchDropping(HandTarget handTarget) {
|
|
float pinchDistance = GetPinchDistance(handTarget);
|
|
return pinchDistance > 0.06F;
|
|
}
|
|
|
|
protected static bool PulledLoose(HandTarget handTarget, Socket pinchSocket) {
|
|
float forearmStretch = Vector3.Distance(handTarget.hand.bone.transform.position, handTarget.forearm.bone.transform.position) - handTarget.forearm.bone.length;
|
|
if (forearmStretch > 0.15F)
|
|
return true;
|
|
|
|
if (pinchSocket.attachedTransform == null)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
protected static void PinchDrop(HandTarget handTarget, Socket pinchSocket) {
|
|
pinchSocket.Release();
|
|
handTarget.grabbedObject = null;
|
|
}
|
|
#endregion
|
|
}
|
|
} |