ComplexThrowable.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. using UnityEngine;
  8. using System.Collections.Generic;
  9. namespace Valve.VR.InteractionSystem
  10. {
  11. //-------------------------------------------------------------------------
  12. [RequireComponent( typeof( Interactable ) )]
  13. public class ComplexThrowable : MonoBehaviour
  14. {
  15. public enum AttachMode
  16. {
  17. FixedJoint,
  18. Force,
  19. }
  20. public float attachForce = 800.0f;
  21. public float attachForceDamper = 25.0f;
  22. public AttachMode attachMode = AttachMode.FixedJoint;
  23. [EnumFlags]
  24. public Hand.AttachmentFlags attachmentFlags = 0;
  25. private List<Hand> holdingHands = new List<Hand>();
  26. private List<Rigidbody> holdingBodies = new List<Rigidbody>();
  27. private List<Vector3> holdingPoints = new List<Vector3>();
  28. private List<Rigidbody> rigidBodies = new List<Rigidbody>();
  29. //-------------------------------------------------
  30. void Awake()
  31. {
  32. GetComponentsInChildren<Rigidbody>( rigidBodies );
  33. }
  34. //-------------------------------------------------
  35. void Update()
  36. {
  37. for ( int i = 0; i < holdingHands.Count; i++ )
  38. {
  39. if (holdingHands[i].IsGrabEnding(this.gameObject))
  40. {
  41. PhysicsDetach( holdingHands[i] );
  42. }
  43. }
  44. }
  45. //-------------------------------------------------
  46. private void OnHandHoverBegin( Hand hand )
  47. {
  48. if ( holdingHands.IndexOf( hand ) == -1 )
  49. {
  50. if ( hand.isActive )
  51. {
  52. hand.TriggerHapticPulse( 800 );
  53. }
  54. }
  55. }
  56. //-------------------------------------------------
  57. private void OnHandHoverEnd( Hand hand )
  58. {
  59. if ( holdingHands.IndexOf( hand ) == -1 )
  60. {
  61. if (hand.isActive)
  62. {
  63. hand.TriggerHapticPulse( 500 );
  64. }
  65. }
  66. }
  67. //-------------------------------------------------
  68. private void HandHoverUpdate( Hand hand )
  69. {
  70. GrabTypes startingGrabType = hand.GetGrabStarting();
  71. if (startingGrabType != GrabTypes.None)
  72. {
  73. PhysicsAttach( hand, startingGrabType );
  74. }
  75. }
  76. //-------------------------------------------------
  77. private void PhysicsAttach( Hand hand, GrabTypes startingGrabType )
  78. {
  79. PhysicsDetach( hand );
  80. Rigidbody holdingBody = null;
  81. Vector3 holdingPoint = Vector3.zero;
  82. // The hand should grab onto the nearest rigid body
  83. float closestDistance = float.MaxValue;
  84. for ( int i = 0; i < rigidBodies.Count; i++ )
  85. {
  86. float distance = Vector3.Distance( rigidBodies[i].worldCenterOfMass, hand.transform.position );
  87. if ( distance < closestDistance )
  88. {
  89. holdingBody = rigidBodies[i];
  90. closestDistance = distance;
  91. }
  92. }
  93. // Couldn't grab onto a body
  94. if ( holdingBody == null )
  95. return;
  96. // Create a fixed joint from the hand to the holding body
  97. if ( attachMode == AttachMode.FixedJoint )
  98. {
  99. Rigidbody handRigidbody = Util.FindOrAddComponent<Rigidbody>( hand.gameObject );
  100. handRigidbody.isKinematic = true;
  101. FixedJoint handJoint = hand.gameObject.AddComponent<FixedJoint>();
  102. handJoint.connectedBody = holdingBody;
  103. }
  104. // Don't let the hand interact with other things while it's holding us
  105. hand.HoverLock( null );
  106. // Affix this point
  107. Vector3 offset = hand.transform.position - holdingBody.worldCenterOfMass;
  108. offset = Mathf.Min( offset.magnitude, 1.0f ) * offset.normalized;
  109. holdingPoint = holdingBody.transform.InverseTransformPoint( holdingBody.worldCenterOfMass + offset );
  110. hand.AttachObject( this.gameObject, startingGrabType, attachmentFlags );
  111. // Update holding list
  112. holdingHands.Add( hand );
  113. holdingBodies.Add( holdingBody );
  114. holdingPoints.Add( holdingPoint );
  115. }
  116. //-------------------------------------------------
  117. private bool PhysicsDetach( Hand hand )
  118. {
  119. int i = holdingHands.IndexOf( hand );
  120. if ( i != -1 )
  121. {
  122. // Detach this object from the hand
  123. holdingHands[i].DetachObject( this.gameObject, false );
  124. // Allow the hand to do other things
  125. holdingHands[i].HoverUnlock( null );
  126. // Delete any existing joints from the hand
  127. if ( attachMode == AttachMode.FixedJoint )
  128. {
  129. Destroy( holdingHands[i].GetComponent<FixedJoint>() );
  130. }
  131. Util.FastRemove( holdingHands, i );
  132. Util.FastRemove( holdingBodies, i );
  133. Util.FastRemove( holdingPoints, i );
  134. return true;
  135. }
  136. return false;
  137. }
  138. //-------------------------------------------------
  139. void FixedUpdate()
  140. {
  141. if ( attachMode == AttachMode.Force )
  142. {
  143. for ( int i = 0; i < holdingHands.Count; i++ )
  144. {
  145. Vector3 targetPoint = holdingBodies[i].transform.TransformPoint( holdingPoints[i] );
  146. Vector3 vdisplacement = holdingHands[i].transform.position - targetPoint;
  147. holdingBodies[i].AddForceAtPosition( attachForce * vdisplacement, targetPoint, ForceMode.Acceleration );
  148. holdingBodies[i].AddForceAtPosition( -attachForceDamper * holdingBodies[i].GetPointVelocity( targetPoint ), targetPoint, ForceMode.Acceleration );
  149. }
  150. }
  151. }
  152. }
  153. }