BunnySpawner.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. /// <summary>
  6. /// Moves around the placeholder object in the ZED place detection demo.
  7. /// Also spawns the real object if BunnyPlacement.cs reports the placeholder is in a valid position.
  8. /// </summary>
  9. public class BunnySpawner : MonoBehaviour
  10. {
  11. /// <summary>
  12. /// Prefab of the Bunny object that we're going to spawn.
  13. /// </summary>
  14. [Tooltip("Prefab of the Bunny object that we're going to spawn.")]
  15. public GameObject bunnyPrefab;
  16. /// <summary>
  17. /// Prefab of the pointer/placeholder that indicates if we can place the object there or not.
  18. /// </summary>
  19. [Tooltip("Prefab of the pointer/placeholder that indicates if we can place the object there or not.")]
  20. public GameObject pointerPrefab;
  21. /// <summary>
  22. /// Prefab of the flag UI that spawns when the Bunny collides with anything.
  23. /// </summary>
  24. [Tooltip("Prefab of the flag UI that spawns when the Bunny collides with anything.")]
  25. public GameObject uiPrefab;
  26. /// <summary>
  27. /// The Material used on the placeHolder of the pointer prefab. Reference used to change colors based on placement validity.
  28. /// </summary>
  29. [Tooltip("The Material used on the placeholder of the pointer prefab. Reference used to change colors based on placement validity.")]
  30. public Material[] placeHolderMat;
  31. /// <summary>
  32. /// The origin position for the pointer, from which you aim the ray to check for a valid placement location.
  33. /// If null (such as in the non-VR sample) it takes this script's GameObject position.
  34. /// </summary>
  35. [Tooltip("The origin position for the pointer, from which you aim the ray to check for a valid placement location. " +
  36. "If null (such as in the non-VR sample) it takes this script's GameObject position.")]
  37. public Transform rayOrigin;
  38. /// <summary>
  39. /// Whether or not we can spawn multiple bunnies at once.
  40. /// </summary>
  41. [Tooltip("Whether or not we can spawn multiple bunnies at once.")]
  42. public bool canSpawnMultipleBunnies = false;
  43. /// <summary>
  44. /// Whether or not we can display the placeHolder bunny.
  45. /// </summary>
  46. [HideInInspector]
  47. public bool canDisplayPlaceholder;
  48. /// <summary>
  49. /// The last UI spawned for a Bunny collision.
  50. /// </summary>
  51. private GameObject currentui;
  52. /// <summary>
  53. /// The last Bunny gameObject spawned in the scene.
  54. /// </summary>
  55. [HideInInspector]
  56. public GameObject currentBunny;
  57. /// <summary>
  58. /// Reference to the object that holds the laser as an anchor.
  59. /// </summary>
  60. private GameObject pointer;
  61. /// <summary>
  62. /// Reference to the object that will be placed at the end of the laser.
  63. /// </summary>
  64. private GameObject placeholder;
  65. /// <summary>
  66. /// The "primary" ZEDManager used for spawning bunnies. Used to aim the UI and decide where bunnies are looking on spawn.
  67. /// <para>If not set, the first available one in the scene will be used.</para>
  68. /// </summary>
  69. [Tooltip("The 'primary' ZEDManager used for spawning bunnies. Used to aim the UI and decide where bunnies are looking on spawn. " +
  70. "If not set, the first available one in the scene will be used.")]
  71. public ZEDManager zedManager;
  72. /// <summary>
  73. /// Reference to the ZED's left camera gameobject.
  74. /// </summary>
  75. private Camera cam;
  76. /// <summary>
  77. /// The text componenet of the current UI gameObject for displaying the score (Distance) of how far the Bunny was sent.
  78. /// </summary>
  79. private Text distancetext;
  80. /// <summary>
  81. /// The gameObject that holds the 3D Model of the Baseball Bat, so we can Show/Hide it.
  82. /// </summary>
  83. [HideInInspector]
  84. public GameObject baseballBat;
  85. void Awake()
  86. {
  87. if (!zedManager)
  88. {
  89. zedManager = FindObjectOfType<ZEDManager>();
  90. }
  91. //Find the left camera object if we didn't assign it at start.
  92. if (!cam)
  93. {
  94. cam = zedManager.GetMainCamera();
  95. }
  96. //Check if there is a Object Tracker on this object for VR controls.
  97. var tracker = GetComponent<ZEDControllerTracker>();
  98. if (tracker != null)
  99. {
  100. //Get the parent object of the baseball bat.
  101. if (transform.childCount > 1)
  102. {
  103. baseballBat = transform.GetChild(1).gameObject;
  104. baseballBat.SetActive(false); //Hide it by default. It'll get revealed once we place a bunny.
  105. }
  106. }
  107. //Instantiate the pointer prefab and assign it to our variables.
  108. if (pointerPrefab != null)
  109. {
  110. pointer = Instantiate(pointerPrefab) as GameObject; //Get the Anchor/root of the pointerBead.
  111. placeholder = pointer.transform.GetChild(0).gameObject; //Get the laser's pointerBead.
  112. }
  113. //If we didn't set a transform for the pointer's origin position...
  114. if (rayOrigin == null)
  115. {
  116. rayOrigin = transform; //...then take our local position.
  117. }
  118. //Set the PlaneManager's reference to our placeholder.
  119. GetComponent<BunnyPlacement>().SetPlaceholder(placeholder.transform);
  120. }
  121. /// <summary>
  122. /// This function is called every fixed framerate frame
  123. /// Here we take care of enabling & disabling the laser pointer by looking for collisions with the real world.
  124. /// </summary>
  125. void FixedUpdate()
  126. {
  127. //Do we have a Pointer Bead to position in the world?
  128. if (pointer != null && GetComponent<BunnyPlacement>().button != BunnyPlacement.state.Idle)
  129. {
  130. Vector3 pointerposition;
  131. //Point the bead at the closest thing in front of the camera.
  132. if (zedManager.IsZEDReady && FindPointerPosition(out pointerposition) && canDisplayPlaceholder)
  133. {
  134. //We hit something. Make sure the bead is active.
  135. pointer.SetActive(true);
  136. //Position the bead a the collision point, and make it face you.
  137. pointer.transform.position = pointerposition;
  138. Quaternion rot = Quaternion.LookRotation(cam.transform.position - pointer.transform.position);
  139. pointer.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f);
  140. }
  141. else
  142. {
  143. //We didn't hit anything. Disable the bead object.
  144. pointer.SetActive(false);
  145. }
  146. }
  147. else
  148. pointer.SetActive(false);
  149. }
  150. /// <summary>
  151. /// Spawning the Bunny prefab.
  152. /// </summary>
  153. /// <param name="spawnPos">Where we'll spawn the bunny.</param>
  154. public void SpawnBunny(Vector3 spawnPos)
  155. {
  156. //Instantiating the prefab.
  157. GameObject newBunny = Instantiate(bunnyPrefab, spawnPos, Quaternion.identity, null) as GameObject;
  158. //Make the UI to face the camera only on the Y axis.
  159. Quaternion rot = Quaternion.LookRotation(cam.transform.position - spawnPos);
  160. newBunny.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f);
  161. //Set this script as the BunnySpawner of the instantiated Bunny.
  162. newBunny.GetComponent<Bunny>().SetMySpawner(this);
  163. //Assigning it to the currentBunny variable.
  164. currentBunny = newBunny;
  165. //Start the coroutine that will enable/show the baseball bat.
  166. StartCoroutine(EnableBat());
  167. }
  168. /// <summary>
  169. /// Waits for X seconds (to let the bunny fall into place) before activating the bat object.
  170. /// </summary>
  171. /// <returns></returns>
  172. IEnumerator EnableBat()
  173. {
  174. //Wait for X seconds...
  175. yield return new WaitForSeconds(1f);
  176. //...then enable/show the baseball bat.
  177. if (!canDisplayPlaceholder && baseballBat != null)
  178. {
  179. baseballBat.SetActive(true); //It's wabbit season.
  180. }
  181. }
  182. /// <summary>
  183. /// Instantiating the flag UI prefab.
  184. /// </summary>
  185. /// <param name="spawnPos"></param>
  186. public void SpawnUI(Vector3 spawnPos)
  187. {
  188. //Hide the baseball bat.
  189. if (baseballBat != null)
  190. baseballBat.SetActive(false);
  191. //Destroy the last UI that was spawned, if any.
  192. if (currentui != null)
  193. {
  194. Destroy(currentui);
  195. currentui = null;
  196. }
  197. //Instantiate a new UI GameObject and position it.
  198. GameObject newUI = Instantiate(uiPrefab, null);
  199. newUI.transform.position = spawnPos;
  200. //Make the UI to face the camera only on the Y axis.
  201. Quaternion rot = Quaternion.LookRotation(cam.transform.position - spawnPos);
  202. newUI.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f);
  203. //Configure the flag UI to be spawned.
  204. currentui = newUI;
  205. distancetext = currentui.GetComponentInChildren<Text>();
  206. //Update the distanceText value to the current Distance between the first/spawned position of the Bunny, and his current one.
  207. distancetext.text = Vector3.Distance(currentBunny.GetComponent<Bunny>().InitialPosition, spawnPos).ToString("F2") + " Meters";
  208. //If the UI position is higher than ours, and for a minimum of 1.5 meters, then rotate it 180 on the X axis so it's turned upside down.
  209. if (currentui.transform.position.y > cam.transform.position.y && currentui.transform.position.y > 1.5f)
  210. {
  211. currentui.transform.eulerAngles = new Vector3(180f, currentui.transform.rotation.eulerAngles.y, 0f);
  212. distancetext.transform.localEulerAngles = new Vector3(180f, 0f, 0f);
  213. }
  214. }
  215. /// <summary>
  216. /// Tests the depth of the real world based on the pointer origin position and rotation.
  217. /// Returns the world position if it collided with anything.
  218. /// </summary>
  219. /// <param name="pointerbeadpoint">The world space position where the pointer is pointing.</param>
  220. /// <returns>True if a valid real world point was found.</returns>
  221. bool FindPointerPosition(out Vector3 pointerbeadpoint)
  222. {
  223. //Find the distance to the real world. The bool will be false if there is an error reading the depth at the center of the screen.
  224. Vector3 realpoint;
  225. foreach (ZEDManager manager in ZEDManager.GetInstances()) //Check all cameras, in case it's hitting something the main ZEDManager can't see.
  226. {
  227. if (ZEDSupportFunctions.HitTestOnRay(zedManager.zedCamera, cam, rayOrigin.position, rayOrigin.rotation, 5.0f, 0.05f, out realpoint))
  228. {
  229. pointerbeadpoint = realpoint;
  230. return true; //No need to check the other cameras.
  231. }
  232. }
  233. //No camera was able to see a collision.
  234. pointerbeadpoint = Vector3.zero;
  235. return false;
  236. }
  237. }