public static VoltVector2 WorldToBodyPoint(
     VoltVector2 bodyPosition,
     VoltVector2 bodyFacing,
     VoltVector2 vector)
 {
     return((vector - bodyPosition).InvRotate(bodyFacing));
 }
Esempio n. 2
0
        internal Axis BodyToWorldAxis(Axis axis)
        {
            VoltVector2 normal = axis.Normal.Rotate(this.facing);
            Fix64       width  = VoltVector2.Dot(normal, this.position) + axis.Width;

            return(new Axis(normal, width));
        }
 public static VoltVector2 BodyToWorldPoint(
     VoltVector2 bodyPosition,
     VoltVector2 bodyFacing,
     VoltVector2 vector)
 {
     return(vector.Rotate(bodyFacing) + bodyPosition);
 }
Esempio n. 4
0
        public static VoltAABB CreateSwept(VoltAABB source, VoltVector2 vector)
        {
            Fix64 top    = source.top;
            Fix64 bottom = source.bottom;
            Fix64 left   = source.left;
            Fix64 right  = source.right;

            if (vector.x < Fix64.Zero)
            {
                left += vector.x;
            }
            else
            {
                right += vector.x;
            }

            if (vector.y < Fix64.Zero)
            {
                bottom += vector.y;
            }
            else
            {
                top += vector.y;
            }

            return(new VoltAABB(top, bottom, left, right));
        }
        /// <summary>
        /// Returns the index of the axis with the max circle penetration depth.
        /// Breaks out if a separating axis is found between the two shapes.
        /// Outputs the penetration depth of the circle in the axis (if any).
        /// </summary>
        internal static int FindAxisMaxPenetration(
            VoltVector2 origin,
            Fix64 radius,
            VoltPolygon poly,
            out Fix64 penetration)
        {
            int index = 0;
            int found = 0;

            penetration = Fix64.MinValue;

            for (int i = 0; i < poly.countWorld; i++)
            {
                Axis  axis = poly.worldAxes[i];
                Fix64 dot  = VoltVector2.Dot(axis.Normal, origin);
                Fix64 dist = dot - axis.Width - radius;

                if (dist > Fix64.Zero)
                {
                    return(-1);
                }

                if (dist > penetration)
                {
                    penetration = dist;
                    found       = index;
                }

                index++;
            }

            return(found);
        }
Esempio n. 6
0
        /// <summary>
        /// Finds all bodies intersecting with a given circle.
        ///
        /// Subsequent calls to other Query functions (Point, Circle, Bounds) will
        /// invalidate the resulting enumeration from this function.
        /// </summary>
        public VoltBuffer <VoltBody> QueryCircle(
            VoltVector2 origin,
            Fix64 radius,
            VoltBodyFilter filter = null,
            int ticksBehind       = 0)
        {
            if (ticksBehind < 0)
            {
                throw new ArgumentOutOfRangeException("ticksBehind");
            }

            this.reusableBuffer.Clear();
            this.staticBroadphase.QueryCircle(origin, radius, this.reusableBuffer);
            this.dynamicBroadphase.QueryCircle(origin, radius, this.reusableBuffer);

            this.reusableOutput.Clear();
            for (int i = 0; i < this.reusableBuffer.Count; i++)
            {
                VoltBody body = this.reusableBuffer[i];
                if (VoltBody.Filter(body, filter))
                {
                    if (body.QueryCircle(origin, radius, ticksBehind))
                    {
                        this.reusableOutput.Add(body);
                    }
                }
            }

            return(this.reusableOutput);
        }
        private static bool FindMinSepAxis(
            VoltPolygon poly1,
            VoltPolygon poly2,
            out Axis axis)
        {
            axis = new Axis(VoltVector2.zero, Fix64.MinValue);

            for (int i = 0; i < poly1.countWorld; i++)
            {
                Axis  a   = poly1.worldAxes[i];
                Fix64 min = Fix64.MaxValue;
                for (int j = 0; j < poly2.countWorld; j++)
                {
                    VoltVector2 v = poly2.worldVertices[j];
                    min = VoltMath.Min(min, VoltVector2.Dot(a.Normal, v));
                }
                min -= a.Width;

                if (min > Fix64.Zero)
                {
                    return(false);
                }
                if (min > axis.Width)
                {
                    axis = new Axis(a.Normal, min);
                }
            }

            return(true);
        }
