Beispiel #1
0
        private bool CircleCastVertices(
            ref VoltRayCast bodySpaceRay,
            float radius,
            ref VoltRayResult result)
        {
            float sqrRadius = radius * radius;
            bool  castHit   = false;

            for (int i = 0; i < this.countBody; i++)
            {
                castHit |=
                    Collision.CircleRayCast(
                        this,
                        this.bodyVertices[i],
                        sqrRadius,
                        ref bodySpaceRay,
                        ref result);
                if (result.IsContained == true)
                {
                    return(true);
                }
            }

            return(castHit);
        }
Beispiel #2
0
        /// <summary>
        /// A cheap ray test that requires some precomputed information.
        /// Adapted from: http://www.cs.utah.edu/~awilliam/box/box.pdf
        /// </summary>
        private static bool RayCast(
            ref VoltRayCast ray,
            Fix64 top,
            Fix64 bottom,
            Fix64 left,
            Fix64 right)
        {
            Fix64 txmin =
                ((ray.signX ? right : left) - ray.origin.x) *
                ray.invDirection.x;
            Fix64 txmax =
                ((ray.signX ? left : right) - ray.origin.x) *
                ray.invDirection.x;

            Fix64 tymin =
                ((ray.signY ? top : bottom) - ray.origin.y) *
                ray.invDirection.y;
            Fix64 tymax =
                ((ray.signY ? bottom : top) - ray.origin.y) *
                ray.invDirection.y;

            if ((txmin > tymax) || (tymin > txmax))
            {
                return(false);
            }
            if (tymin > txmin)
            {
                txmin = tymin;
            }
            if (tymax < txmax)
            {
                txmax = tymax;
            }
            return((txmax > Fix64.Zero) && (txmin < ray.distance));
        }
   public void CircleCast(
 ref VoltRayCast ray,
 float radius,
 VoltBuffer<VoltBody> outBuffer)
   {
       outBuffer.Add(this.bodies, this.count);
   }
Beispiel #4
0
        /// <summary>
        /// Performs a circle cast on all world bodies.
        /// </summary>
        public bool CircleCast(
            ref VoltRayCast ray,
            Fix64 radius,
            ref VoltRayResult result,
            VoltBodyFilter filter = null,
            int ticksBehind       = 0)
        {
            if (ticksBehind < 0)
            {
                throw new ArgumentOutOfRangeException("ticksBehind");
            }

            this.reusableBuffer.Clear();
            this.staticBroadphase.CircleCast(ref ray, radius, this.reusableBuffer);
            this.dynamicBroadphase.CircleCast(ref ray, radius, this.reusableBuffer);

            for (int i = 0; i < this.reusableBuffer.Count; i++)
            {
                VoltBody body = this.reusableBuffer[i];
                if (VoltBody.Filter(body, filter))
                {
                    body.CircleCast(ref ray, radius, ref result, ticksBehind);
                    if (result.IsContained)
                    {
                        return(true);
                    }
                }
            }
            return(result.IsValid);
        }
Beispiel #5
0
 internal VoltRayCast WorldToBodyRay(ref VoltRayCast rayCast)
 {
     return new VoltRayCast(
     this.WorldToBodyPoint(rayCast.origin),
     this.WorldToBodyDirection(rayCast.direction),
     rayCast.distance);
 }
Beispiel #6
0
 public void CircleCast(
     ref VoltRayCast ray,
     float radius,
     VoltBuffer <VoltBody> outBuffer)
 {
     outBuffer.Add(this.bodies, this.count);
 }
Beispiel #7
0
    void OnDrawGizmos()
    {
        VolatileWorld world = VolatileWorld.Instance;
        if ((world != null) && (Application.isPlaying == true))
        {
          VoltRayResult result = new VoltRayResult();
          VoltRayCast cast =
        new VoltRayCast(
          transform.position,
          transform.position + (transform.up * 100.0f));

          if (this.radius > 0.0f)
        world.World.CircleCast(ref cast, this.radius, ref result, this.Filter, -this.frameOffset);
          else
        world.World.RayCast(ref cast, ref result, this.Filter, -this.frameOffset);

          float drawRadius = (this.radius == 0.0f) ? 0.2f : this.radius;
          Gizmos.color = this.color;
          if (result.IsValid == true)
          {
        Vector2 point = transform.position + (transform.up * result.Distance);
        Gizmos.DrawLine(transform.position, point);
        Gizmos.DrawWireSphere(point,drawRadius);
          }
          else
          {
        Gizmos.DrawLine(transform.position, transform.position + (transform.up * 100.0f));
          }
        }
    }
