Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
12 KiB

  1. // Chest|Controls3D|100030
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Transforms a game object into a chest with a lid. The direction can be auto-detected with very high reliability or set manually.
  7. /// </summary>
  8. /// <remarks>
  9. /// The script will instantiate the required Rigidbody, Interactable and HingeJoint components automatically in case they do not exist yet. It will expect three distinct game objects: a body, a lid and a handle. These should be independent and not children of each other.
  10. /// </remarks>
  11. /// <example>
  12. /// `VRTK/Examples/025_Controls_Overview` shows a chest that can be open and closed, it also displays the current opening angle of the chest.
  13. /// </example>
  14. [AddComponentMenu("VRTK/Scripts/Controls/3D/VRTK_Chest")]
  15. [System.Obsolete("`VRTK.VRTK_Chest` has been deprecated and can be recreated with `VRTK.Controllables.PhysicsBased.VRTK_PhysicsRotator`. This script will be removed in a future version of VRTK.")]
  16. public class VRTK_Chest : VRTK_Control
  17. {
  18. [Tooltip("The axis on which the chest should open. All other axis will be frozen.")]
  19. public Direction direction = Direction.autodetect;
  20. [Tooltip("The game object for the lid.")]
  21. public GameObject lid;
  22. [Tooltip("The game object for the body.")]
  23. public GameObject body;
  24. [Tooltip("The game object for the handle.")]
  25. public GameObject handle;
  26. [Tooltip("The parent game object for the chest content elements.")]
  27. public GameObject content;
  28. [Tooltip("Makes the content invisible while the chest is closed.")]
  29. public bool hideContent = true;
  30. [Tooltip("The maximum opening angle of the chest.")]
  31. public float maxAngle = 160f;
  32. protected float minAngle = 0f;
  33. protected float stepSize = 1f;
  34. protected Rigidbody bodyRigidbody;
  35. protected Rigidbody handleRigidbody;
  36. protected FixedJoint handleJoint;
  37. protected Rigidbody lidRigidbody;
  38. protected HingeJoint lidJoint;
  39. protected bool lidJointCreated;
  40. protected Direction finalDirection;
  41. protected float subDirection = 1; // positive or negative can be determined automatically since handle dictates that
  42. protected override void OnDrawGizmos()
  43. {
  44. base.OnDrawGizmos();
  45. if (!enabled || !setupSuccessful)
  46. {
  47. return;
  48. }
  49. // show opening direction
  50. Bounds bounds;
  51. if (handle)
  52. {
  53. bounds = VRTK_SharedMethods.GetBounds(handle.transform, handle.transform);
  54. }
  55. else
  56. {
  57. bounds = VRTK_SharedMethods.GetBounds(lid.transform, lid.transform);
  58. }
  59. float length = bounds.extents.y * 5f;
  60. Vector3 point = bounds.center + new Vector3(0, length, 0);
  61. switch (finalDirection)
  62. {
  63. case Direction.x:
  64. point += transform.right.normalized * (length / 2f) * subDirection;
  65. break;
  66. case Direction.y:
  67. point += transform.up.normalized * (length / 2f) * subDirection;
  68. break;
  69. case Direction.z:
  70. point += transform.forward.normalized * (length / 2f) * subDirection;
  71. break;
  72. }
  73. Gizmos.DrawLine(bounds.center + new Vector3(0, bounds.extents.y, 0), point);
  74. Gizmos.DrawSphere(point, length / 8f);
  75. }
  76. protected override void InitRequiredComponents()
  77. {
  78. InitBody();
  79. InitLid();
  80. InitHandle();
  81. SetContent(content, hideContent);
  82. }
  83. protected override bool DetectSetup()
  84. {
  85. if (lid == null || body == null)
  86. {
  87. return false;
  88. }
  89. finalDirection = (direction == Direction.autodetect) ? DetectDirection() : direction;
  90. if (finalDirection == Direction.autodetect)
  91. {
  92. return false;
  93. }
  94. Bounds lidBounds = VRTK_SharedMethods.GetBounds(lid.transform, transform);
  95. // determin sub-direction depending on handle
  96. if (handle)
  97. {
  98. Bounds handleBounds = VRTK_SharedMethods.GetBounds(handle.transform, transform);
  99. switch (finalDirection)
  100. {
  101. case Direction.x:
  102. subDirection = (handleBounds.center.x > lidBounds.center.x) ? -1 : 1;
  103. break;
  104. case Direction.y:
  105. subDirection = (handleBounds.center.y > lidBounds.center.y) ? -1 : 1;
  106. break;
  107. case Direction.z:
  108. subDirection = (handleBounds.center.z > lidBounds.center.z) ? -1 : 1;
  109. break;
  110. }
  111. // handle should be outside lid hierarchy, otherwise anchor-by-bounds calculation is off
  112. if (handle.transform.IsChildOf(lid.transform))
  113. {
  114. return false;
  115. }
  116. }
  117. else
  118. {
  119. subDirection = -1;
  120. }
  121. if (lidJointCreated)
  122. {
  123. lidJoint.useLimits = true;
  124. lidJoint.enableCollision = true;
  125. JointLimits limits = lidJoint.limits;
  126. switch (finalDirection)
  127. {
  128. case Direction.x:
  129. lidJoint.anchor = new Vector3(subDirection * lidBounds.extents.x, 0, 0);
  130. lidJoint.axis = new Vector3(0, 0, 1);
  131. if (subDirection > 0)
  132. {
  133. limits.min = -maxAngle;
  134. limits.max = minAngle;
  135. }
  136. else
  137. {
  138. limits.min = minAngle;
  139. limits.max = maxAngle;
  140. }
  141. break;
  142. case Direction.y:
  143. lidJoint.anchor = new Vector3(0, subDirection * lidBounds.extents.y, 0);
  144. lidJoint.axis = new Vector3(0, 1, 0);
  145. if (subDirection > 0)
  146. {
  147. limits.min = -maxAngle;
  148. limits.max = minAngle;
  149. }
  150. else
  151. {
  152. limits.min = minAngle;
  153. limits.max = maxAngle;
  154. }
  155. break;
  156. case Direction.z:
  157. lidJoint.anchor = new Vector3(0, 0, subDirection * lidBounds.extents.z);
  158. lidJoint.axis = new Vector3(1, 0, 0);
  159. if (subDirection < 0)
  160. {
  161. limits.min = -maxAngle;
  162. limits.max = minAngle;
  163. }
  164. else
  165. {
  166. limits.min = minAngle;
  167. limits.max = maxAngle;
  168. }
  169. break;
  170. }
  171. lidJoint.limits = limits;
  172. }
  173. return true;
  174. }
  175. protected override ControlValueRange RegisterValueRange()
  176. {
  177. return new ControlValueRange()
  178. {
  179. controlMin = lidJoint.limits.min,
  180. controlMax = lidJoint.limits.max
  181. };
  182. }
  183. protected override void HandleUpdate()
  184. {
  185. value = CalculateValue();
  186. }
  187. protected virtual Direction DetectDirection()
  188. {
  189. Direction returnDirection = Direction.autodetect;
  190. if (!handle)
  191. {
  192. return returnDirection;
  193. }
  194. Bounds handleBounds = VRTK_SharedMethods.GetBounds(handle.transform, transform);
  195. Bounds lidBounds = VRTK_SharedMethods.GetBounds(lid.transform, transform);
  196. float lengthX = Mathf.Abs(handleBounds.center.x - (lidBounds.center.x + lidBounds.extents.x));
  197. float lengthZ = Mathf.Abs(handleBounds.center.z - (lidBounds.center.z + lidBounds.extents.z));
  198. float lengthNegX = Mathf.Abs(handleBounds.center.x - (lidBounds.center.x - lidBounds.extents.x));
  199. float lengthNegZ = Mathf.Abs(handleBounds.center.z - (lidBounds.center.z - lidBounds.extents.z));
  200. if (VRTK_SharedMethods.IsLowest(lengthX, new float[] { lengthZ, lengthNegX, lengthNegZ }))
  201. {
  202. returnDirection = Direction.x;
  203. }
  204. else if (VRTK_SharedMethods.IsLowest(lengthNegX, new float[] { lengthX, lengthZ, lengthNegZ }))
  205. {
  206. returnDirection = Direction.x;
  207. }
  208. else if (VRTK_SharedMethods.IsLowest(lengthZ, new float[] { lengthX, lengthNegX, lengthNegZ }))
  209. {
  210. returnDirection = Direction.z;
  211. }
  212. else if (VRTK_SharedMethods.IsLowest(lengthNegZ, new float[] { lengthX, lengthZ, lengthNegX }))
  213. {
  214. returnDirection = Direction.z;
  215. }
  216. return returnDirection;
  217. }
  218. protected virtual void InitBody()
  219. {
  220. bodyRigidbody = body.GetComponent<Rigidbody>();
  221. if (bodyRigidbody == null)
  222. {
  223. bodyRigidbody = body.AddComponent<Rigidbody>();
  224. bodyRigidbody.isKinematic = true; // otherwise body moves/falls over when lid is moved or fully open
  225. }
  226. }
  227. protected virtual void InitLid()
  228. {
  229. lidRigidbody = lid.GetComponent<Rigidbody>();
  230. if (lidRigidbody == null)
  231. {
  232. lidRigidbody = lid.AddComponent<Rigidbody>();
  233. }
  234. lidJoint = lid.GetComponent<HingeJoint>();
  235. if (lidJoint == null)
  236. {
  237. lidJoint = lid.AddComponent<HingeJoint>();
  238. lidJointCreated = true;
  239. }
  240. lidJoint.connectedBody = bodyRigidbody;
  241. if (!handle)
  242. {
  243. CreateInteractableObject(lid);
  244. }
  245. }
  246. protected virtual void InitHandle()
  247. {
  248. if (!handle)
  249. {
  250. return;
  251. }
  252. handleRigidbody = handle.GetComponent<Rigidbody>();
  253. if (handleRigidbody == null)
  254. {
  255. handleRigidbody = handle.AddComponent<Rigidbody>();
  256. }
  257. handleRigidbody.isKinematic = false;
  258. handleRigidbody.useGravity = false;
  259. handleJoint = handle.GetComponent<FixedJoint>();
  260. if (handleJoint == null)
  261. {
  262. handleJoint = handle.AddComponent<FixedJoint>();
  263. handleJoint.connectedBody = lidRigidbody;
  264. }
  265. CreateInteractableObject(handle);
  266. }
  267. protected virtual void CreateInteractableObject(GameObject targetGameObject)
  268. {
  269. VRTK_InteractableObject targetInteractableObject = targetGameObject.GetComponent<VRTK_InteractableObject>();
  270. if (targetInteractableObject == null)
  271. {
  272. targetInteractableObject = targetGameObject.AddComponent<VRTK_InteractableObject>();
  273. }
  274. targetInteractableObject.isGrabbable = true;
  275. targetInteractableObject.grabAttachMechanicScript = gameObject.AddComponent<GrabAttachMechanics.VRTK_TrackObjectGrabAttach>();
  276. targetInteractableObject.secondaryGrabActionScript = gameObject.AddComponent<SecondaryControllerGrabActions.VRTK_SwapControllerGrabAction>();
  277. targetInteractableObject.grabAttachMechanicScript.precisionGrab = true;
  278. targetInteractableObject.stayGrabbedOnTeleport = false;
  279. }
  280. protected virtual float CalculateValue()
  281. {
  282. return (Mathf.Round((minAngle + Mathf.Clamp01(Mathf.Abs(lidJoint.angle / (lidJoint.limits.max - lidJoint.limits.min))) * (maxAngle - minAngle)) / stepSize) * stepSize);
  283. }
  284. }
  285. }