294 lines
10 KiB
C#
Executable File
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);
|
|
}
|
|
}
|
|
}
|
|
}
|