Beispiel #8
0
        /// <summary>
        /// A cheap ray test that requires some precomputed information.
        /// Adapted from: http://www.cs.utah.edu/~awilliam/box/box.pdf
        /// </summary>
        private static bool RayCast(
            ref VoltRayCast ray,
            float top,
            float bottom,
            float left,
            float right)
        {
            float txmin =
                ((ray.signX ? right : left) - ray.origin.x) *
                ray.invDirection.x;
            float txmax =
                ((ray.signX ? left : right) - ray.origin.x) *
                ray.invDirection.x;

            float tymin =
                ((ray.signY ? top : bottom) - ray.origin.y) *
                ray.invDirection.y;
            float tymax =
                ((ray.signY ? bottom : top) - ray.origin.y) *
                ray.invDirection.y;

            if ((txmin > tymax) || (tymin > txmax))
            {
                return(false);
            }
            if (tymin > txmin)
            {
                txmin = tymin;
            }
            if (tymax < txmax)
            {
                txmax = tymax;
            }
            return((txmax > 0.0f) && (txmin < ray.distance));
        }
Beispiel #9
0
 internal VoltRayCast WorldToBodyRay(ref VoltRayCast rayCast)
 {
     return(new VoltRayCast(
                this.WorldToBodyPoint(rayCast.origin),
                this.WorldToBodyDirection(rayCast.direction),
                rayCast.distance));
 }
Beispiel #10
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;
        }
Beispiel #11
0
 private void ExplosionCallback(
 VoltRayCast rayCast,
 VoltRayResult rayResult,
 float rayWeight)
 {
     Vector2 point = rayResult.ComputePoint(ref rayCast);
     this.hits.Add(point);
 }
Beispiel #12
0
 /// <summary>
 /// Note: This doesn't take rounded edges into account.
 /// </summary>
 public bool CircleCastApprox(ref VoltRayCast ray, float radius)
 {
     return(VoltAABB.RayCast(
                ref ray,
                this.top + radius,
                this.bottom - radius,
                this.left - radius,
                this.right + radius));
 }
Beispiel #13
0
 public bool RayCast(ref VoltRayCast ray)
 {
     return(VoltAABB.RayCast(
                ref ray,
                this.top,
                this.bottom,
                this.left,
                this.right));
 }
Beispiel #14
0
 protected override bool ShapeRayCast(
     ref VoltRayCast bodySpaceRay,
     ref VoltRayResult result)
 {
     return(Collision.CircleRayCast(
                this,
                this.bodySpaceOrigin,
                this.sqrRadius,
                ref bodySpaceRay,
                ref result));
 }
Beispiel #15
0
 /// <summary>
 /// Performs a raycast check on this shape.
 /// Begins with an AABB check.
 /// </summary>
 internal bool RayCast(
     ref VoltRayCast bodySpaceRay,
     ref VoltRayResult result)
 {
     // Queries and casts on shapes are always done in body space
     if (this.bodySpaceAABB.RayCast(ref bodySpaceRay))
     {
         return(this.ShapeRayCast(ref bodySpaceRay, ref result));
     }
     return(false);
 }
Beispiel #16
0
 /// <summary>
 /// Performs a circlecast check on this shape.
 /// Begins with an AABB check.
 /// </summary>
 internal bool CircleCast(
     ref VoltRayCast bodySpaceRay,
     float radius,
     ref VoltRayResult result)
 {
     // Queries and casts on shapes are always done in body space
     if (this.bodySpaceAABB.CircleCastApprox(ref bodySpaceRay, radius))
     {
         return(this.ShapeCircleCast(ref bodySpaceRay, radius, ref result));
     }
     return(false);
 }
 public void RayCast(
     ref VoltRayCast ray,
     VoltBuffer <VoltBody> outBuffer)
 {
     this.StartQuery(outBuffer);
     while (this.queryStack.Count > 0)
     {
         Node node = this.GetNextNode();
         if (node.aabb.RayCast(ref ray))
         {
             this.ExpandNode(node, outBuffer);
         }
     }
 }
