using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; /// /// Checks for collisions with both the real and virtual world and moves forward each frame. /// Inherit from this class to easily make your own projectile that can hit both the virtual and real. /// See LaserShot_Drone and LaserShot_Player in the ZED Drone Battle sample for examples. /// Real world "collisions" test if it's behind the real world using the static hit test functions in ZEDSupportFunctions. /// public class ZEDProjectile : MonoBehaviour { /// /// How fast the projectile moves forward in meters per second. /// [Tooltip("How fast the projectile moves forward in meters per second.")] public float speed = 10f; /// /// How long the projectile lasts before being destroyed, even if it doesn't collide with anything. /// [Tooltip("How long the projectile lasts before being destroyed, even if it doesn't collide with anything.")] public float lifespan = 8f; /// /// How granular the dots are along the fake raycast done for real-world collisions. /// [Tooltip("How granular the dots are along the fake raycast done for real-world collisions.")] public float distanceBetweenRayChecks = 0.01f; /// /// How far behind a real pixel can a collision check decide it's not a collision. /// [Tooltip("How far behind a real pixel can a collision check decide it's not a collision.")] public float realWorldThickness = 0.05f; /// /// If true, all active ZEDs are used to check for collisions. /// This can mean being able to shoot things that aren't visible to the first player, but due to the /// nature of collisions testing if virtual objects are behind the real world, can lead to /// false positives if, for instance, a player in pass-through AR is between a projectile and a third-person ZED. /// Use the realWorldThickness value to help mitigate this. /// [Tooltip("If true, all active ZEDs are used to check for collisions. " + "This can mean being able to shoot things that aren't visible to the first player, but due to the " + "nature of collisions testing if virtual objects are behind the real world, can lead to " + "false positives if, for instance, a player in pass-through AR is between a projectile and a third-person ZED. " + "Use the realWorldThickness value to help mitigate this.")] public bool testCollisionsUsingAllZEDs = true; /// /// Primary ZEDManager, used for collision detection when testCollisionsUsingAllZEDs is set to false. /// public ZEDManager zedManager = null; /// /// The ZED camera reference, used for calling ZEDSupportFunctions to transform depth data from the ZED into world space. /// protected Camera cam; private void Awake() { if (zedManager == null) { zedManager = FindObjectOfType(); //If this happenend when only using a primary ZED for collisions but there are multiple ZEDs, collisions will be //calculated using an arbitrary camera. Warn the user. if (testCollisionsUsingAllZEDs == false && ZEDManager.GetInstances().Count > 1) { Debug.LogWarning("Warning: ZEDProjectile's zedManager value was not specified, resulting in assigning to first available " + " camera, but there are multiple cameras in the scene. This can cause strange collision test behavior."); } } if (!cam) { cam = zedManager.GetMainCamera(); } } /// /// Handles movements and collisions on a constant basis. /// void FixedUpdate() { //Calculate where the object should move this frame Vector3 newpos = transform.position + transform.rotation * Vector3.forward * (speed * Time.deltaTime); //Collisions with the real World. As the object moves, collisions checks are made each frame at the next position. Vector3 collisionpoint; Vector3 collisionnormal; //First, test the primary ZED. Collisions will look the most accurate if calculated from this one. bool primaryhit = ZEDSupportFunctions.HitTestOnRay(zedManager.zedCamera, cam, newpos, transform.rotation, Vector3.Distance(transform.position, newpos), distanceBetweenRayChecks, out collisionpoint, false, realWorldThickness); if (primaryhit) { //Call the function to resolve the impact. This allows us to easily override what happens on collisions with classes that inherit this one. ZEDSupportFunctions.GetNormalAtWorldLocation(zedManager.zedCamera, collisionpoint, sl.REFERENCE_FRAME.WORLD, cam, out collisionnormal); OnHitRealWorld(collisionpoint, collisionnormal); } if (!primaryhit && testCollisionsUsingAllZEDs) //If set to true, test the rest of the ZEDs as well. { foreach (ZEDManager manager in ZEDManager.GetInstances()) { if (manager == zedManager) continue; //If it's the primary ZED, skip as we've already tested that one. if (ZEDSupportFunctions.HitTestOnRay(manager.zedCamera, manager.GetMainCamera(), newpos, transform.rotation, Vector3.Distance(transform.position, newpos), distanceBetweenRayChecks, out collisionpoint, false, realWorldThickness)) { //Call the function to resolve the impact. This allows us to easily override what happens on collisions with classes that inherit this one. ZEDSupportFunctions.GetNormalAtWorldLocation(manager.zedCamera, collisionpoint, sl.REFERENCE_FRAME.WORLD, manager.GetMainCamera(), out collisionnormal); OnHitRealWorld(collisionpoint, collisionnormal); break; //No need to test the rest of the ZEDs. } } } //Collisions with virtual objects //Cast a ray to check collisions between here and the intended move point for virtual objects. RaycastHit hitinfo; if (Physics.Raycast(transform.position, newpos - transform.position, out hitinfo, Vector3.Distance(transform.position, newpos))) { //Call the function to resolve the impact. This allows us to easily override what happens on collisions with classes that inherit this one. OnHitVirtualWorld(hitinfo); } //Move it to this new place transform.position = newpos; //Tick down its lifespan and check if we should destroy it. lifespan -= Time.deltaTime; if (lifespan <= 0f) { Destroy(gameObject); } } /// /// Called when the projectile hits real geometry. Override to spawn effects, play sounds, etc. /// /// /// public virtual void OnHitRealWorld(Vector3 collisionpoint, Vector3 collisionnormal) { Destroy(gameObject); } /// /// Called when the projectile hits a virtual collider. Override to spawn effects, inflict damage, etc. /// /// The RayCastHit supplied by the raycast used to detect the collision. public virtual void OnHitVirtualWorld(RaycastHit hitinfo) { Destroy(gameObject); } }