Esempio n. 8
0
 public void SetForce(VoltVector2 force, Fix64 torque, VoltVector2 biasVelocity, Fix64 biasRotation)
 {
     this.Force        = force;
     this.Torque       = torque;
     this.BiasVelocity = biasVelocity;
     this.BiasRotation = biasRotation;
 }
Esempio n. 9
0
        /// <summary>
        /// Checks if a point is contained in this body.
        /// Begins with AABB checks unless bypassed.
        /// </summary>
        internal bool QueryPoint(
            VoltVector2 point,
            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.QueryPoint(point) == false)
                {
                    return(false);
                }
            }

            // Actual query on shapes done in body space
            VoltVector2 bodySpacePoint = record.WorldToBodyPoint(point);

            for (int i = 0; i < this.shapeCount; i++)
            {
                if (this.shapes[i].QueryPoint(bodySpacePoint))
                {
                    return(true);
                }
            }
            return(false);
        }
        /// <summary>
        /// Workhorse for circle-circle collisions, compares origin distance
        /// to the sum of the two circles' radii, returns a Manifold.
        /// </summary>
        ///
        private static Manifold TestCircles(
            VoltWorld world,
            VoltCircle shapeA,
            VoltShape shapeB,
            VoltVector2 overrideBCenter, // For testing vertices in circles
            Fix64 overrideBRadius)
        {
            VoltVector2 r      = overrideBCenter - shapeA.worldSpaceOrigin;
            Fix64       min    = shapeA.radius + overrideBRadius;
            Fix64       distSq = r.sqrMagnitude;

            if (distSq >= min * min)
            {
                return(null);
            }

            Fix64 dist = VoltMath.Sqrt(distSq);

            // 최소값을 지정하여 divide by zero 방지
            Fix64 distInv = Fix64.One / VoltMath.Max(dist, min / (Fix64)10);

            VoltVector2 pos =
                shapeA.worldSpaceOrigin +
                (Fix64.One / (Fix64)2 + distInv * (shapeA.radius - min / (Fix64)2)) * r;

            // Build the collision Manifold
            Manifold manifold =
                world.AllocateManifold().Assign(world, shapeA, shapeB);

            manifold.AddContact(pos, distInv * r, dist - min);
            return(manifold);
        }
        /// <summary>
        /// Returns the index of the nearest axis on the poly to a point.
        /// Outputs the minimum distance between the axis and the point.
        /// </summary>
        internal static int FindAxisShortestDistance(
            VoltVector2 point,
            Axis[] axes,
            out Fix64 minDistance)
        {
            int ix = 0;

            minDistance = Fix64.MaxValue;
            bool inside = true;

            for (int i = 0; i < axes.Length; i++)
            {
                Fix64 dot  = VoltVector2.Dot(axes[i].Normal, point);
                Fix64 dist = axes[i].Width - dot;

                if (dist < Fix64.Zero)
                {
                    inside = false;
                }

                if (dist < minDistance)
                {
                    minDistance = dist;
                    ix          = i;
                }
            }

            if (inside == true)
            {
                minDistance = Fix64.Zero;
                ix          = -1;
            }

            return(ix);
        }