Beispiel #18
0
        protected override bool ShapeCircleCast(
            ref VoltRayCast bodySpaceRay,
            float radius,
            ref VoltRayResult result)
        {
            float totalRadius = this.radius + radius;

            return(Collision.CircleRayCast(
                       this,
                       this.bodySpaceOrigin,
                       totalRadius * totalRadius,
                       ref bodySpaceRay,
                       ref result));
        }
 public void CircleCast(
     ref VoltRayCast ray,
     Fix64 radius,
     VoltBuffer <VoltBody> outBuffer)
 {
     this.StartQuery(outBuffer);
     while (this.queryStack.Count > 0)
     {
         Node node = this.GetNextNode();
         if (node.aabb.CircleCastApprox(ref ray, radius))
         {
             this.ExpandNode(node, outBuffer);
         }
     }
 }
Beispiel #20
0
        public void PerformExplosion(
            TSVector2 origin,
            FP radius,
            VoltExplosionCallback callback,
            VoltBodyFilter targetFilter    = null,
            VoltBodyFilter occlusionFilter = null,
            int ticksBehind = 0,
            int rayCount    = 32)
        {
            if (ticksBehind < 0)
            {
                throw new ArgumentOutOfRangeException("ticksBehind");
            }

            // Get all target bodies
            this.PopulateFiltered(
                origin,
                radius,
                targetFilter,
                ticksBehind,
                ref this.targetBodies);

            // Get all occluding bodies
            this.PopulateFiltered(
                origin,
                radius,
                occlusionFilter,
                ticksBehind,
                ref this.occludingBodies);

            VoltRayCast ray;
            FP          rayWeight      = 1.0f / rayCount;
            FP          angleIncrement = (TSMath.Pi * 2.0f) * rayWeight;

            for (int i = 0; i < rayCount; i++)
            {
                TSVector2 normal = VoltMath.Polar(angleIncrement * i);
                ray = new VoltRayCast(origin, normal, radius);

                FP minDistance =
                    this.GetOccludingDistance(ray, ticksBehind);
                minDistance += VoltWorld.EXPLOSION_OCCLUDER_SLOP;

                this.TestTargets(ray, callback, ticksBehind, minDistance, rayWeight);
            }
        }
Beispiel #21
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);
        }
Beispiel #22
0
        protected override bool ShapeCircleCast(
            ref VoltRayCast bodySpaceRay,
            float radius,
            ref VoltRayResult result)
        {
            bool checkVertices =
                this.CircleCastVertices(
                    ref bodySpaceRay,
                    radius,
                    ref result);

            bool checkEdges =
                this.CircleCastEdges(
                    ref bodySpaceRay,
                    radius,
                    ref result);

            // We need to check both to get the closest hit distance
            return(checkVertices || checkEdges);
        }
Beispiel #23
0
        /// <summary>
        /// Tests all valid explosion targets for a given ray.
        /// </summary>
        private void TestTargets(
            VoltRayCast ray,
            VoltExplosionCallback callback,
            int ticksBehind,
            FP minOccluderDistance,
            FP rayWeight)
        {
            for (int i = 0; i < this.targetBodies.Count; i++)
            {
                VoltBody      targetBody = this.targetBodies[i];
                VoltRayResult result     = default(VoltRayResult);

                if (targetBody.RayCast(ref ray, ref result, ticksBehind))
                {
                    if (result.Distance < minOccluderDistance)
                    {
                        callback.Invoke(ray, result, rayWeight);
                    }
                }
            }
        }
Beispiel #24
0
        /// <summary>
        /// Gets the distance to the closest occluder for the given ray.
        /// </summary>
        private FP GetOccludingDistance(
            VoltRayCast ray,
            int ticksBehind)
        {
            FP            distance = FP.MaxValue;
            VoltRayResult result   = default(VoltRayResult);

            for (int i = 0; i < this.occludingBodies.Count; i++)
            {
                if (this.occludingBodies[i].RayCast(ref ray, ref result, ticksBehind))
                {
                    distance = result.Distance;
                }
                if (result.IsContained)
                {
                    break;
                }
            }

            return(distance);
        }
