Ejemplo n.º 1
0
        static bool collidePolygonCircle(PolygonShape polygon, ref FSTransform polyTransform, CircleShape circle, ref FSTransform circleTransform, out FSCollisionResult result)
        {
            result = new FSCollisionResult();
            Collision.collidePolygonAndCircle(ref _manifold, polygon, ref polyTransform, circle, ref circleTransform);
            if (_manifold.pointCount > 0)
            {
                FixedArray2 <Vector2> points;
                ContactSolver.WorldManifold.initialize(ref _manifold, ref polyTransform, polygon.radius, ref circleTransform, circle.radius, out result.normal, out points);

                //var circleInPolySpace = polygonFixture.Body.GetLocalPoint( circleFixture.Body.Position );
                var circleInPolySpace = MathUtils.mulT(ref polyTransform, circleTransform.p);
                var value1            = circleInPolySpace - _manifold.localPoint;
                var value2            = _manifold.localNormal;
                var separation        = circle.radius - (value1.X * value2.X + value1.Y * value2.Y);

                if (separation <= 0)
                {
                    return(false);
                }

                result.point = points[0] * FSConvert.simToDisplay;
                result.minimumTranslationVector = result.normal * separation;

                                #if DEBUG_FSCOLLISIONS
                Debug.drawPixel(result.point, 2, Color.Red, 0.2f);
                Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f);
                                #endif

                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        static bool collideCircles(CircleShape circleA, ref FSTransform firstTransform, CircleShape circleB, ref FSTransform secondTransform, out FSCollisionResult result)
        {
            result = new FSCollisionResult();
            Collision.collideCircles(ref _manifold, circleA, ref firstTransform, circleB, ref secondTransform);
            if (_manifold.pointCount > 0)
            {
                // this is essentically directly from ContactSolver.WorldManifold.Initialize. To avoid doing the extra math twice we duplicate this code
                // here because it doesnt return some values we need to calculate separation
                var pointA = MathUtils.mul(ref firstTransform, _manifold.localPoint);
                var pointB = MathUtils.mul(ref secondTransform, _manifold.points[0].localPoint);

                result.normal = pointA - pointB;
                result.normal.Normalize();

                var cA = pointA - circleA.radius * result.normal;
                var cB = pointB + circleB.radius * result.normal;
                result.point  = 0.5f * (cA + cB);
                result.point *= FSConvert.simToDisplay;

                var separation = Vector2.Dot(pointA - pointB, result.normal) - circleA.radius - circleB.radius;
                result.minimumTranslationVector = result.normal * Math.Abs(separation);

                                #if DEBUG_FSCOLLISIONS
                Debug.drawPixel(result.point, 5, Color.Red, 0.2f);
                Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f);
                                #endif

                return(true);
            }

            return(false);
        }
Ejemplo n.º 3
0
        static bool CollidePolygons(PolygonShape polygonA, ref FSTransform transformA, PolygonShape polygonB,
                                    ref FSTransform transformB, out FSCollisionResult result)
        {
            result = new FSCollisionResult();

            Collision.CollidePolygons(ref _manifold, polygonA as PolygonShape, ref transformA, polygonB as PolygonShape,
                                      ref transformB);
            if (_manifold.PointCount > 0)
            {
                FixedArray2 <Vector2> points;
                ContactSolver.WorldManifold.Initialize(ref _manifold, ref transformA, polygonA.Radius, ref transformB,
                                                       polygonB.Radius, out result.Normal, out points);

                // code adapted from PositionSolverManifold.Initialize
                if (_manifold.Type == ManifoldType.FaceA)
                {
                    result.Normal = MathUtils.Mul(transformA.Q, _manifold.LocalNormal);
                    var planePoint = MathUtils.Mul(ref transformA, _manifold.LocalPoint);

                    var clipPoint  = MathUtils.Mul(ref transformB, _manifold.Points[0].LocalPoint);
                    var separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - polygonA.Radius -
                                     polygonB.Radius;
                    result.Point = clipPoint * FSConvert.SimToDisplay;

                    // Ensure normal points from A to B
                    Vector2.Negate(ref result.Normal, out result.Normal);

                    result.MinimumTranslationVector = result.Normal * -separation;
                }
                else
                {
                    result.Normal = MathUtils.Mul(transformB.Q, _manifold.LocalNormal);
                    var planePoint = MathUtils.Mul(ref transformB, _manifold.LocalPoint);

                    var clipPoint  = MathUtils.Mul(ref transformA, _manifold.Points[0].LocalPoint);
                    var separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - polygonA.Radius -
                                     polygonB.Radius;
                    result.Point = clipPoint * FSConvert.SimToDisplay;

                    result.MinimumTranslationVector = result.Normal * -separation;
                }

#if DEBUG_FSCOLLISIONS
                Debug.drawPixel(result.point, 2, Color.Red, 0.2f);
                Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f);
#endif

                return(true);
            }

            return(false);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// checks for collisions between two Fixtures. Note that the first Fixture must have a Circle/PolygonShape and one of the Fixtures must be
        /// static.
        /// </summary>
        /// <returns><c>true</c>, if shapes was collided, <c>false</c> otherwise.</returns>
        /// <param name="fixtureA">Fixture a.</param>
        /// <param name="fixtureB">Fixture b.</param>
        /// <param name="result">Result.</param>
        public static bool collideFixtures(Fixture fixtureA, Fixture fixtureB, out FSCollisionResult result)
        {
            // gather our transforms
            FSTransform transformA;

            fixtureA.body.getTransform(out transformA);

            FSTransform transformB;

            fixtureB.body.getTransform(out transformB);

            return(collideFixtures(fixtureA, ref transformA, fixtureB, ref transformB, out result));
        }
