Exemple #1
0
        /// <summary>
        /// Returns true if a contact should not be disabled due to portal clipping.
        /// </summary>
        private bool IsContactValid(Contact contact)
        {
            FixtureData[] fixtureData = new FixtureData[2];
            fixtureData[0] = FixtureExt.GetData(contact.FixtureA);
            fixtureData[1] = FixtureExt.GetData(contact.FixtureB);

            BodyData[] bodyData = new BodyData[2];
            bodyData[0] = BodyExt.GetData(contact.FixtureA.Body);
            bodyData[1] = BodyExt.GetData(contact.FixtureB.Body);

            Xna.Vector2 normal;
            FixedArray2<Xna.Vector2> vList;
            contact.GetWorldManifold(out normal, out vList);

            if (bodyData[0].IsChild || bodyData[1].IsChild)
            {
                if (bodyData[0].IsChild && bodyData[1].IsChild)
                {
                    //return true;
                }

                int childIndex = bodyData[0].IsChild ? 0 : 1;
                int otherIndex = bodyData[0].IsChild ? 1 : 0;
                BodyData bodyDataChild = bodyData[childIndex];
                BodyData bodyDataOther = bodyData[otherIndex];
                FixtureData fixtureDataChild = fixtureData[childIndex];
                FixtureData fixtureDataOther = fixtureData[otherIndex];

            }

            //Contact is invalid if it is between two fixtures where one fixture is colliding with a portal on the other fixture.
            if (fixtureData[0].IsPortalParentless() && fixtureData[1].IsPortalParentless())
            {
                for (int i = 0; i < fixtureData.Length; i++)
                {
                    int iNext = (i + 1) % fixtureData.Length;
                    var intersection = fixtureData[iNext].GetPortalChildren().Intersect(fixtureData[i].PortalCollisions);
                    if (intersection.Count() > 0)
                    {
                        //Debug.Fail("Fixtures with portal collisions should be filtered.");
                        return false;
                    }
                }
            }

            //Contact is invalid if it is too close to a portal.
            foreach (IPortal p in Scene.GetPortalList())
            {
                if (!Portal.IsValid(p))
                {
                    continue;
                }
                FixturePortal portal = p as FixturePortal;
                if (portal != null)
                {
                    //Don't consider this portal if its fixtures are part of the contact.
                    if (fixtureData[0].PartOfPortal(portal) || fixtureData[1].PartOfPortal(portal))
                    {
                        continue;
                    }

                    LineF line = new LineF(Portal.GetWorldVerts(portal));
                    double[] vDist = new double[] {
                        MathExt.PointLineDistance(vList[0], line, true),
                        MathExt.PointLineDistance(vList[1], line, true)
                    };
                    //Only consider contacts that are between the fixture this portal is parented too and some other fixture.
                    if (contact.FixtureA == FixtureExt.GetFixtureAttached(portal) || contact.FixtureB == FixtureExt.GetFixtureAttached(portal))
                    {
                        if (contact.Manifold.PointCount == 1)
                        {
                            if (vDist[0] < FixturePortal.CollisionMargin)
                            {
                                return false;
                            }
                        }
                        else if (vDist[0] < FixturePortal.CollisionMargin && vDist[1] < FixturePortal.CollisionMargin)
                        {
                            return false;
                        }
                    }
                }
            }

            //Contact is invalid if it is on the opposite side of a colliding portal.
            for (int i = 0; i < fixtureData.Length; i++)
            {
                int iNext = (i + 1) % fixtureData.Length;
                foreach (IPortal portal in fixtureData[i].PortalCollisions)
                {
                    LineF line = new LineF(Portal.GetWorldVerts(portal));

                    FixturePortal cast = portal as FixturePortal;
                    if (cast != null)
                    {
                        if (fixtureData[i].PartOfPortal(cast) || fixtureData[iNext].PartOfPortal(cast))
                        {
                            continue;
                        }
                    }

                    //Contact is invalid if it is on the opposite side of the portal from its body origin.
                    //Xna.Vector2 pos = BodyExt.GetData(fixtureData[i].Fixture.Body).PreviousPosition;
                    Vector2 pos = BodyExt.GetLocalOrigin(fixtureData[i].Fixture.Body);
                    bool oppositeSides0 = line.GetSideOf(vList[0]) != line.GetSideOf(pos);
                    Debug.Assert(contact.Manifold.PointCount > 0);
                    if (contact.Manifold.PointCount == 1)
                    {
                        if (oppositeSides0)
                        {
                            return false;
                        }
                    }
                    else
                    //else if (line.GetSideOf((vList[0] + vList[1])/2) != line.GetSideOf(pos))
                    {
                        bool oppositeSides1 = line.GetSideOf(vList[1]) != line.GetSideOf(pos);
                        /*if (oppositeSides0 && oppositeSides1)
                        {
                            return false;
                        }
                        if (oppositeSides0)
                        {
                            contact.Manifold.Points[0] = contact.Manifold.Points[1];
                        }
                        contact.Manifold.PointCount = 1;

                        return true;*/
                        if (!oppositeSides0 && !oppositeSides1)
                        {
                            continue;
                        }
                        if (!fixtureData[iNext].PortalCollisions.Contains(portal) || !(oppositeSides0 || oppositeSides1))
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
Exemple #2
0
        private void PreSolveListener(Contact contact, ref Manifold oldManifold)
        {
            if (contact.IsTouching)
            {
                Debug.Assert(contact.Manifold.PointCount > 0);

                /* Sometimes a body will tunnel through a portal fixture.
                 * The circumstances aren't well understood but checking if the contact normal
                 * is facing from fixtureB to fixtureA (it should always face from A to B
                 * according to the Box2D documentation) and then reversing the normal if it is
                 * helps prevent tunneling from occuring.*/
                if (!FixtureExt.GetData(contact.FixtureA).IsPortalParentless() || !FixtureExt.GetData(contact.FixtureB).IsPortalParentless())
                {
                    Xna.Vector2 normal;
                    FixedArray2<Xna.Vector2> vList;
                    contact.GetWorldManifold(out normal, out vList);

                    Vector2 center0 = FixtureExt.GetCenterWorld(contact.FixtureA);
                    Vector2 center1 = FixtureExt.GetCenterWorld(contact.FixtureB);

                    if (Math.Abs(MathExt.AngleDiff(center1 - center0, (Vector2)normal)) > Math.PI / 2)
                    {
                        contact.Manifold.LocalNormal *= -1;
                    }
                }

                if (!IsContactValid(contact))
                {
                    contact.Enabled = false;
                    //return;
                }
                else
                {
                    Actor actor0 = BodyExt.GetData(contact.FixtureA.Body).Actor;
                    Actor actor1 = BodyExt.GetData(contact.FixtureB.Body).Actor;
                    actor0.CallOnCollision(actor1, true);
                    actor1.CallOnCollision(actor0, false);
                }
                #region Debug
                if (DebugMode)
                {
                    FixtureData[] userData = new FixtureData[2];
                    userData[0] = FixtureExt.GetData(contact.FixtureA);
                    userData[1] = FixtureExt.GetData(contact.FixtureB);
                    Xna.Vector2 normal;
                    FixedArray2<Xna.Vector2> vList;
                    contact.GetWorldManifold(out normal, out vList);

                    if (contact.Manifold.PointCount == 2)
                    {
                        Model line = ModelFactory.CreateLines(
                           new LineF[] {
                            new LineF(vList[0], vList[1])
                           });
                        if (contact.Enabled)
                        {
                            line.SetColor(new Vector3(1, 1, 0.2f));
                        }
                        else
                        {
                            line.SetColor(new Vector3(0.5f, 0.5f, 0));
                        }
                        line.Transform.Position += new Vector3(0, 0, 5);
                        DebugEntity.AddModel(line);
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        float scale = 0.8f;
                        Vector3 pos = new Vector3(vList[i].X, vList[i].Y, 5);
                        //Ignore contact points that are exactly on the origin. These are almost certainly null values.
                        if (pos.X == 0 && pos.Y == 0)
                        {
                            continue;
                        }
                        Vector2 arrowNormal = (Vector2)normal * 0.2f * scale;
                        if (i == 0)
                        {
                            arrowNormal *= -1;
                        }
                        Model arrow = ModelFactory.CreateArrow(pos, arrowNormal, 0.02f * scale, 0.05f * scale, 0.03f * scale);
                        DebugEntity.AddModel(arrow);

                        Model model = ModelFactory.CreateCube();
                        model.Transform.Scale = new Vector3(0.08f, 0.08f, 0.08f) * scale;
                        DebugEntity.AddModel(model);
                        if (contact.Enabled)
                        {
                            model.SetColor(new Vector3(1, 1, 0.2f));
                            arrow.SetColor(new Vector3(1, 1, 0.2f));
                        }
                        else
                        {
                            model.SetColor(new Vector3(0.5f, 0.5f, 0));
                            arrow.SetColor(new Vector3(0.5f, 0.5f, 0));
                        }
                        if (userData[0].IsPortalParentless() && userData[1].IsPortalParentless())
                        {
                            arrow.SetColor(new Vector3(0.7f, 0.5f, 0.2f));
                        }
                        model.Transform.Position = pos;

                        if (!userData[i].IsPortalParentless())
                        {
                            IList<Vector2> vertices = Vector2Ext.ToOtk(((PolygonShape)userData[i].Fixture.Shape).Vertices);
                            Model fixtureModel = ModelFactory.CreatePolygon(vertices);
                            fixtureModel.SetColor(new Vector3(0, 1, 1));
                            fixtureModel.Transform = userData[i].Actor.GetTransform().Get3D();
                            fixtureModel.Transform.Position += new Vector3(0, 0, 5);
                            fixtureModel.Transform.Scale = Vector3.One;

                            DebugEntity.AddModel(fixtureModel);
                        }
                    }
                }
                #endregion
            }
        }
Exemple #3
0
 public static FixtureData SetData(Fixture fixture)
 {
     FixtureData userData = new FixtureData(fixture);
     fixture.UserData = userData;
     return userData;
 }