using UnityEngine;
using System.Collections;
[RequireComponent(typeof(SteamVR_TrackedObject))]
public class Hand : MonoBehaviour {
///
/// The point at which to attach the object we pick up on the hands.
///
public Rigidbody AttachPoint;
///
/// When true, the object will be picked up based on where the hand
/// touched the object. When false, the object will attach to the contact point
/// assigned.
///
public bool IgnoreContactPoint = false;
///
/// The thickness of the teleporting laser.
///
public float LaserThickness = 0.002f;
///
/// The color of the laser when the touchpad is touched.
///
public Color TeleportStartLaserColor = Color.blue;
///
/// The color of the laser when the touchpad is pressed.
///
public Color TeleportLaserColor = Color.red;
///
/// The maximum distance the player can teleport.
///
public float MaxTeleportDistance = 100.0f;
///
/// Manages the state of the hand.
///
private enum State
{
EMPTY,
TOUCHING,
HOLDING
};
///
/// The hands current state.
///
private State mHandState = State.EMPTY;
///
/// Our actual controller device. This is used to handle button presses, velocities, etc.
///
private SteamVR_Controller.Device mControllerDevice;
///
/// The tracked object representing our controller. This is used to get the
/// controller device.
///
private SteamVR_TrackedObject mTrackedObj;
///
/// The object currently being held.
///
private Rigidbody mHeldObject;
///
/// A temporary joint connect the object we are holding to our hand.
///
private FixedJoint mTempJoint;
///
/// The laser's physical object (just a block).
///
private GameObject mLaser;
///
/// Initializes a hand's starting properties.
///
void Start () {
mHandState = State.EMPTY;
mTrackedObj = GetComponent();
mControllerDevice = SteamVR_Controller.Input((int)mTrackedObj.index);
mLaser = GameObject.CreatePrimitive(PrimitiveType.Cube);
mLaser.transform.parent = this.transform;
mLaser.transform.localScale = new Vector3(0f, 0f, 0f);
mLaser.transform.localPosition = new Vector3(0.0f, 0.0f, 0f);
mLaser.GetComponent().material = new Material(Shader.Find("Unlit/Color"));
mLaser.GetComponent().material.SetColor("_Color", TeleportStartLaserColor);
mLaser.GetComponent().enabled = false;
}
///
/// Update called in sync with physics.
///
void FixedUpdate () {
updateHand();
updateLaser();
}
///
/// Throws the object the hand was holding.
///
private void throwObject()
{
var origin = mTrackedObj.origin ? mTrackedObj.origin : mTrackedObj.transform.parent;
if (origin != null)
{
mHeldObject.velocity = origin.TransformVector(mControllerDevice.velocity);
mHeldObject.angularVelocity = origin.TransformVector(mControllerDevice.angularVelocity);
}
else
{
mHeldObject.velocity = mControllerDevice.velocity;
mHeldObject.angularVelocity = mControllerDevice.angularVelocity;
}
mHeldObject.maxAngularVelocity = mHeldObject.angularVelocity.magnitude;
}
///
/// Updates the hand based on its state.
///
private void updateHand()
{
switch (mHandState)
{
case State.TOUCHING:
if (mTempJoint == null && mControllerDevice.GetPress(SteamVR_Controller.ButtonMask.Grip))
{
mHeldObject.velocity = Vector3.zero;
mTempJoint = mHeldObject.gameObject.AddComponent();
if (IgnoreContactPoint)
{
mHeldObject.transform.position = AttachPoint.transform.position;
}
mTempJoint.connectedBody = AttachPoint;
mHandState = State.HOLDING;
}
break;
case State.HOLDING:
if (mTempJoint != null && mControllerDevice.GetPressUp(SteamVR_Controller.ButtonMask.Grip))
{
Object.DestroyImmediate(mTempJoint);
mTempJoint = null;
throwObject();
mHandState = State.EMPTY;
}
break;
}
}
///
/// Updates the teleport laser in each hand.
///
private void updateLaser()
{
if (mControllerDevice != null)
{
Ray raycast = new Ray(transform.position, transform.forward);
RaycastHit hitInfo;
bool hit = Physics.Raycast(raycast, out hitInfo, MaxTeleportDistance);
float distance = hit ? hitInfo.distance : MaxTeleportDistance;
if (mControllerDevice.GetTouch(SteamVR_Controller.ButtonMask.Touchpad))
{
mLaser.transform.localScale = new Vector3(LaserThickness, LaserThickness, distance);
mLaser.transform.localPosition = new Vector3(0f, 0f, distance / 2f);
}
else
{
mLaser.transform.localScale = new Vector3(0f, 0f, 0f);
mLaser.transform.localPosition = new Vector3(0f, 0f, 0f);
}
if (mControllerDevice.GetPress(SteamVR_Controller.ButtonMask.Touchpad))
{
if (hit && hitInfo.collider.gameObject.layer == LayerMask.NameToLayer("teleportable"))
{
mLaser.GetComponent().material.SetColor("_Color", TeleportLaserColor);
}
else
{
mLaser.GetComponent().material.SetColor("_Color", TeleportStartLaserColor);
}
}
if (mControllerDevice.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad))
{
if (hit && hitInfo.collider.gameObject.layer == LayerMask.NameToLayer("teleportable"))
{
float originalY = transform.parent.position.y;
transform.parent.position = transform.parent.position + raycast.direction * distance;
transform.parent.position = new Vector3(transform.parent.position.x, originalY, transform.parent.position.z);
}
mLaser.GetComponent().material.SetColor("_Color", TeleportStartLaserColor);
}
}
}
///
/// Checks for a collision with the hand and
/// changes the state based on it, also storing
/// the object we touched.
///
/// The object we touched.
void OnTriggerEnter(Collider collider)
{
if (mHandState == State.EMPTY)
{
GameObject temp = collider.gameObject;
while (temp.GetComponent() == null && temp.transform.parent != null)
{
temp = temp.transform.parent.gameObject;
}
if (temp != null && temp.layer == LayerMask.NameToLayer("grabbable") &&
temp.GetComponent() != null)
{
mHeldObject = temp.GetComponent();
mHandState = State.TOUCHING;
mControllerDevice.TriggerHapticPulse(2000);
}
}
}
///
/// When we are no longer touching an object or holding
/// and object, clean up the current state and remove the object
/// we let go of/stopped touching.
///
/// The object we are no longer touching.
void OnTriggerExit(Collider collider)
{
if (mHandState != State.HOLDING)
{
if (collider.gameObject.layer == LayerMask.NameToLayer("grabbable"))
{
mHeldObject = null;
mHandState = State.EMPTY;
}
}
}
}