Beispiel #25
0
        /// <summary>
        /// Performs a circle cast check on this body.
        /// Begins with AABB checks.
        /// </summary>
        internal bool CircleCast(
            ref VoltRayCast ray,
            FP radius,
            ref VoltRayResult result,
            int ticksBehind,
            bool bypassAABB = false)
        {
            HistoryRecord record = this.GetState(ticksBehind);

            // AABB check done in world space (because it keeps changing)
            if (bypassAABB == false)
            {
                if (record.aabb.CircleCastApprox(ref ray, radius) == false)
                {
                    return(false);
                }
            }

            // Actual tests on shapes done in body space
            VoltRayCast bodySpaceRay = record.WorldToBodyRay(ref ray);

            for (int i = 0; i < this.shapeCount; i++)
            {
                if (this.shapes[i].CircleCast(ref bodySpaceRay, radius, ref result))
                {
                    if (result.IsContained)
                    {
                        return(true);
                    }
                }
            }

            // We need to convert the results back to world space to be any use
            // (Doesn't matter if we were contained since there will be no normal)
            if (result.Body == this)
            {
                result.normal = record.BodyToWorldDirection(result.normal);
            }
            return(result.IsValid);
        }
Beispiel #26
0
 protected abstract bool ShapeCircleCast(
     ref VoltRayCast bodySpaceRay,
     float radius,
     ref VoltRayResult result);
Beispiel #27
0
        public void PerformExplosion(
      Vector2 origin,
      float radius,
      VoltExplosionCallback callback,
      VoltBodyFilter targetFilter = null,
      VoltBodyFilter occlusionFilter = null,
      int ticksBehind = 0,
      int rayCount = 32)
        {
            if (ticksBehind < 0)
            throw new ArgumentOutOfRangeException("ticksBehind");

              // Get all target bodies
              this.PopulateFiltered(
            origin,
            radius,
            targetFilter,
            ticksBehind,
            ref this.targetBodies);

              // Get all occluding bodies
              this.PopulateFiltered(
            origin,
            radius,
            occlusionFilter,
            ticksBehind,
            ref this.occludingBodies);

              VoltRayCast ray;
              float rayWeight = 1.0f / rayCount;
              float angleIncrement = (Mathf.PI * 2.0f) * rayWeight;

              for (int i = 0; i < rayCount; i++)
              {
            Vector2 normal = VoltMath.Polar(angleIncrement * i);
            ray = new VoltRayCast(origin, normal, radius);

            float minDistance =
              this.GetOccludingDistance(ray, ticksBehind);
            minDistance += VoltWorld.EXPLOSION_OCCLUDER_SLOP;

            this.TestTargets(ray, callback, ticksBehind, minDistance, rayWeight);
              }
        }
Beispiel #28
0
        protected override bool ShapeCircleCast(
      ref VoltRayCast bodySpaceRay,
      float radius,
      ref VoltRayResult result)
        {
            bool checkVertices =
            this.CircleCastVertices(
              ref bodySpaceRay,
              radius,
              ref result);

              bool checkEdges =
            this.CircleCastEdges(
              ref bodySpaceRay,
              radius,
              ref result);

              // We need to check both to get the closest hit distance
              return checkVertices || checkEdges;
        }
Beispiel #29
0
 protected abstract bool ShapeRayCast(
     ref VoltRayCast bodySpaceRay,
     ref VoltRayResult result);
Beispiel #30
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);
        }
Beispiel #31
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;
        }
Beispiel #32
0
 public Vector2 ComputePoint(ref VoltRayCast cast)
 {
     return cast.origin + (cast.direction * this.distance);
 }
Beispiel #33
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);
        }
Beispiel #34
0
 /// <summary>
 /// Note: This doesn't take rounded edges into account.
 /// </summary>
 public bool CircleCastApprox(ref VoltRayCast ray, float radius)
 {
     return VoltAABB.RayCast(
     ref ray,
     this.top + radius,
     this.bottom - radius,
     this.left - radius,
     this.right + radius);
 }
Beispiel #35
0
        /// <summary>
        /// Performs a raycast on all world bodies.
        /// </summary>
        public bool RayCast(
      ref VoltRayCast ray,
      ref VoltRayResult result,
      VoltBodyFilter filter = null,
      int ticksBehind = 0)
        {
            if (ticksBehind < 0)
            throw new ArgumentOutOfRangeException("ticksBehind");

              this.reusableBuffer.Clear();
              this.staticBroadphase.RayCast(ref ray, this.reusableBuffer);
              this.dynamicBroadphase.RayCast(ref ray, this.reusableBuffer);

              for (int i = 0; i < this.reusableBuffer.Count; i++)
              {
            VoltBody body = this.reusableBuffer[i];
            if (VoltBody.Filter(body, filter))
            {
              body.RayCast(ref ray, ref result, ticksBehind);
              if (result.IsContained)
            return true;
            }
              }

              return result.IsValid;
        }
