using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// /// Moves around the placeholder object in the ZED place detection demo. /// Also spawns the real object if BunnyPlacement.cs reports the placeholder is in a valid position. /// public class BunnySpawner : MonoBehaviour { /// /// Prefab of the Bunny object that we're going to spawn. /// [Tooltip("Prefab of the Bunny object that we're going to spawn.")] public GameObject bunnyPrefab; /// /// Prefab of the pointer/placeholder that indicates if we can place the object there or not. /// [Tooltip("Prefab of the pointer/placeholder that indicates if we can place the object there or not.")] public GameObject pointerPrefab; /// /// Prefab of the flag UI that spawns when the Bunny collides with anything. /// [Tooltip("Prefab of the flag UI that spawns when the Bunny collides with anything.")] public GameObject uiPrefab; /// /// The Material used on the placeHolder of the pointer prefab. Reference used to change colors based on placement validity. /// [Tooltip("The Material used on the placeholder of the pointer prefab. Reference used to change colors based on placement validity.")] public Material[] placeHolderMat; /// /// The origin position for the pointer, from which you aim the ray to check for a valid placement location. /// If null (such as in the non-VR sample) it takes this script's GameObject position. /// [Tooltip("The origin position for the pointer, from which you aim the ray to check for a valid placement location. " + "If null (such as in the non-VR sample) it takes this script's GameObject position.")] public Transform rayOrigin; /// /// Whether or not we can spawn multiple bunnies at once. /// [Tooltip("Whether or not we can spawn multiple bunnies at once.")] public bool canSpawnMultipleBunnies = false; /// /// Whether or not we can display the placeHolder bunny. /// [HideInInspector] public bool canDisplayPlaceholder; /// /// The last UI spawned for a Bunny collision. /// private GameObject currentui; /// /// The last Bunny gameObject spawned in the scene. /// [HideInInspector] public GameObject currentBunny; /// /// Reference to the object that holds the laser as an anchor. /// private GameObject pointer; /// /// Reference to the object that will be placed at the end of the laser. /// private GameObject placeholder; /// /// The "primary" ZEDManager used for spawning bunnies. Used to aim the UI and decide where bunnies are looking on spawn. /// If not set, the first available one in the scene will be used. /// [Tooltip("The 'primary' ZEDManager used for spawning bunnies. Used to aim the UI and decide where bunnies are looking on spawn. " + "If not set, the first available one in the scene will be used.")] public ZEDManager zedManager; /// /// Reference to the ZED's left camera gameobject. /// private Camera cam; /// /// The text componenet of the current UI gameObject for displaying the score (Distance) of how far the Bunny was sent. /// private Text distancetext; /// /// The gameObject that holds the 3D Model of the Baseball Bat, so we can Show/Hide it. /// [HideInInspector] public GameObject baseballBat; void Awake() { if (!zedManager) { zedManager = FindObjectOfType(); } //Find the left camera object if we didn't assign it at start. if (!cam) { cam = zedManager.GetMainCamera(); } //Check if there is a Object Tracker on this object for VR controls. var tracker = GetComponent(); if (tracker != null) { //Get the parent object of the baseball bat. if (transform.childCount > 1) { baseballBat = transform.GetChild(1).gameObject; baseballBat.SetActive(false); //Hide it by default. It'll get revealed once we place a bunny. } } //Instantiate the pointer prefab and assign it to our variables. if (pointerPrefab != null) { pointer = Instantiate(pointerPrefab) as GameObject; //Get the Anchor/root of the pointerBead. placeholder = pointer.transform.GetChild(0).gameObject; //Get the laser's pointerBead. } //If we didn't set a transform for the pointer's origin position... if (rayOrigin == null) { rayOrigin = transform; //...then take our local position. } //Set the PlaneManager's reference to our placeholder. GetComponent().SetPlaceholder(placeholder.transform); } /// /// This function is called every fixed framerate frame /// Here we take care of enabling & disabling the laser pointer by looking for collisions with the real world. /// void FixedUpdate() { //Do we have a Pointer Bead to position in the world? if (pointer != null && GetComponent().button != BunnyPlacement.state.Idle) { Vector3 pointerposition; //Point the bead at the closest thing in front of the camera. if (zedManager.IsZEDReady && FindPointerPosition(out pointerposition) && canDisplayPlaceholder) { //We hit something. Make sure the bead is active. pointer.SetActive(true); //Position the bead a the collision point, and make it face you. pointer.transform.position = pointerposition; Quaternion rot = Quaternion.LookRotation(cam.transform.position - pointer.transform.position); pointer.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); } else { //We didn't hit anything. Disable the bead object. pointer.SetActive(false); } } else pointer.SetActive(false); } /// /// Spawning the Bunny prefab. /// /// Where we'll spawn the bunny. public void SpawnBunny(Vector3 spawnPos) { //Instantiating the prefab. GameObject newBunny = Instantiate(bunnyPrefab, spawnPos, Quaternion.identity, null) as GameObject; //Make the UI to face the camera only on the Y axis. Quaternion rot = Quaternion.LookRotation(cam.transform.position - spawnPos); newBunny.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); //Set this script as the BunnySpawner of the instantiated Bunny. newBunny.GetComponent().SetMySpawner(this); //Assigning it to the currentBunny variable. currentBunny = newBunny; //Start the coroutine that will enable/show the baseball bat. StartCoroutine(EnableBat()); } /// /// Waits for X seconds (to let the bunny fall into place) before activating the bat object. /// /// IEnumerator EnableBat() { //Wait for X seconds... yield return new WaitForSeconds(1f); //...then enable/show the baseball bat. if (!canDisplayPlaceholder && baseballBat != null) { baseballBat.SetActive(true); //It's wabbit season. } } /// /// Instantiating the flag UI prefab. /// /// public void SpawnUI(Vector3 spawnPos) { //Hide the baseball bat. if (baseballBat != null) baseballBat.SetActive(false); //Destroy the last UI that was spawned, if any. if (currentui != null) { Destroy(currentui); currentui = null; } //Instantiate a new UI GameObject and position it. GameObject newUI = Instantiate(uiPrefab, null); newUI.transform.position = spawnPos; //Make the UI to face the camera only on the Y axis. Quaternion rot = Quaternion.LookRotation(cam.transform.position - spawnPos); newUI.transform.eulerAngles = new Vector3(0f, rot.eulerAngles.y, 0f); //Configure the flag UI to be spawned. currentui = newUI; distancetext = currentui.GetComponentInChildren(); //Update the distanceText value to the current Distance between the first/spawned position of the Bunny, and his current one. distancetext.text = Vector3.Distance(currentBunny.GetComponent().InitialPosition, spawnPos).ToString("F2") + " Meters"; //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. if (currentui.transform.position.y > cam.transform.position.y && currentui.transform.position.y > 1.5f) { currentui.transform.eulerAngles = new Vector3(180f, currentui.transform.rotation.eulerAngles.y, 0f); distancetext.transform.localEulerAngles = new Vector3(180f, 0f, 0f); } } /// /// Tests the depth of the real world based on the pointer origin position and rotation. /// Returns the world position if it collided with anything. /// /// The world space position where the pointer is pointing. /// True if a valid real world point was found. bool FindPointerPosition(out Vector3 pointerbeadpoint) { //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. Vector3 realpoint; foreach (ZEDManager manager in ZEDManager.GetInstances()) //Check all cameras, in case it's hitting something the main ZEDManager can't see. { if (ZEDSupportFunctions.HitTestOnRay(zedManager.zedCamera, cam, rayOrigin.position, rayOrigin.rotation, 5.0f, 0.05f, out realpoint)) { pointerbeadpoint = realpoint; return true; //No need to check the other cameras. } } //No camera was able to see a collision. pointerbeadpoint = Vector3.zero; return false; } }