Esempio n. 12
0
        /// <summary>
        /// Finds all dynamic bodies that overlap with the explosion AABB
        /// and pass the target filter test. Does not test actual shapes.
        /// </summary>
        private void PopulateFiltered(
            VoltVector2 origin,
            Fix64 radius,
            VoltBodyFilter targetFilter,
            int ticksBehind,
            ref VoltBuffer <VoltBody> filterBuffer)
        {
            if (filterBuffer == null)
            {
                filterBuffer = new VoltBuffer <VoltBody>();
            }
            filterBuffer.Clear();

            this.reusableBuffer.Clear();
            this.staticBroadphase.QueryCircle(origin, radius, this.reusableBuffer);
            this.dynamicBroadphase.QueryCircle(origin, radius, this.reusableBuffer);

            VoltAABB aabb = new VoltAABB(origin, radius);

            for (int i = 0; i < this.reusableBuffer.Count; i++)
            {
                VoltBody body = this.reusableBuffer[i];
                if ((targetFilter == null) || targetFilter.Invoke(body))
                {
                    if (body.QueryAABBOnly(aabb, ticksBehind))
                    {
                        filterBuffer.Add(body);
                    }
                }
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Checks if a circle overlaps with this body.
        /// Begins with AABB checks.
        /// </summary>
        internal bool QueryCircle(
            VoltVector2 origin,
            Fix64 radius,
            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.QueryCircleApprox(origin, radius) == false)
                {
                    return(false);
                }
            }

            // Actual query on shapes done in body space
            VoltVector2 bodySpaceOrigin = record.WorldToBodyPoint(origin);

            for (int i = 0; i < this.shapeCount; i++)
            {
                if (this.shapes[i].QueryCircle(bodySpaceOrigin, radius))
                {
                    return(true);
                }
            }
            return(false);
        }
 public void QueryCircle(
     VoltVector2 point,
     Fix64 radius,
     VoltBuffer <VoltBody> outBuffer)
 {
     outBuffer.Add(this.bodies, this.count);
 }
Esempio n. 15
0
        private void Initialize(
            VoltVector2 position,
            Fix64 radians,
            VoltShape[] shapesToAdd)
        {
            this.Position = position;
            this.Angle    = radians;
            this.Facing   = VoltMath.Polar(radians);

#if DEBUG
            for (int i = 0; i < shapesToAdd.Length; i++)
            {
                VoltDebug.Assert(shapesToAdd[i].IsInitialized);
            }
#endif

            if ((this.shapes == null) || (this.shapes.Length < shapesToAdd.Length))
            {
                this.shapes = new VoltShape[shapesToAdd.Length];
            }
            Array.Copy(shapesToAdd, this.shapes, shapesToAdd.Length);
            this.shapeCount = shapesToAdd.Length;
            for (int i = 0; i < this.shapeCount; i++)
            {
                this.shapes[i].AssignBody(this);
            }

#if DEBUG
            this.IsInitialized = true;
#endif
        }
Esempio n. 16
0
        /// <summary>
        /// Tries to get a reference frame for a given number of ticks behind
        /// the current tick. Returns true if a value was found, false if a
        /// value was not found (in which case we clamp to the nearest).
        /// </summary>
        public bool TryGetSpace(
            int ticksBehind,
            out VoltVector2 position,
            out VoltVector2 facing)
        {
            if (ticksBehind < 0)
            {
                throw new ArgumentOutOfRangeException("ticksBehind");
            }

            if (ticksBehind == 0)
            {
                position = this.Position;
                facing   = this.Facing;
                return(true);
            }

            if (this.history == null)
            {
                position = this.Position;
                facing   = this.Facing;
                return(false);
            }

            HistoryRecord record;
            bool          found = this.history.TryGet(ticksBehind - 1, out record);

            position = record.position;
            facing   = record.facing;
            return(found);
        }
Esempio n. 17
0
 public void Set(VoltVector2 position, Fix64 radians)
 {
     this.Position = position;
     this.Angle    = radians;
     this.Facing   = VoltMath.Polar(radians);
     this.OnPositionUpdated();
 }
        /// <summary>
        /// A fallback for handling degenerate "Star of David" cases.
        /// </summary>
        private static void FindVertsFallback(
            VoltPolygon poly1,
            VoltPolygon poly2,
            VoltVector2 normal,
            Fix64 penetration,
            Manifold manifold)
        {
            for (int i = 0; i < poly1.countWorld; i++)
            {
                VoltVector2 vertex = poly1.worldVertices[i];
                if (poly2.ContainsPointPartial(vertex, normal) == true)
                {
                    if (manifold.AddContact(vertex, normal, penetration) == false)
                    {
                        return;
                    }
                }
            }

            for (int i = 0; i < poly2.countWorld; i++)
            {
                VoltVector2 vertex = poly2.worldVertices[i];
                if (poly1.ContainsPointPartial(vertex, -normal) == true)
                {
                    if (manifold.AddContact(vertex, normal, penetration) == false)
                    {
                        return;
                    }
                }
            }
        }
Esempio n. 19
0
 /// <summary>
 /// Note: This doesn't take rounded edges into account.
 /// </summary>
 public bool QueryCircleApprox(VoltVector2 origin, Fix64 radius)
 {
     return
         ((this.left - radius) <= origin.x &&
          (this.right + radius) >= origin.x &&
          (this.bottom - radius) <= origin.y &&
          (this.top + radius) >= origin.y);
 }
Esempio n. 20
0
 /// <summary>
 /// Performs a point test on the AABB.
 /// </summary>
 public bool QueryPoint(VoltVector2 point)
 {
     return
         (this.left <= point.x &&
          this.right >= point.x &&
          this.bottom <= point.y &&
          this.top >= point.y);
 }
Esempio n. 21
0
 private void IntegrateForces(
     VoltVector2 force,
     Fix64 torque,
     Fix64 mult)
 {
     this.LinearVelocity  += this.World.DeltaTime * force * mult;
     this.AngularVelocity -= this.World.DeltaTime * torque * mult;
 }
 /// <summary>
 /// Checks if a point is contained in this shape.
 /// Begins with an AABB check.
 /// </summary>
 internal bool QueryPoint(VoltVector2 bodySpacePoint)
 {
     // Queries and casts on shapes are always done in body space
     if (this.bodySpaceAABB.QueryPoint(bodySpacePoint))
     {
         return(this.ShapeQueryPoint(bodySpacePoint));
     }
     return(false);
 }
 protected override bool ShapeQueryPoint(
     VoltVector2 bodySpacePoint)
 {
     return
         (Collision.TestPointCircleSimple(
              this.bodySpaceOrigin,
              bodySpacePoint,
              this.radius));
 }
        protected override void Reset()
        {
            base.Reset();

            this.worldSpaceOrigin = VoltVector2.zero;
            this.radius           = Fix64.Zero;
            this.sqrRadius        = Fix64.Zero;
            this.bodySpaceOrigin  = VoltVector2.zero;
        }
Esempio n. 25
0
 internal void InitializeStatic(
     VoltVector2 position,
     Fix64 radians,
     VoltShape[] shapesToAdd)
 {
     this.Initialize(position, radians, shapesToAdd);
     this.OnPositionUpdated();
     this.SetStatic();
 }
Esempio n. 26
0
 internal void InitializeDynamic(
     VoltVector2 position,
     Fix64 radians,
     VoltShape[] shapesToAdd)
 {
     this.Initialize(position, radians, shapesToAdd);
     this.OnPositionUpdated();
     this.ComputeDynamics();
 }
        /// <summary>
        /// Simple check for point-circle containment.
        /// </summary>
        internal static bool TestPointCircleSimple(
            VoltVector2 point,
            VoltVector2 origin,
            Fix64 radius)
        {
            VoltVector2 delta = origin - point;

            return(delta.sqrMagnitude <= (radius * radius));
        }
 /// <summary>
 /// Checks if a circle overlaps with this shape.
 /// Begins with an AABB check.
 /// </summary>
 internal bool QueryCircle(VoltVector2 bodySpaceOrigin, Fix64 radius)
 {
     // Queries and casts on shapes are always done in body space
     if (this.bodySpaceAABB.QueryCircleApprox(bodySpaceOrigin, radius))
     {
         return(this.ShapeQueryCircle(bodySpaceOrigin, radius));
     }
     return(false);
 }
Esempio n. 29
0
        private void ApplyNormalBiasImpulse(
            VoltBody bodyA,
            VoltBody bodyB,
            Fix64 normalBiasImpulse)
        {
            VoltVector2 impulse = normalBiasImpulse * this.normal;

            bodyA.ApplyBias(-impulse, this.toA);
            bodyB.ApplyBias(impulse, this.toB);
        }
        /// <summary>
        /// Simple check for two overlapping circles.
        /// </summary>
        internal static bool TestCircleCircleSimple(
            VoltVector2 originA,
            VoltVector2 originB,
            Fix64 radiusA,
            Fix64 radiusB)
        {
            Fix64 radiusTotal = radiusA + radiusB;

            return((originA - originB).sqrMagnitude <= (radiusTotal * radiusTotal));
        }