using UnityEngine; using UnityEngine.UI; using System.Collections; using System; /// /// Handles detecting whether or not a real-world location is valid for placing a Bunny object /// in the ZED plane detection samples. To be valid, it must find a plane at the given location /// and that plane must face upward. Turns a placeholder object blue when valid, and red when not. /// Also works with VR controllers if the SteamVR or Oculus Integration plugins are installed. /// public class BunnyPlacement : MonoBehaviour { /// /// Textures assigned to the placeholder object when placement is valid. /// Index of each texture corresponds to the index of the material on the placeholder object. /// [Tooltip("Textures assigned to the placeholder object when placement is valid. " + "Index of each texture corresponds to the index of the material on the placeholder object.")] public Texture[] goodPlacementTex; /// /// Textures assigned to the placeholder object when placement is not valid. /// Index of each texture corresponds to the index of the material on the placeholder object. /// [Tooltip("Textures assigned to the placeholder object when placement is not valid. " + "Index of each texture corresponds to the index of the material on the placeholder object.")] public Texture[] badPlacementTex; /// /// Light object in the placeholder object. We change its color based on placement validity. /// private Light pointlight; /// /// The ZEDControllerTracker object in the VR controller used to place the object, if applicable. /// private ZEDControllerTracker_DemoInputs tracker; /// /// The scene's ZED Plane Detection Manager. /// private ZEDPlaneDetectionManager zedPlane; /// /// The BunnySpawner object, normally on the same object as this component. /// private BunnySpawner bunnySpawner; /// /// The placeholder object's transform. /// private Transform placeholder; /// /// Whether or not we are able to spawn a bunny here. /// private bool canspawnbunny; /// /// Possible states of the button used for input, whether the spacebar, a VR controller trigger, etc. /// public enum state { Idle, Down, Press, Up }; /// /// The current state of the button used for input. /// public state button { get; private set; } /// /// Awake is used to initialize any variables or game state before the game starts. /// void Awake() { canspawnbunny = false; tracker = GetComponent(); zedPlane = FindObjectOfType(); bunnySpawner = GetComponent(); } /// /// Sets a reference to the placeholder object. Set from BunnySpawner.cs. /// /// The placeholder object. public void SetPlaceholder(Transform pointer) { placeholder = pointer; pointlight = pointer.GetChild(0).GetComponentInChildren(); } /// /// Update is called every frame. /// Here we receive the input from the Controller. /// Then we decide what to do in each case. /// private void Update() { if (tracker == null) { if (Input.GetKeyDown(KeyCode.Space)) button = state.Down; else if (Input.GetKey(KeyCode.Space)) button = state.Press; else if (Input.GetKeyUp(KeyCode.Space)) button = state.Up; else button = state.Idle; } else { if (tracker.CheckClickButton(ControllerButtonState.Down)) button = state.Down; else if (tracker.CheckClickButton(ControllerButtonState.Held)) button = state.Press; else if (tracker.CheckClickButton(ControllerButtonState.Up)) button = state.Up; else button = state.Idle; } //If the Trigger Button is being used. if (button != state.Idle) { //It just got pressed. if (button == state.Down) { //Enable the bunnySpawner to display the placeholder. bunnySpawner.canDisplayPlaceholder = true; //If we were holding the baseball bat but the user wants to re-place the bunny, hide the baseball bat. if (bunnySpawner.baseballBat != null) bunnySpawner.baseballBat.SetActive(false); //Clean up the list of detected planes. if (zedPlane.hitPlaneList.Count > 0) { for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { Destroy(zedPlane.hitPlaneList[i].gameObject); zedPlane.hitPlaneList.RemoveAt(i); } } //Destroy the current Bunny, if any, on the scene. if (!bunnySpawner.canSpawnMultipleBunnies && bunnySpawner.currentBunny != null) { Destroy(bunnySpawner.currentBunny); bunnySpawner.currentBunny = null; } } //From the first input to the next ones as it keeps being hold down. if (button == state.Press || button == state.Down) { if (zedPlane.hitPlaneList.Count == 0) { //Start detecting planes through the ZED Plane Detection Manager. foreach (ZEDManager manager in ZEDManager.GetInstances()) //Check all active ZED cameras for planes. { if (zedPlane.DetectPlaneAtHit(manager, manager.GetMainCamera().WorldToScreenPoint(placeholder.position))) { //Get the normal of the plane. ZEDPlaneGameObject currentPlane = zedPlane.hitPlaneList[zedPlane.hitPlaneList.Count - 1]; Vector3 planeNormal = currentPlane.worldNormal; //Check if the plane has a normal close enough to Y (horizontal surface) to be stable for the Bunny to spawn into. if (Vector3.Dot(planeNormal, Vector3.up) > 0.85f) { //Allow spawning the Bunny, and set the placeholder to a positive color. if (canspawnbunny == false) { canspawnbunny = true; bunnySpawner.placeHolderMat[0].mainTexture = goodPlacementTex[0]; bunnySpawner.placeHolderMat[1].mainTexture = goodPlacementTex[1]; pointlight.color = Color.blue; } else //Clear the list of planes. { for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { if (i == 0) { Destroy(zedPlane.hitPlaneList[i].gameObject); zedPlane.hitPlaneList.RemoveAt(i); } } } } else //Surface wasn't horizontal enough { //Don't allow the Bunny to spawn, and set the placeholder to a negative color. canspawnbunny = false; bunnySpawner.placeHolderMat[0].mainTexture = badPlacementTex[0]; bunnySpawner.placeHolderMat[1].mainTexture = badPlacementTex[1]; pointlight.color = Color.red; //Clear the list of planes. for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { Destroy(zedPlane.hitPlaneList[i].gameObject); zedPlane.hitPlaneList.RemoveAt(i); } } break; //If we detected a plane in one view, no need to go through the rest of the cameras. } } } else if (zedPlane.hitPlaneList.Count > 0) { if (!Physics.Raycast(transform.position, placeholder.position - transform.position)) { //Don't allow for the Bunny to spawn, and set the placeholder to a negative color. canspawnbunny = false; bunnySpawner.placeHolderMat[0].mainTexture = badPlacementTex[0]; bunnySpawner.placeHolderMat[1].mainTexture = badPlacementTex[1]; pointlight.color = Color.red; //Clear the list of planes. for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { Destroy(zedPlane.hitPlaneList[i].gameObject); zedPlane.hitPlaneList.RemoveAt(i); } } } } //Button is released. if (button == state.Up) { //If at that moment the bunny was allowed to spawn, proceed ot make the call. if (canspawnbunny) { bunnySpawner.SpawnBunny(placeholder.position); } else //Clear the list of planes. { for (int i = 0; i < zedPlane.hitPlaneList.Count; i++) { Destroy(zedPlane.hitPlaneList[i].gameObject); zedPlane.hitPlaneList.RemoveAt(i); } } //Reset the booleans. canspawnbunny = false; bunnySpawner.canDisplayPlaceholder = false; } } } }