Esempio n. 1
0
        /// <summary>
        ///Returns a SphericalObstacle from the current gameObject
        /// </summary>
        /// <param name="gameObject">
        /// A game object to create the obstacle from<see cref="GameObject"/>
        /// </param>
        /// <returns>
        /// A SphericalObstacle encompassing the game object<see cref="Obstacle"/>
        /// </returns>
        public static Obstacle GetObstacle(GameObject gameObject)
        {
            SphericalObstacle obstacle;
            int id = gameObject.GetInstanceID();

            Component[] colliders;
            float       radius = 0.0f, currentRadius;

            if (!ObstacleCache.ContainsKey(id))
            {
                var obstacleData = gameObject.GetComponent <SphericalObstacleData>();
                // If the object provides his own spherical obstacle information,
                // use it instead of calculating a sphere that encompasses the
                // whole collider.
                if (obstacleData != null)
                {
                    ObstacleCache[id] = new SphericalObstacle(obstacleData.Radius, gameObject.transform.position + obstacleData.Center);
                }
                else
                {
                    colliders = gameObject.GetComponentsInChildren <Collider>();

                    if (colliders == null)
                    {
                        Debug.LogError("Obstacle '" + gameObject.name + "' has no colliders");
                        return(null);
                    }

                    foreach (Collider collider in colliders)
                    {
                        if (collider.isTrigger)
                        {
                            continue;
                        }
                        // Get the maximum extent to create a sphere that encompasses the whole obstacle
                        float maxExtents = Mathf.Max(Mathf.Max(collider.bounds.extents.x, collider.bounds.extents.y),
                                                     collider.bounds.extents.z);

                        /*
                         * Calculate the displacement from the object center to the
                         * collider, and add in the maximum extents of the bounds.
                         * Notice that we don't need to multiply by the object's
                         * local scale, since that is already considered in the
                         * bounding rectangle.
                         */
                        float distanceToCollider = Vector3.Distance(gameObject.transform.position, collider.bounds.center);
                        currentRadius = distanceToCollider + maxExtents;
                        if (currentRadius > radius)
                        {
                            radius = currentRadius;
                        }
                    }
                    ObstacleCache[id] = new SphericalObstacle(radius, gameObject.transform.position);
                }
            }
            obstacle = ObstacleCache[id] as SphericalObstacle;

            return(obstacle);
        }
Esempio n. 2
0
        /// <summary>
        ///Returns a SphericalObstacle from the current gameObject 
        /// </summary>
        /// <param name="gameObject">
        /// A game object to create the obstacle from<see cref="GameObject"/>
        /// </param>
        /// <returns>
        /// A SphericalObstacle encompassing the game object<see cref="Obstacle"/>
        /// </returns>
        public static Obstacle GetObstacle( GameObject gameObject )
    	{
    		SphericalObstacle obstacle;
    		int id = gameObject.GetInstanceID();
    		Component[] colliders;
    		float radius = 0.0f, currentRadius;

    		if(!ObstacleCache.ContainsKey( id ))
    		{
				var obstacleData = gameObject.GetComponent<SphericalObstacleData>();
				// If the object provides his own spherical obstacle information,
				// use it instead of calculating a sphere that encompasses the 
				// whole collider.
				if (obstacleData != null) 
				{
					ObstacleCache[id] = new SphericalObstacle(obstacleData.Radius, gameObject.transform.position + obstacleData.Center);
				}
				else 
				{
	    			colliders = gameObject.GetComponentsInChildren<Collider>();
	
	    			if( colliders == null )
	    			{
	    				Debug.LogError( "Obstacle '" + gameObject.name + "' has no colliders" );
	    				return null;
	    			}
	
	    			foreach( Collider collider in colliders )
	    			{
	    				if( collider.isTrigger )
	    				{
	    					continue;
	    				}
	    				// Get the maximum extent to create a sphere that encompasses the whole obstacle
	    				float maxExtents = Mathf.Max(Mathf.Max(collider.bounds.extents.x, collider.bounds.extents.y),
	    				                             collider.bounds.extents.z);
	    				
					    /*
					     * Calculate the displacement from the object center to the 
					     * collider, and add in the maximum extents of the bounds.
					     * Notice that we don't need to multiply by the object's 
					     * local scale, since that is already considered in the 
					     * bounding rectangle.
					     */
					    float distanceToCollider = Vector3.Distance(gameObject.transform.position, collider.bounds.center);
	                    currentRadius = distanceToCollider + maxExtents;
	    				if( currentRadius > radius )
	    				{
	    					radius = currentRadius;
	    				}
	    			}
	    			ObstacleCache[id] = new SphericalObstacle( radius, gameObject.transform.position );
				}
    		}
    		obstacle = ObstacleCache[ id ] as SphericalObstacle;

    		return obstacle;
    	}
		public PathIntersection(SphericalObstacle obstacle)
		{
			this.obstacle = obstacle;
			intersect = false;
			distance = float.MaxValue;
		}
	/// <summary>
	/// Finds the vehicle's next intersection with a spherical obstacle
	/// </summary>
	/// <param name="obs">
	/// A spherical obstacle to check against <see cref="SphericalObstacle"/>
	/// </param>
	/// <param name="line">
	/// Line that we expect we'll follow to our future destination
	/// </param>
	/// <returns>
	/// A PathIntersection with the intersection details <see cref="PathIntersection"/>
	/// </returns>
	public PathIntersection FindNextIntersectionWithSphere (SphericalObstacle obs, Vector3 line)
	{
		/*
		 * This routine is based on the Paul Bourke's derivation in:
		 *   Intersection of a Line and a Sphere (or circle)
		 *   http://www.swin.edu.au/astronomy/pbourke/geometry/sphereline/
		 *
		 * Retaining the same variable values used in that description.
		 * 
		 */
		float a, b, c, bb4ac;
		var toCenter = Vehicle.Position - obs.center;

		// initialize pathIntersection object
		var intersection = new PathIntersection(obs);
		
		#if ANNOTATE_AVOIDOBSTACLES
		obs.annotatePosition();
		Debug.DrawLine(Vehicle.Position, Vehicle.Position + line, Color.cyan);
		#endif
		
		// computer line-sphere intersection parameters
		a = line.sqrMagnitude;
		b = 2 * Vector3.Dot(line, toCenter);
		c = obs.center.sqrMagnitude;
		c += Vehicle.Position.sqrMagnitude;
		c -= 2 * Vector3.Dot(obs.center, Vehicle.Position); 
		c -= Mathf.Pow(obs.radius + Vehicle.ScaledRadius, 2);
		bb4ac = b * b - 4 * a * c;

		if (bb4ac >= 0)  {
			intersection.intersect = true;
			Vector3 closest = Vector3.zero;
			if (bb4ac == 0) {
				// Only one intersection
				var mu = -b / (2*a);
				closest = mu * line;
			}
			else {
				// More than one intersection
				var mu1 = (-b + Mathf.Sqrt(bb4ac)) / (2*a);
				var mu2 = (-b - Mathf.Sqrt(bb4ac)) / (2*a);
				/*
				 * If the results are negative, the obstacle is behind us.
				 * 
				 * If one result is negative and the other one positive,
				 * that would indicate that one intersection is behind us while
				 * the other one ahead of us, which would mean that we're 
				 * just overlapping the obstacle, so we should still avoid.  
				 */
				if (mu1 < 0 && mu2 < 0)
					intersection.intersect = false;
				else
					closest = (Mathf.Abs(mu1) < Mathf.Abs (mu2)) ? mu1 * line : mu2 * line;
			}
			#if ANNOTATE_AVOIDOBSTACLES
			Debug.DrawRay(Vehicle.Position, closest, Color.red);
			#endif

			intersection.distance =  closest.magnitude;
		}
		return intersection;
	}
	/// <summary>
	/// Finds the vehicle's next intersection with a spherical obstacle
	/// </summary>
	/// <param name="obs">
	/// A spherical obstacle to check against <see cref="SphericalObstacle"/>
	/// </param>
	/// <returns>
	/// A PathIntersection with the intersection details <see cref="PathIntersection"/>
	/// </returns>
	public PathIntersection FindNextIntersectionWithSphere (SphericalObstacle obs)
	{
		// This routine is based on the Paul Bourke's derivation in:
		//	 Intersection of a Line and a Sphere (or circle)
		//	 http://www.swin.edu.au/astronomy/pbourke/geometry/sphereline/

		float b, c, d, p, q, s;
		Vector3 lc;

		// initialize pathIntersection object
		PathIntersection intersection = new PathIntersection(obs);
		// find "local center" (lc) of sphere in the vehicle's coordinate space
		lc = transform.InverseTransformPoint(obs.center);
		
		#if ANNOTATE_AVOIDOBSTACLES
		obs.annotatePosition();
		#endif
		
		// computer line-sphere intersection parameters
		b = -2 * lc.z;
		c = Mathf.Pow(lc.x, 2) + Mathf.Pow(lc.y, 2) + Mathf.Pow(lc.z, 2) - 
			Mathf.Pow(obs.radius + Vehicle.Radius, 2);
		d = (b * b) - (4 * c);

		// when the path does not intersect the sphere
		if (d < 0) return intersection;

		// otherwise, the path intersects the sphere in two points with
		// parametric coordinates of "p" and "q".
		// (If "d" is zero the two points are coincident, the path is tangent)
		s = (float) System.Math.Sqrt(d);
		p = (-b + s) / 2;
		q = (-b - s) / 2;

		// both intersections are behind us, so no potential collisions
		if ((p < 0) && (q < 0)) return intersection; 

		// at least one intersection is in front of us
		intersection.intersect = true;
		intersection.distance =
			((p > 0) && (q > 0)) ?
			// both intersections are in front of us, find nearest one
			((p < q) ? p : q) :
			// otherwise only one intersections is in front, select it
			((p > 0) ? p : q);
		
		return intersection;
	}