Ejemplo n.º 1
0
        /// <summary>
        /// Checks a ray against a circle with a given origin and square radius.
        /// </summary>
        internal static bool CircleRayCast(
      VoltShape shape,
      Vector2 shapeOrigin,
      float sqrRadius,
      ref VoltRayCast ray,
      ref VoltRayResult result)
        {
            Vector2 toOrigin = shapeOrigin - ray.origin;

              if (toOrigin.sqrMagnitude < sqrRadius)
              {
            result.SetContained(shape);
            return true;
              }

              float slope = Vector2.Dot(toOrigin, ray.direction);
              if (slope < 0)
            return false;

              float sqrSlope = slope * slope;
              float d = sqrRadius + sqrSlope - Vector2.Dot(toOrigin, toOrigin);
              if (d < 0)
            return false;

              float dist = slope - Mathf.Sqrt(d);
              if (dist < 0 || dist > ray.distance)
            return false;

              // N.B.: For historical raycasts this normal will be wrong!
              // Must be either transformed back to world or invalidated later.
              Vector2 normal = (dist * ray.direction - toOrigin).normalized;
              result.Set(shape, dist, normal);
              return true;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Checks a ray against a circle with a given origin and square radius.
        /// </summary>
        internal static bool CircleRayCast(
            VoltShape shape,
            Vector2 shapeOrigin,
            float sqrRadius,
            ref VoltRayCast ray,
            ref VoltRayResult result)
        {
            Vector2 toOrigin = shapeOrigin - ray.origin;

            if (toOrigin.sqrMagnitude < sqrRadius)
            {
                result.SetContained(shape);
                return(true);
            }

            float slope = Vector2.Dot(toOrigin, ray.direction);

            if (slope < 0)
            {
                return(false);
            }

            float sqrSlope = slope * slope;
            float d        = sqrRadius + sqrSlope - Vector2.Dot(toOrigin, toOrigin);

            if (d < 0)
            {
                return(false);
            }

            float dist = slope - Mathf.Sqrt(d);

            if (dist < 0 || dist > ray.distance)
            {
                return(false);
            }

            // N.B.: For historical raycasts this normal will be wrong!
            // Must be either transformed back to world or invalidated later.
            Vector2 normal = (dist * ray.direction - toOrigin).normalized;

            result.Set(shape, dist, normal);
            return(true);
        }
Ejemplo n.º 3
0
        private bool CircleCastEdges(
            ref VoltRayCast bodySpaceRay,
            float radius,
            ref VoltRayResult result)
        {
            int  foundIndex       = -1;
            bool couldBeContained = true;

            // Pre-compute and initialize values
            float   shortestDist = float.MaxValue;
            Vector2 v3           = bodySpaceRay.direction.Left();

            // Check the edges -- this will be different from the raycast because
            // we care about staying within the ends of the edge line segment
            for (int i = 0; i < this.countBody; i++)
            {
                Axis curAxis = this.bodyAxes[i];

                // Push the edges out by the radius
                Vector2 extension = curAxis.Normal * radius;
                Vector2 a         = this.bodyVertices[i] + extension;
                Vector2 b         = this.bodyVertices[(i + 1) % this.countBody] + extension;

                // Update the check for containment
                if (couldBeContained == true)
                {
                    float proj =
                        Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width;

                    // The point lies outside of the outer layer
                    if (proj > radius)
                    {
                        couldBeContained = false;
                    }
                    // The point lies between the outer and inner layer
                    else if (proj > 0.0f)
                    {
                        // See if the point is within the center Vornoi region of the edge
                        float d = VoltMath.Cross(curAxis.Normal, bodySpaceRay.origin);
                        if (d > VoltMath.Cross(curAxis.Normal, a))
                        {
                            couldBeContained = false;
                        }
                        if (d < VoltMath.Cross(curAxis.Normal, b))
                        {
                            couldBeContained = false;
                        }
                    }
                }

                // For the cast, only consider rays pointing towards the edge
                if (Vector2.Dot(curAxis.Normal, bodySpaceRay.direction) >= 0.0f)
                {
                    continue;
                }

                // See:
                // https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/
                Vector2 v1 = bodySpaceRay.origin - a;
                Vector2 v2 = b - a;

                float denominator = Vector2.Dot(v2, v3);
                float t1          = VoltMath.Cross(v2, v1) / denominator;
                float t2          = Vector2.Dot(v1, v3) / denominator;

                if ((t2 >= 0.0f) && (t2 <= 1.0f) && (t1 > 0.0f) && (t1 < shortestDist))
                {
                    // See if the point is outside of any of the axes
                    shortestDist = t1;
                    foundIndex   = i;
                }
            }

            // Report results
            if (couldBeContained == true)
            {
                result.SetContained(this);
                return(true);
            }
            else if (foundIndex >= 0 && shortestDist <= bodySpaceRay.distance)
            {
                result.Set(
                    this,
                    shortestDist,
                    this.bodyAxes[foundIndex].Normal);
                return(true);
            }
            return(false);
        }
Ejemplo n.º 4
0
        protected override bool ShapeRayCast(
            ref VoltRayCast bodySpaceRay,
            ref VoltRayResult result)
        {
            int   foundIndex       = -1;
            float inner            = float.MaxValue;
            float outer            = 0;
            bool  couldBeContained = true;

            for (int i = 0; i < this.countBody; i++)
            {
                Axis curAxis = this.bodyAxes[i];

                // Distance between the ray origin and the axis/edge along the
                // normal (i.e., shortest distance between ray origin and the edge)
                float proj =
                    Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width;

                // See if the point is outside of any of the axes
                if (proj > 0.0f)
                {
                    couldBeContained = false;
                }

                // Projection of the ray direction onto the axis normal (use
                // negative normal because we want to get the penetration length)
                float slope = Vector2.Dot(-curAxis.Normal, bodySpaceRay.direction);

                if (slope == 0.0f)
                {
                    continue;
                }
                float dist = proj / slope;

                // The ray is pointing opposite the edge normal (towards the edge)
                if (slope > 0.0f)
                {
                    if (dist > inner)
                    {
                        return(false);
                    }
                    if (dist > outer)
                    {
                        outer      = dist;
                        foundIndex = i;
                    }
                }
                // The ray is pointing along the edge normal (away from the edge)
                else
                {
                    if (dist < outer)
                    {
                        return(false);
                    }
                    if (dist < inner)
                    {
                        inner = dist;
                    }
                }
            }

            if (couldBeContained == true)
            {
                result.SetContained(this);
                return(true);
            }
            else if (foundIndex >= 0 && outer <= bodySpaceRay.distance)
            {
                result.Set(
                    this,
                    outer,
                    this.bodyAxes[foundIndex].Normal);
                return(true);
            }

            return(false);
        }
Ejemplo n.º 5
0
        private bool CircleCastEdges(
      ref VoltRayCast bodySpaceRay,
      float radius,
      ref VoltRayResult result)
        {
            int foundIndex = -1;
              bool couldBeContained = true;

              // Pre-compute and initialize values
              float shortestDist = float.MaxValue;
              Vector2 v3 = bodySpaceRay.direction.Left();

              // Check the edges -- this will be different from the raycast because
              // we care about staying within the ends of the edge line segment
              for (int i = 0; i < this.countBody; i++)
              {
            Axis curAxis = this.bodyAxes[i];

            // Push the edges out by the radius
            Vector2 extension = curAxis.Normal * radius;
            Vector2 a = this.bodyVertices[i] + extension;
            Vector2 b = this.bodyVertices[(i + 1) % this.countBody] + extension;

            // Update the check for containment
            if (couldBeContained == true)
            {
              float proj =
            Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width;

              // The point lies outside of the outer layer
              if (proj > radius)
              {
            couldBeContained = false;
              }
              // The point lies between the outer and inner layer
              else if (proj > 0.0f)
              {
            // See if the point is within the center Vornoi region of the edge
            float d = VoltMath.Cross(curAxis.Normal, bodySpaceRay.origin);
            if (d > VoltMath.Cross(curAxis.Normal, a))
              couldBeContained = false;
            if (d < VoltMath.Cross(curAxis.Normal, b))
              couldBeContained = false;
              }
            }

            // For the cast, only consider rays pointing towards the edge
            if (Vector2.Dot(curAxis.Normal, bodySpaceRay.direction) >= 0.0f)
              continue;

            // See:
            // https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/
            Vector2 v1 = bodySpaceRay.origin - a;
            Vector2 v2 = b - a;

            float denominator = Vector2.Dot(v2, v3);
            float t1 = VoltMath.Cross(v2, v1) / denominator;
            float t2 = Vector2.Dot(v1, v3) / denominator;

            if ((t2 >= 0.0f) && (t2 <= 1.0f) && (t1 > 0.0f) && (t1 < shortestDist))
            {
              // See if the point is outside of any of the axes
              shortestDist = t1;
              foundIndex = i;
            }
              }

              // Report results
              if (couldBeContained == true)
              {
            result.SetContained(this);
            return true;
              }
              else if (foundIndex >= 0 && shortestDist <= bodySpaceRay.distance)
              {
            result.Set(
              this,
              shortestDist,
              this.bodyAxes[foundIndex].Normal);
            return true;
              }
              return false;
        }
Ejemplo n.º 6
0
        protected override bool ShapeRayCast(
      ref VoltRayCast bodySpaceRay,
      ref VoltRayResult result)
        {
            int foundIndex = -1;
              float inner = float.MaxValue;
              float outer = 0;
              bool couldBeContained = true;

              for (int i = 0; i < this.countBody; i++)
              {
            Axis curAxis = this.bodyAxes[i];

            // Distance between the ray origin and the axis/edge along the
            // normal (i.e., shortest distance between ray origin and the edge)
            float proj =
              Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width;

            // See if the point is outside of any of the axes
            if (proj > 0.0f)
              couldBeContained = false;

            // Projection of the ray direction onto the axis normal (use
            // negative normal because we want to get the penetration length)
            float slope = Vector2.Dot(-curAxis.Normal, bodySpaceRay.direction);

            if (slope == 0.0f)
              continue;
            float dist = proj / slope;

            // The ray is pointing opposite the edge normal (towards the edge)
            if (slope > 0.0f)
            {
              if (dist > inner)
              {
            return false;
              }
              if (dist > outer)
              {
            outer = dist;
            foundIndex = i;
              }
            }
            // The ray is pointing along the edge normal (away from the edge)
            else
            {
              if (dist < outer)
              {
            return false;
              }
              if (dist < inner)
              {
            inner = dist;
              }
            }
              }

              if (couldBeContained == true)
              {
            result.SetContained(this);
            return true;
              }
              else if (foundIndex >= 0 && outer <= bodySpaceRay.distance)
              {
            result.Set(
              this,
              outer,
              this.bodyAxes[foundIndex].Normal);
            return true;
              }

              return false;
        }