IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
ComplexThrowable.cs
1 //======= Copyright (c) Valve Corporation, All rights reserved. ===============
2 //
3 // Purpose: Throwable that uses physics joints to attach instead of just
4 // parenting
5 //
6 //=============================================================================
7 
8 using UnityEngine;
9 using System.Collections.Generic;
10 
11 namespace Valve.VR.InteractionSystem
12 {
13  //-------------------------------------------------------------------------
14  [RequireComponent( typeof( Interactable ) )]
15  public class ComplexThrowable : MonoBehaviour
16  {
17  public enum AttachMode
18  {
19  FixedJoint,
20  Force,
21  }
22 
23  public float attachForce = 800.0f;
24  public float attachForceDamper = 25.0f;
25 
26  public AttachMode attachMode = AttachMode.FixedJoint;
27 
28  [EnumFlags]
29  public Hand.AttachmentFlags attachmentFlags = 0;
30 
31  private List<Hand> holdingHands = new List<Hand>();
32  private List<Rigidbody> holdingBodies = new List<Rigidbody>();
33  private List<Vector3> holdingPoints = new List<Vector3>();
34 
35  private List<Rigidbody> rigidBodies = new List<Rigidbody>();
36 
37  //-------------------------------------------------
38  void Awake()
39  {
40  GetComponentsInChildren<Rigidbody>( rigidBodies );
41  }
42 
43 
44  //-------------------------------------------------
45  void Update()
46  {
47  for ( int i = 0; i < holdingHands.Count; i++ )
48  {
49  if ( !holdingHands[i].GetStandardInteractionButton() )
50  {
51  PhysicsDetach( holdingHands[i] );
52  }
53  }
54  }
55 
56 
57  //-------------------------------------------------
58  private void OnHandHoverBegin( Hand hand )
59  {
60  if ( holdingHands.IndexOf( hand ) == -1 )
61  {
62  if ( hand.controller != null )
63  {
64  hand.controller.TriggerHapticPulse( 800 );
65  }
66  }
67  }
68 
69 
70  //-------------------------------------------------
71  private void OnHandHoverEnd( Hand hand )
72  {
73  if ( holdingHands.IndexOf( hand ) == -1 )
74  {
75  if ( hand.controller != null )
76  {
77  hand.controller.TriggerHapticPulse( 500 );
78  }
79  }
80  }
81 
82 
83  //-------------------------------------------------
84  private void HandHoverUpdate( Hand hand )
85  {
86  if ( hand.GetStandardInteractionButtonDown() )
87  {
88  PhysicsAttach( hand );
89  }
90  }
91 
92 
93  //-------------------------------------------------
94  private void PhysicsAttach( Hand hand )
95  {
96  PhysicsDetach( hand );
97 
98  Rigidbody holdingBody = null;
99  Vector3 holdingPoint = Vector3.zero;
100 
101  // The hand should grab onto the nearest rigid body
102  float closestDistance = float.MaxValue;
103  for ( int i = 0; i < rigidBodies.Count; i++ )
104  {
105  float distance = Vector3.Distance( rigidBodies[i].worldCenterOfMass, hand.transform.position );
106  if ( distance < closestDistance )
107  {
108  holdingBody = rigidBodies[i];
109  closestDistance = distance;
110  }
111  }
112 
113  // Couldn't grab onto a body
114  if ( holdingBody == null )
115  return;
116 
117  // Create a fixed joint from the hand to the holding body
118  if ( attachMode == AttachMode.FixedJoint )
119  {
120  Rigidbody handRigidbody = Util.FindOrAddComponent<Rigidbody>( hand.gameObject );
121  handRigidbody.isKinematic = true;
122 
123  FixedJoint handJoint = hand.gameObject.AddComponent<FixedJoint>();
124  handJoint.connectedBody = holdingBody;
125  }
126 
127  // Don't let the hand interact with other things while it's holding us
128  hand.HoverLock( null );
129 
130  // Affix this point
131  Vector3 offset = hand.transform.position - holdingBody.worldCenterOfMass;
132  offset = Mathf.Min( offset.magnitude, 1.0f ) * offset.normalized;
133  holdingPoint = holdingBody.transform.InverseTransformPoint( holdingBody.worldCenterOfMass + offset );
134 
135  hand.AttachObject( this.gameObject, attachmentFlags );
136 
137  // Update holding list
138  holdingHands.Add( hand );
139  holdingBodies.Add( holdingBody );
140  holdingPoints.Add( holdingPoint );
141  }
142 
143 
144  //-------------------------------------------------
145  private bool PhysicsDetach( Hand hand )
146  {
147  int i = holdingHands.IndexOf( hand );
148 
149  if ( i != -1 )
150  {
151  // Detach this object from the hand
152  holdingHands[i].DetachObject( this.gameObject, false );
153 
154  // Allow the hand to do other things
155  holdingHands[i].HoverUnlock( null );
156 
157  // Delete any existing joints from the hand
158  if ( attachMode == AttachMode.FixedJoint )
159  {
160  Destroy( holdingHands[i].GetComponent<FixedJoint>() );
161  }
162 
163  Util.FastRemove( holdingHands, i );
164  Util.FastRemove( holdingBodies, i );
165  Util.FastRemove( holdingPoints, i );
166 
167  return true;
168  }
169 
170  return false;
171  }
172 
173 
174  //-------------------------------------------------
175  void FixedUpdate()
176  {
177  if ( attachMode == AttachMode.Force )
178  {
179  for ( int i = 0; i < holdingHands.Count; i++ )
180  {
181  Vector3 targetPoint = holdingBodies[i].transform.TransformPoint( holdingPoints[i] );
182  Vector3 vdisplacement = holdingHands[i].transform.position - targetPoint;
183 
184  holdingBodies[i].AddForceAtPosition( attachForce * vdisplacement, targetPoint, ForceMode.Acceleration );
185  holdingBodies[i].AddForceAtPosition( -attachForceDamper * holdingBodies[i].GetPointVelocity( targetPoint ), targetPoint, ForceMode.Acceleration );
186  }
187  }
188  }
189  }
190 }