Ejemplo n.º 5
0
        static bool CollideEdgeAndCircle(EdgeShape edge, ref FSTransform edgeTransform, CircleShape circle,
                                         ref FSTransform circleTransform, out FSCollisionResult result)
        {
            result = new FSCollisionResult();
            Collision.CollideEdgeAndCircle(ref _manifold, edge, ref edgeTransform, circle, ref circleTransform);
            if (_manifold.PointCount > 0)
            {
                // code adapted from PositionSolverManifold.Initialize
                if (_manifold.Type == ManifoldType.Circles)
                {
                    // this is essentically directly from ContactSolver.WorldManifold.Initialize. To avoid doing the extra math twice we duplicate this code
                    // here because it doesnt return some values we need to calculate separation
                    var pointA = MathUtils.Mul(ref edgeTransform, _manifold.LocalPoint);
                    var pointB = MathUtils.Mul(ref circleTransform, _manifold.Points[0].LocalPoint);

                    result.Normal = pointA - pointB;
                    Vector2Ext.Normalize(ref result.Normal);

                    var cA = pointA - edge.Radius * result.Normal;
                    var cB = pointB + circle.Radius * result.Normal;
                    result.Point  = 0.5f * (cA + cB);
                    result.Point *= FSConvert.SimToDisplay;

                    var separation = Vector2.Dot(pointA - pointB, result.Normal) - edge.Radius - circle.Radius;

                    // Ensure normal points from A to B
                    Vector2.Negate(ref result.Normal, out result.Normal);
                    result.MinimumTranslationVector = result.Normal * Math.Abs(separation);
                }
                else                 // FaceA
                {
                    result.Normal = MathUtils.Mul(edgeTransform.Q, _manifold.LocalNormal);
                    var planePoint = MathUtils.Mul(ref edgeTransform, _manifold.LocalPoint);

                    var clipPoint  = MathUtils.Mul(ref circleTransform, _manifold.Points[0].LocalPoint);
                    var separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - edge.Radius - circle.Radius;
                    result.Point = (clipPoint - result.Normal * circle.Radius) * FSConvert.SimToDisplay;

                    result.MinimumTranslationVector = result.Normal * -separation;
                }

#if DEBUG_FSCOLLISIONS
                Debug.drawPixel(result.point, 5, Color.Red, 0.2f);
                Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f);
#endif

                return(true);
            }

            return(false);
        }