Beispiel #36
0
 public void RayCast(
     ref VoltRayCast ray,
     VoltBuffer <VoltBody> outBuffer)
 {
     outBuffer.Add(this.bodies, this.count);
 }
Beispiel #37
0
 public bool RayCast(ref VoltRayCast ray)
 {
     return VoltAABB.RayCast(
     ref ray,
     this.top,
     this.bottom,
     this.left,
     this.right);
 }
Beispiel #38
0
        /// <summary>
        /// A cheap ray test that requires some precomputed information.
        /// Adapted from: http://www.cs.utah.edu/~awilliam/box/box.pdf
        /// </summary>
        private static bool RayCast(
      ref VoltRayCast ray,
      float top,
      float bottom,
      float left,
      float right)
        {
            float txmin =
            ((ray.signX ? right : left) - ray.origin.x) *
            ray.invDirection.x;
              float txmax =
            ((ray.signX ? left : right) - ray.origin.x) *
            ray.invDirection.x;

              float tymin =
            ((ray.signY ? top : bottom) - ray.origin.y) *
            ray.invDirection.y;
              float tymax =
            ((ray.signY ? bottom : top) - ray.origin.y) *
            ray.invDirection.y;

              if ((txmin > tymax) || (tymin > txmax))
            return false;
              if (tymin > txmin)
            txmin = tymin;
              if (tymax < txmax)
            txmax = tymax;
              return (txmax > 0.0f) && (txmin < ray.distance);
        }
   public void RayCast(
 ref VoltRayCast ray,
 VoltBuffer<VoltBody> outBuffer)
   {
       outBuffer.Add(this.bodies, this.count);
   }
Beispiel #40
0
        private bool CircleCastVertices(
      ref VoltRayCast bodySpaceRay,
      float radius,
      ref VoltRayResult result)
        {
            float sqrRadius = radius * radius;
              bool castHit = false;

              for (int i = 0; i < this.countBody; i++)
              {
            castHit |=
              Collision.CircleRayCast(
            this,
            this.bodyVertices[i],
            sqrRadius,
            ref bodySpaceRay,
            ref result);
            if (result.IsContained == true)
              return true;
              }

              return castHit;
        }
Beispiel #41
0
        /// <summary>
        /// Tests all valid explosion targets for a given ray.
        /// </summary>
        private void TestTargets(
      VoltRayCast ray,
      VoltExplosionCallback callback,
      int ticksBehind,
      float minOccluderDistance,
      float rayWeight)
        {
            for (int i = 0; i < this.targetBodies.Count; i++)
              {
            VoltBody targetBody = this.targetBodies[i];
            VoltRayResult result = default(VoltRayResult);

            if (targetBody.RayCast(ref ray, ref result, ticksBehind))
              if (result.Distance < minOccluderDistance)
            callback.Invoke(ray, result, rayWeight);
              }
        }
Beispiel #42
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;
        }
Beispiel #43
0
   public void CircleCast(
 ref VoltRayCast ray, 
 float radius,
 VoltBuffer<VoltBody> outBuffer)
   {
       this.StartQuery(outBuffer);
         while (this.queryStack.Count > 0)
         {
       Node node = this.GetNextNode();
       if (node.aabb.CircleCastApprox(ref ray, radius))
         this.ExpandNode(node, outBuffer);
         }
   }
Beispiel #44
0
        /// <summary>
        /// Gets the distance to the closest occluder for the given ray.
        /// </summary>
        private float GetOccludingDistance(
      VoltRayCast ray,
      int ticksBehind)
        {
            float distance = float.MaxValue;
              VoltRayResult result = default(VoltRayResult);

              for (int i = 0; i < this.occludingBodies.Count; i++)
              {
            if (this.occludingBodies[i].RayCast(ref ray, ref result, ticksBehind))
              distance = result.Distance;
            if (result.IsContained)
              break;
              }

              return distance;
        }
Beispiel #45
0
 public VoltVector2 ComputePoint(ref VoltRayCast cast)
 {
     return(cast.origin + (cast.direction * this.distance));
 }
Beispiel #46
0
   public void RayCast(
 ref VoltRayCast ray,
 VoltBuffer<VoltBody> outBuffer)
   {
       this.StartQuery(outBuffer);
         while (this.queryStack.Count > 0)
         {
       Node node = this.GetNextNode();
       if (node.aabb.RayCast(ref ray))
         this.ExpandNode(node, outBuffer);
         }
   }