using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// Behavior for drone objects in the ZED ArUco Drone Wars sample.
/// When other drones are in front of this drone and within range, will fire projectiles until it's dead.
///
[RequireComponent(typeof(Collider))]
public class ArUcoDrone : MonoBehaviour
{
///
/// How close other drones have to be for this drone to start firing. Must also be directly in front of the drone.
///
[Tooltip("How close other drones have to be for this drone to start firing. Must also be directly in front of the drone.")]
public float shootRangeMeters = 0.25f;
///
/// Time between each shot when firing.
///
[Tooltip("Time between each shot when firing.")]
public float shootCooldownSeconds = 0.33f;
///
/// How much damage this drone can take before dying.
///
[Tooltip("How much damage this drone can take before dying.")]
public float maxHealth = 10;
///
/// How much health the drone currently has. Goes down when a ArUcoDroneLaser hits it and calls TakeDamage().
///
private float currentHealth;
///
/// Time since last shot. Set to zero after it exceeds shootCooldownSeconds.
///
private float shootTimer = 0f;
///
/// Whether the drone can shoot right now. Simply checks if shootTimer is 0, which the Shoot() coroutine will set it to when finished.
///
private bool canShoot
{
get
{
return shootTimer <= 0f;
}
}
///
/// Prefab of the projectile object the drone shoots. Should have an ArUcoDroneLaser component on it.
///
[Tooltip("Prefab of the projectile object the drone shoots. Should have an ArUcoDroneLaser component on it.")]
public GameObject projectilePrefab;
///
/// Transform where laser shots are spawned, and from where the drone's laser range is tested.
///
[Tooltip("Transform where laser shots are spawned, and from where the drone's laser range is tested.")]
public Transform shootAnchorObject;
///
/// Object spawned when the drone dies.
///
[Tooltip("Object spawned when the drone dies.")]
public GameObject explosionPrefab;
private Collider col;
///
/// Sound played every time the drone fires a laser. Requires an AudioSource attached to this GameObject.
///
[Tooltip("Sound played every time the drone fires a laser. Requires an AudioSource attached to this GameObject.")]
public AudioClip laserShootSound;
private AudioSource audioSource;
///
/// If true, will use the ZED's depth to check if there's a real-world object between this drone and its target.
///
[Tooltip("If true, will use the ZED's depth to check if there's a real-world object between this drone and its target.")]
public bool checkRealWorldObstaclesBeforeShooting = false;
// Use this for initialization
void Start ()
{
col = GetComponent();
currentHealth = maxHealth;
audioSource = GetComponent();
}
private void OnEnable()
{
shootTimer = 0f; //If the drone was disabled from being hidden, this prevents laser not being able to fire.
}
// Update is called once per frame
void Update ()
{
if(canShoot == true && IsAimingAtTarget() == true)
{
StartCoroutine(Shoot());
}
}
///
/// Checks if another ArUcoDrone is in front of the drone and within range.
/// Will also check if there's a real object in the way, if checkRealWorldObstaclesBeforeShooting is true.
///
/// True if there's a valid target in front of the drone.
private bool IsAimingAtTarget()
{
//First make sure there's a valid virtual target in front of the drone.
Ray ray = new Ray(shootAnchorObject.position, shootAnchorObject.rotation * Vector3.forward);
RaycastHit[] hits = Physics.RaycastAll(ray, shootRangeMeters);
bool foundvirtualtarget = false;
float nearestdist = Mathf.Infinity;
foreach(RaycastHit hit in hits)
{
ArUcoDrone otherdrone = hit.transform.GetComponent();
if(otherdrone != null && otherdrone != this)
{
foundvirtualtarget = true;
if (hit.distance < nearestdist) nearestdist = hit.distance;
}
}
if (!foundvirtualtarget) return false;
if (checkRealWorldObstaclesBeforeShooting) //Make sure there's not a real-world obstacle in the way of the target.
{
//If there is one, check to make sure there's not a real-world object in the way.
Vector3 collisionpoint; //Not used but required for HitTestOnRay function.
foreach (ZEDManager manager in ZEDManager.GetInstances())
{
bool hitreal = ZEDSupportFunctions.HitTestOnRay(manager.zedCamera, manager.GetLeftCamera(), shootAnchorObject.transform.position, shootAnchorObject.transform.rotation,
nearestdist, 0.01f, out collisionpoint, false, 0.1f);
if (hitreal) return false;
}
return true;
}
else return true; //We're not checking against the real world, and we already found a virtual object, so fire.
}
///
/// Instantiate a projectilePrefab at the anchor point.
///
private void SpawnProjectile()
{
//SHOOT STUFF.
if (!projectilePrefab) return;
GameObject lasergo = Instantiate(projectilePrefab, shootAnchorObject.transform.position, shootAnchorObject.transform.rotation);
//lasergo.transform.localScale = transform.lossyScale;
lasergo.name = gameObject.name + "'s Laser";
ArUcoDroneLaser laser = lasergo.GetComponentInChildren();
if(!laser)
{
Debug.LogError("projectilePrefab assigned to " + gameObject.name + " does not have an ArUcoDroneLaser component.");
Destroy(lasergo);
return;
}
laser.spawningDrone = this;
if(audioSource && laserShootSound)
{
audioSource.PlayOneShot(laserShootSound);
}
}
///
/// Spawns a projectile and advances the shootTimer until the cooldown period is over - then resets it, allowing another shot.
///
///
private IEnumerator Shoot()
{
SpawnProjectile();
while(shootTimer < shootCooldownSeconds)
{
shootTimer += Time.deltaTime;
yield return null;
}
shootTimer = 0f;
}
///
/// Reduces the drone's health, and destroys it if it goes below zero.
/// Called by ArUcoDroneLaser when it hits this drone's collider.
///
public void TakeDamage(float damage)
{
currentHealth -= damage;
//print("Took " + damage + " damage. Now at " + currentHealth + " HP.");
if (currentHealth <= 0)
{
Die();
}
}
///
/// Spawns an explosion and destroys this object.
///
public void Die()
{
print(gameObject.name + " destroyed.");
if(explosionPrefab)
{
Instantiate(explosionPrefab, transform.position, transform.rotation);
}
Destroy(gameObject);
}
}