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;
}
}