Ejemplo n.º 6
0
        private static bool CollideEdgeAndPolygon(EdgeShape edge, ref FSTransform edgeTransform, PolygonShape polygon,
                                                  ref FSTransform polygonTransform, out FSCollisionResult result)
        {
            result = new FSCollisionResult();
            Collision.CollideEdgeAndPolygon(ref _manifold, edge, ref edgeTransform, polygon, ref polygonTransform);
            if (_manifold.PointCount > 0)
            {
                FixedArray2 <Vector2> points;
                ContactSolver.WorldManifold.Initialize(ref _manifold, ref edgeTransform, edge.Radius,
                                                       ref polygonTransform, polygon.Radius, out result.Normal, out points);

                // code adapted from PositionSolverManifold.Initialize
                if (_manifold.Type == ManifoldType.FaceA)
                {
                    result.Normal = MathUtils.Mul(edgeTransform.Q, _manifold.LocalNormal);
                    Vector2 planePoint = MathUtils.Mul(ref edgeTransform, _manifold.LocalPoint);

                    Vector2 clipPoint  = MathUtils.Mul(ref polygonTransform, _manifold.Points[0].LocalPoint);
                    float   separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - edge.Radius - polygon.Radius;
                    result.Point = clipPoint * FSConvert.SimToDisplay;

                    result.MinimumTranslationVector = result.Normal * -separation;
                }
                else
                {
                    result.Normal = MathUtils.Mul(polygonTransform.Q, _manifold.LocalNormal);
                    Vector2 planePoint = MathUtils.Mul(ref polygonTransform, _manifold.LocalPoint);

                    Vector2 clipPoint  = MathUtils.Mul(ref edgeTransform, _manifold.Points[0].LocalPoint);
                    float   separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - edge.Radius - polygon.Radius;
                    result.Point = clipPoint * FSConvert.SimToDisplay;

                    // Ensure normal points from A to B
                    Vector2.Negate(ref result.Normal, out result.Normal);

                    result.MinimumTranslationVector = result.Normal * -separation;
                }

#if DEBUG_FSCOLLISIONS
                Debug.drawPixel(result.point, 5, Color.Red, 0.2f);
                Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f);
#endif

                return(true);
            }

            return(false);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// checks to see if fixtureA with motion applied (delta movement vector) collides with any collider. If it does, true will be
        /// returned and result will be populated with collision data. Motion will be set to the maximum distance the Body can travel
        /// before colliding.
        /// </summary>
        /// <returns><c>true</c>, if fixtures was collided, <c>false</c> otherwise.</returns>
        /// <param name="fixtureA">Fixture a.</param>
        /// <param name="motion">delta movement in simulation space</param>
        /// <param name="fixtureB">Fixture b.</param>
        /// <param name="result">Result.</param>
        public static bool CollideFixtures(Fixture fixtureA, ref Vector2 motion, Fixture fixtureB,
                                           out FSCollisionResult result)
        {
            // gather our transforms and adjust fixtureA's transform to account for the motion so we check for the collision at its new location
            FSTransform transformA;

            fixtureA.Body.GetTransform(out transformA);
            transformA.P += motion;

            FSTransform transformB;

            fixtureB.Body.GetTransform(out transformB);

            if (CollideFixtures(fixtureA, ref transformA, fixtureB, ref transformB, out result))
            {
                motion += result.MinimumTranslationVector;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// checks to see if the Fixture with motion applied (delta movement vector) collides with any collider. If it does, true will be
        /// returned and result will be populated with collision data. motion will be set to the maximum distance the Body can travel
        /// before colliding.
        /// </summary>
        /// <returns><c>true</c>, if with any was collidesed, <c>false</c> otherwise.</returns>
        /// <param name="self">Fixture a.</param>
        /// <param name="motion">the delta movement in Nez pixel coordinates</param>
        /// <param name="result">Result.</param>
        public static bool CollidesWithAnyFixtures(this Fixture self, ref Vector2 motion, out FSCollisionResult result)
        {
            result  = new FSCollisionResult();
            motion *= FSConvert.DisplayToSim;
            AABB        aabb;
            FSTransform xf;
            var         didCollide = false;

            self.Body.GetTransform(out xf);
            xf.P += motion;
            self.Shape.ComputeAABB(out aabb, ref xf, 0);

            var neighbors = ListPool <Fixture> .Obtain();

            self.Body.World.QueryAABB(ref aabb, neighbors);
            if (neighbors.Count > 1)
            {
                // handle collisions with all but ourself
                for (var i = 0; i < neighbors.Count; i++)
                {
                    if (neighbors[i].FixtureId == self.FixtureId)
                    {
                        continue;
                    }

                    if (FSCollisions.CollideFixtures(self, ref motion, neighbors[i], out result))
                    {
                        // if we have a collision, adjust the transform to account for it
                        xf.P += result.MinimumTranslationVector;
                    }
                }
            }

            ListPool <Fixture> .Free(neighbors);

            motion *= FSConvert.SimToDisplay;

            return(didCollide);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// checks for collisions between two Fixtures. Note that the first Fixture must have a Circle/PolygonShape and one of the Fixtures must be
 /// static for a collision to occur.
 /// </summary>
 /// <returns><c>true</c>, if fixtures was collided, <c>false</c> otherwise.</returns>
 /// <param name="self">Self.</param>
 /// <param name="fixtureB">Fixture b.</param>
 /// <param name="result">Result.</param>
 public static bool CollideFixtures(this Fixture self, Fixture fixtureB, out FSCollisionResult result)
 {
     return(FSCollisions.CollideFixtures(self, fixtureB, out result));
 }
Ejemplo n.º 10
0
        /// <summary>
        /// checks for collisions between two Fixtures. Note that the first Fixture must have a Circle/PolygonShape and one of the Fixtures must be
        /// static.
        /// </summary>
        /// <returns><c>true</c>, if fixtures was collided, <c>false</c> otherwise.</returns>
        /// <param name="fixtureA">Fixture a.</param>
        /// <param name="transformA">Transform a.</param>
        /// <param name="fixtureB">Fixture b.</param>
        /// <param name="transformB">Transform b.</param>
        /// <param name="result">Result.</param>
        public static bool collideFixtures(Fixture fixtureA, ref FSTransform transformA, Fixture fixtureB, ref FSTransform transformB, out FSCollisionResult result)
        {
            result         = new FSCollisionResult();
            result.fixture = fixtureB;

            // we need at least one static fixture
            if (!fixtureA.body.isStatic && !fixtureB.body.isStatic)
            {
                // if the body is dyanmic and asleep wake it up
                if (fixtureB.body.isDynamic && !fixtureB.body.isAwake)
                {
                    fixtureB.body.isAwake = true;
                }
                return(false);
            }

            // check normal collision filtering
            if (!ContactManager.shouldCollide(fixtureA, fixtureB))
            {
                return(false);
            }

            // check user filtering
            if (fixtureA.body.world.contactManager.onContactFilter != null && !fixtureA.body.world.contactManager.onContactFilter(fixtureA, fixtureB))
            {
                return(false);
            }

            // we only handle Circle or Polygon collisions
            if (fixtureA.shape is CircleShape)
            {
                if (fixtureB.shape is CircleShape)
                {
                    return(collideCircles(fixtureA.shape as CircleShape, ref transformA, fixtureB.shape as CircleShape, ref transformB, out result));
                }

                if (fixtureB.shape is PolygonShape)
                {
                    return(collidePolygonCircle(fixtureB.shape as PolygonShape, ref transformB, fixtureA.shape as CircleShape, ref transformA, out result));
                }

                if (fixtureB.shape is EdgeShape)
                {
                    return(collideEdgeAndCircle(fixtureB.shape as EdgeShape, ref transformB, fixtureA.shape as CircleShape, ref transformA, out result));
                }

                if (fixtureB.shape is ChainShape)
                {
                    var chain = fixtureB.shape as ChainShape;
                    for (var i = 0; i < chain.childCount; i++)
                    {
                        var edge = chain.getChildEdge(i);
                        if (collideEdgeAndCircle(edge, ref transformB, fixtureA.shape as CircleShape, ref transformA, out result))
                        {
                            return(true);
                        }
                    }
                }
            }

            if (fixtureA.shape is PolygonShape)
            {
                if (fixtureB.shape is CircleShape)
                {
                    var res = collidePolygonCircle(fixtureA.shape as PolygonShape, ref transformA, fixtureB.shape as CircleShape, ref transformB, out result);
                    result.invertResult();
                    return(res);
                }

                if (fixtureB.shape is PolygonShape)
                {
                    return(collidePolygons(fixtureA.shape as PolygonShape, ref transformA, fixtureB.shape as PolygonShape, ref transformB, out result));
                }

                if (fixtureB.shape is EdgeShape)
                {
                    return(collideEdgeAndPolygon(fixtureB.shape as EdgeShape, ref transformB, fixtureA.shape as PolygonShape, ref transformA, out result));
                }

                if (fixtureB.shape is ChainShape)
                {
                    var chain = fixtureB.shape as ChainShape;
                    for (var i = 0; i < chain.childCount; i++)
                    {
                        var edge = chain.getChildEdge(i);
                        if (collideEdgeAndPolygon(edge, ref transformB, fixtureA.shape as PolygonShape, ref transformA, out result))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// checks for collisions between two Fixtures. Note that the first Fixture must have a Circle/PolygonShape and one of the Fixtures must be
        /// static.
        /// </summary>
        /// <returns><c>true</c>, if fixtures was collided, <c>false</c> otherwise.</returns>
        /// <param name="fixtureA">Fixture a.</param>
        /// <param name="transformA">Transform a.</param>
        /// <param name="fixtureB">Fixture b.</param>
        /// <param name="transformB">Transform b.</param>
        /// <param name="result">Result.</param>
        public static bool CollideFixtures(Fixture fixtureA, ref FSTransform transformA, Fixture fixtureB,
                                           ref FSTransform transformB, out FSCollisionResult result)
        {
            result = new FSCollisionResult {
                Fixture = fixtureB
            };

            // we need at least one static fixture
            if (!fixtureA.Body.IsStatic && !fixtureB.Body.IsStatic)
            {
                // if the body is dyanmic and asleep wake it up
                if (fixtureB.Body.IsDynamic && !fixtureB.Body.IsAwake)
                {
                    fixtureB.Body.IsAwake = true;
                }

                return(false);
            }

            // check normal collision filtering
            if (!ContactManager.ShouldCollide(fixtureA, fixtureB))
            {
                return(false);
            }

            // check user filtering
            if (fixtureA.Body.World.ContactManager.OnContactFilter != null &&
                !fixtureA.Body.World.ContactManager.OnContactFilter(fixtureA, fixtureB))
            {
                return(false);
            }

            // we only handle Circle or Polygon collisions
            if (fixtureA.Shape is CircleShape)
            {
                if (fixtureB.Shape is CircleShape)
                {
                    return(CollideCircles(fixtureA.Shape as CircleShape, ref transformA, fixtureB.Shape as CircleShape,
                                          ref transformB, out result));
                }

                if (fixtureB.Shape is PolygonShape)
                {
                    return(CollidePolygonCircle(fixtureB.Shape as PolygonShape, ref transformB,
                                                fixtureA.Shape as CircleShape, ref transformA, out result));
                }

                if (fixtureB.Shape is EdgeShape)
                {
                    return(CollideEdgeAndCircle(fixtureB.Shape as EdgeShape, ref transformB,
                                                fixtureA.Shape as CircleShape, ref transformA, out result));
                }

                if (fixtureB.Shape is ChainShape)
                {
                    ChainShape chain = fixtureB.Shape as ChainShape;
                    for (int i = 0; i < chain.ChildCount; i++)
                    {
                        EdgeShape edge = chain.GetChildEdge(i);
                        if (CollideEdgeAndCircle(edge, ref transformB, fixtureA.Shape as CircleShape, ref transformA,
                                                 out result))
                        {
                            return(true);
                        }
                    }
                }
            }

            if (fixtureA.Shape is PolygonShape)
            {
                if (fixtureB.Shape is CircleShape)
                {
                    bool res = CollidePolygonCircle(fixtureA.Shape as PolygonShape, ref transformA,
                                                    fixtureB.Shape as CircleShape, ref transformB, out result);
                    result.InvertResult();
                    return(res);
                }

                if (fixtureB.Shape is PolygonShape)
                {
                    return(CollidePolygons(fixtureA.Shape as PolygonShape, ref transformA,
                                           fixtureB.Shape as PolygonShape, ref transformB, out result));
                }

                if (fixtureB.Shape is EdgeShape)
                {
                    return(CollideEdgeAndPolygon(fixtureB.Shape as EdgeShape, ref transformB,
                                                 fixtureA.Shape as PolygonShape, ref transformA, out result));
                }

                if (fixtureB.Shape is ChainShape)
                {
                    ChainShape chain = fixtureB.Shape as ChainShape;
                    for (int i = 0; i < chain.ChildCount; i++)
                    {
                        EdgeShape edge = chain.GetChildEdge(i);
                        if (CollideEdgeAndPolygon(edge, ref transformB, fixtureA.Shape as PolygonShape, ref transformA,
                                                  out result))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }