Files
vstyler/Assets/SteamVR_Unity_Toolkit/Scripts/SteamVR_InteractGrab.cs
T
2016-05-26 16:11:13 +02:00

294 lines
10 KiB
C#
Executable File

//====================================================================================
//
// Purpose: Provide ability to grab an interactable object when it is being touched
//
// This script must be attached to a Controller within the [CameraRig] Prefab
//
// The SteamVR_ControllerEvents and SteamVR_InteractTouch scripts must also be
// attached to the Controller
//
// Press the default 'Trigger' button on the controller to grab an object
// Released the default 'Trigger' button on the controller to drop an object
//
//====================================================================================
using UnityEngine;
using System.Collections;
public class SteamVR_InteractGrab : MonoBehaviour
{
public Rigidbody controllerAttachPoint = null;
public bool hideControllerOnGrab = false;
public float hideControllerDelay = 0f;
public event ObjectInteractEventHandler ControllerGrabInteractableObject;
public event ObjectInteractEventHandler ControllerUngrabInteractableObject;
Joint controllerAttachJoint;
GameObject grabbedObject = null;
SteamVR_InteractTouch interactTouch;
SteamVR_TrackedObject trackedController;
SteamVR_ControllerActions controllerActions;
private int grabEnabledState = 0;
public virtual void OnControllerGrabInteractableObject(ObjectInteractEventArgs e)
{
if (ControllerGrabInteractableObject != null)
ControllerGrabInteractableObject(this, e);
}
public virtual void OnControllerUngrabInteractableObject(ObjectInteractEventArgs e)
{
if (ControllerUngrabInteractableObject != null)
ControllerUngrabInteractableObject(this, e);
}
public void ForceRelease()
{
if (grabbedObject.GetComponent<SteamVR_InteractableObject>().AttatchIsTrackObject())
{
UngrabTrackedObject();
}
else
{
ReleaseObject((uint)trackedController.index, false);
}
}
private void Awake()
{
if (GetComponent<SteamVR_InteractTouch>() == null)
{
Debug.LogError("SteamVR_InteractGrab is required to be attached to a SteamVR Controller that has the SteamVR_InteractTouch script attached to it");
return;
}
interactTouch = GetComponent<SteamVR_InteractTouch>();
trackedController = GetComponent<SteamVR_TrackedObject>();
controllerActions = GetComponent<SteamVR_ControllerActions>();
}
private void Start()
{
//If no attach point has been specified then just use the tip of the controller
if (controllerAttachPoint == null)
{
controllerAttachPoint = transform.GetChild(0).Find("tip").GetChild(0).GetComponent<Rigidbody>();
}
if (GetComponent<SteamVR_ControllerEvents>() == null)
{
Debug.LogError("SteamVR_InteractGrab is required to be attached to a SteamVR Controller that has the SteamVR_ControllerEvents script attached to it");
return;
}
GetComponent<SteamVR_ControllerEvents>().AliasGrabOn += new ControllerClickedEventHandler(DoGrabObject);
GetComponent<SteamVR_ControllerEvents>().AliasGrabOff += new ControllerClickedEventHandler(DoReleaseObject);
}
private bool IsObjectGrabbable(GameObject obj)
{
return (interactTouch.IsObjectInteractable(obj) && obj.GetComponent<SteamVR_InteractableObject>().isGrabbable);
}
private bool IsObjectHoldOnGrab(GameObject obj)
{
return (obj && obj.GetComponent<SteamVR_InteractableObject>() && obj.GetComponent<SteamVR_InteractableObject>().holdButtonToGrab);
}
private void SnapObjectToGrabToController(GameObject obj)
{
//Pause collisions (if allowed on object) for a moment whilst sorting out position to prevent clipping issues
obj.GetComponent<SteamVR_InteractableObject>().PauseCollisions(0.2f);
SteamVR_InteractableObject.GrabSnapType grabType = obj.GetComponent<SteamVR_InteractableObject>().grabSnapType;
if (grabType == SteamVR_InteractableObject.GrabSnapType.Rotation_Snap)
{
// Identity Controller Rotation
this.transform.eulerAngles = new Vector3(0f, 270f, 0f);
obj.transform.eulerAngles = obj.GetComponent<SteamVR_InteractableObject>().snapToRotation;
}
if (grabType != SteamVR_InteractableObject.GrabSnapType.Precision_Snap)
{
obj.transform.position = controllerAttachPoint.transform.position + obj.GetComponent<SteamVR_InteractableObject>().snapToPosition;
}
CreateJoint(obj);
}
private void CreateJoint(GameObject obj)
{
if (obj.GetComponent<SteamVR_InteractableObject>().grabAttatchMechanic == SteamVR_InteractableObject.GrabAttatchType.Fixed_Joint)
{
controllerAttachJoint = obj.AddComponent<FixedJoint>();
}
else if (obj.GetComponent<SteamVR_InteractableObject>().grabAttatchMechanic == SteamVR_InteractableObject.GrabAttatchType.Spring_Joint)
{
SpringJoint tempSpringJoint = obj.AddComponent<SpringJoint>();
tempSpringJoint.spring = obj.GetComponent<SteamVR_InteractableObject>().springJointStrength;
tempSpringJoint.damper = obj.GetComponent<SteamVR_InteractableObject>().springJointDamper;
controllerAttachJoint = tempSpringJoint;
}
controllerAttachJoint.breakForce = obj.GetComponent<SteamVR_InteractableObject>().detatchThreshold;
controllerAttachJoint.connectedBody = controllerAttachPoint;
}
private Rigidbody ReleaseGrabbedObjectFromController(bool withThrow)
{
var jointGameObject = controllerAttachJoint.gameObject;
var rigidbody = jointGameObject.GetComponent<Rigidbody>();
if (withThrow)
{
Object.DestroyImmediate(controllerAttachJoint);
} else
{
Object.Destroy(controllerAttachJoint);
}
controllerAttachJoint = null;
return rigidbody;
}
private void ThrowReleasedObject(Rigidbody rb, uint controllerIndex)
{
var origin = trackedController.origin ? trackedController.origin : trackedController.transform.parent;
var device = SteamVR_Controller.Input((int)controllerIndex);
if (origin != null)
{
rb.velocity = origin.TransformVector(device.velocity);
rb.angularVelocity = origin.TransformVector(device.angularVelocity);
}
else
{
rb.velocity = device.velocity;
rb.angularVelocity = device.angularVelocity;
}
rb.maxAngularVelocity = rb.angularVelocity.magnitude;
}
private void GrabInteractedObject()
{
if (controllerAttachJoint == null && grabbedObject == null && IsObjectGrabbable(interactTouch.GetTouchedObject()))
{
InitGrabbedObject();
SnapObjectToGrabToController(grabbedObject);
}
}
private void GrabTrackedObject()
{
if (grabbedObject == null && IsObjectGrabbable(interactTouch.GetTouchedObject())) {
InitGrabbedObject();
}
}
private void InitGrabbedObject()
{
grabbedObject = interactTouch.GetTouchedObject();
OnControllerGrabInteractableObject(interactTouch.SetControllerInteractEvent(grabbedObject));
grabbedObject.GetComponent<SteamVR_InteractableObject>().Grabbed(this.gameObject);
if (grabbedObject)
{
grabbedObject.GetComponent<SteamVR_InteractableObject>().ToggleHighlight(false);
}
if (hideControllerOnGrab)
{
Invoke("HideController", hideControllerDelay);
}
}
private void HideController()
{
if(grabbedObject != null)
{
controllerActions.ToggleControllerModel(false);
}
}
private void UngrabInteractedObject(uint controllerIndex, bool withThrow)
{
if (grabbedObject != null && controllerAttachJoint != null)
{
Rigidbody releasedObjectRigidBody = ReleaseGrabbedObjectFromController(withThrow);
if (withThrow)
{
ThrowReleasedObject(releasedObjectRigidBody, controllerIndex);
}
InitUngrabbedObject();
}
}
private void UngrabTrackedObject()
{
if (grabbedObject != null)
{
InitUngrabbedObject();
}
}
private void InitUngrabbedObject()
{
OnControllerUngrabInteractableObject(interactTouch.SetControllerInteractEvent(grabbedObject));
grabbedObject.GetComponent<SteamVR_InteractableObject>().Ungrabbed(this.gameObject);
if (hideControllerOnGrab)
{
controllerActions.ToggleControllerModel(true);
}
grabbedObject.GetComponent<SteamVR_InteractableObject>().ToggleHighlight(false);
grabbedObject = null;
}
private void ReleaseObject(uint controllerIndex, bool withThrow)
{
UngrabInteractedObject(controllerIndex, withThrow);
grabEnabledState = 0;
}
private bool IsValidGrab()
{
GameObject obj = interactTouch.GetTouchedObject();
return (obj != null && interactTouch.IsObjectInteractable(obj));
}
private void DoGrabObject(object sender, ControllerClickedEventArgs e)
{
if (IsValidGrab())
{
if (interactTouch.GetTouchedObject().GetComponent<SteamVR_InteractableObject>().AttatchIsTrackObject())
{
GrabTrackedObject();
} else
{
GrabInteractedObject();
}
if(!IsObjectHoldOnGrab(interactTouch.GetTouchedObject()))
{
grabEnabledState++;
}
}
}
private void DoReleaseObject(object sender, ControllerClickedEventArgs e)
{
if (IsObjectHoldOnGrab(grabbedObject) || grabEnabledState >= 2)
{
if (grabbedObject.GetComponent<SteamVR_InteractableObject>().AttatchIsTrackObject())
{
UngrabTrackedObject();
}
else
{
ReleaseObject(e.controllerIndex, true);
}
}
}
}