ZEDXRGrabber.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /// <summary>
  5. /// Checks for trigger colliders with IXRHoverable components added, and lets user click or grab them if they
  6. /// have IXRClickable or IXRGrabbable scripts on them.
  7. /// </summary>
  8. [RequireComponent(typeof(Collider))]
  9. public class ZEDXRGrabber : MonoBehaviour
  10. {
  11. public ZEDControllerTracker_DemoInputs zedController;
  12. private IXRHoverable hoveringObject;
  13. private IXRGrabbable grabbingObject;
  14. private bool isGrabbing
  15. {
  16. get
  17. {
  18. return grabbingObject != null;
  19. }
  20. }
  21. private List<IXRHoverable> collidingHoverables = new List<IXRHoverable>();
  22. private List<IXRClickable> collidingClickables = new List<IXRClickable>();
  23. private List<IXRGrabbable> collidingGrabbables = new List<IXRGrabbable>();
  24. [Space(5)]
  25. [Header("Sounds")]
  26. public AudioClip clickSound;
  27. public AudioClip grabStartSound;
  28. public AudioClip grabEndSound;
  29. public AudioClip hoverStartSound;
  30. // Use this for initialization
  31. void Start()
  32. {
  33. if (!zedController) zedController = GetComponentInParent<ZEDControllerTracker_DemoInputs>();
  34. }
  35. // Update is called once per frame
  36. void Update()
  37. {
  38. CheckListElementsForValidity();
  39. CheckHovers();
  40. }
  41. private void OnTriggerEnter(Collider collision)
  42. {
  43. IXRHoverable newhoverable = collision.gameObject.GetComponent<IXRHoverable>();
  44. if (newhoverable != null && !collidingHoverables.Contains(newhoverable)) collidingHoverables.Add(newhoverable);
  45. IXRClickable newclickable = collision.gameObject.GetComponent<IXRClickable>();
  46. if (newclickable != null && !collidingClickables.Contains(newclickable)) collidingClickables.Add(newclickable);
  47. IXRGrabbable newgrabbable = collision.gameObject.GetComponent<IXRGrabbable>();
  48. if (newgrabbable != null && !collidingGrabbables.Contains(newgrabbable)) collidingGrabbables.Add(newgrabbable);
  49. }
  50. private void OnTriggerExit(Collider collision)
  51. {
  52. IXRHoverable newhoverable = collision.gameObject.GetComponent<IXRHoverable>();
  53. if (newhoverable != null && collidingHoverables.Contains(newhoverable)) collidingHoverables.Remove(newhoverable);
  54. IXRClickable newclickable = collision.gameObject.GetComponent<IXRClickable>();
  55. if (newclickable != null && collidingClickables.Contains(newclickable)) collidingClickables.Remove(newclickable);
  56. IXRGrabbable newgrabbable = collision.gameObject.GetComponent<IXRGrabbable>();
  57. if (newgrabbable != null && collidingGrabbables.Contains(newgrabbable)) collidingGrabbables.Remove(newgrabbable);
  58. }
  59. private void CheckHovers()
  60. {
  61. //If we're grabbing something, we shouldn't be hovering over anything.
  62. if(grabbingObject != null)
  63. {
  64. if(hoveringObject != null)
  65. {
  66. if(!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd();
  67. hoveringObject = null;
  68. }
  69. return;
  70. }
  71. float nearestdist = Mathf.Infinity;
  72. IXRHoverable newhover = null;
  73. foreach(IXRHoverable hover in collidingHoverables)
  74. {
  75. float dist = Vector3.Distance(transform.position, hover.GetTransform().position);
  76. if (dist < nearestdist) newhover = hover;
  77. }
  78. if(hoveringObject != newhover)
  79. {
  80. if (hoveringObject != null && !hoveringObject.Equals(null))
  81. {
  82. hoveringObject.OnHoverEnd();
  83. }
  84. if(newhover != null)
  85. {
  86. PlaySoundIfValid(hoverStartSound);
  87. newhover.OnHoverStart();
  88. }
  89. hoveringObject = newhover;
  90. }
  91. }
  92. /// <summary>
  93. /// Checks the interface lists to make sure that they all still exist. Otherwise, if something is destroyed
  94. /// or disabled while still in range, we'll still try to interact with it.
  95. /// </summary>
  96. private void CheckListElementsForValidity()
  97. {
  98. List<IXRHoverable> toremove = new List<IXRHoverable>();
  99. foreach(IXRHoverable hoverable in collidingHoverables)
  100. {
  101. if(hoverable.Equals(null))
  102. {
  103. toremove.Add(hoverable);
  104. continue;
  105. }
  106. Collider col = hoverable.GetTransform().GetComponent<Collider>();
  107. if(col == null || col.enabled == false)
  108. {
  109. toremove.Add(hoverable);
  110. }
  111. }
  112. foreach (IXRHoverable deadhoverable in toremove)
  113. {
  114. collidingHoverables.Remove(deadhoverable);
  115. }
  116. }
  117. public void TryClick()
  118. {
  119. if (hoveringObject == null) return;
  120. IXRClickable newclick = hoveringObject.GetTransform().GetComponent<IXRClickable>();
  121. if (newclick == null) return;
  122. PlaySoundIfValid(clickSound);
  123. newclick.OnClick(this);
  124. }
  125. public void TryGrab()
  126. {
  127. if (grabbingObject != null)
  128. {
  129. Debug.Log("Somehow grabbed something while already grabbing something else. Calling ReleaseGrab on that object.");
  130. ReleaseGrab();
  131. }
  132. if (hoveringObject == null) return;
  133. IXRGrabbable newgrab = hoveringObject.GetTransform().GetComponent<IXRGrabbable>();
  134. if (newgrab == null) return;
  135. if (!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd();
  136. hoveringObject = null;
  137. newgrab.OnGrabStart(transform);
  138. grabbingObject = newgrab;
  139. PlaySoundIfValid(grabStartSound);
  140. }
  141. public void ReleaseGrab()
  142. {
  143. if (grabbingObject == null) return;
  144. grabbingObject.OnGrabEnd();
  145. grabbingObject = null;
  146. PlaySoundIfValid(grabEndSound);
  147. }
  148. /// <summary>
  149. /// Plays the given clip, but in a temporary gameobject that appears where the ball is.
  150. /// This lets the sound finish playing even if this object is disabled, such as if you press
  151. /// the switch hands button.
  152. /// </summary>
  153. private void PlaySoundIfValid(AudioClip clip)
  154. {
  155. if (clip == null) return;
  156. //audioSource.PlayOneShot(clip);
  157. GameObject soundgo = new GameObject("Temp Audio Object: " + clip.name);
  158. soundgo.transform.position = transform.position;
  159. TempAudioObject sound = soundgo.AddComponent<TempAudioObject>();
  160. sound.Setup(clip);
  161. }
  162. private void OnDisable()
  163. {
  164. if(hoveringObject != null)
  165. {
  166. if (!Equals(hoveringObject, null)) hoveringObject.OnHoverEnd();
  167. hoveringObject = null;
  168. }
  169. if(grabbingObject != null)
  170. {
  171. grabbingObject.OnGrabEnd();
  172. grabbingObject = null;
  173. }
  174. collidingHoverables.Clear();
  175. collidingGrabbables.Clear();
  176. collidingClickables.Clear();
  177. }
  178. }
  179. public interface IXRHoverable
  180. {
  181. Transform GetTransform();
  182. void OnHoverStart();
  183. void OnHoverEnd();
  184. }
  185. public interface IXRClickable
  186. {
  187. Transform GetTransform();
  188. void OnClick(ZEDXRGrabber clicker);
  189. }
  190. public interface IXRGrabbable
  191. {
  192. Transform GetTransform();
  193. void OnGrabStart(Transform grabtransform);
  194. void OnGrabEnd();
  195. }