public CollisionPair(Geom g1, Geom g2)
            {
                Debug.Assert(g1 != g2);

                if (g1 < g2)
                {
                    geom1 = g1;
                    geom2 = g2;
                }
                else
                {
                    geom1 = g2;
                    geom2 = g1;
                }
            }
            public void AddPair(Geom g1, Geom g2)
            {
                CollisionPair cp = new CollisionPair(g1, g2);

                // This check is a trade-off. In many cases, we don't need to perform
                // this check and we could just do a "try" block instead, however,
                // when exceptions are thrown, they are mega-slow... so checking for
                // the key is really the best option all round.
                if (ContainsKey(cp))
                {
                    return;
                }

                Add(cp, true);
            }
        private void DetectInternal(bool doX)
        {
            List <Stub>          stubs         = (doX) ? (_xStubs) : (_yStubs);
            LinkedList <Wrapper> currentBodies = new LinkedList <Wrapper>();

            for (int index = 0; index < stubs.Count; index++)
            {
                Stub    stub     = stubs[index];
                Wrapper wrapper1 = stub.wrapper;
                if (stub.begin)
                {
                    //set the min and max values
                    if (doX)
                    {
                        wrapper1.SetY();
                    }
                    else
                    {
                        wrapper1.SetX();
                    }

                    Geom geom1 = wrapper1.geom;
                    for (LinkedListNode <Wrapper> node = currentBodies.First;
                         node != null;
                         node = node.Next)
                    {
                        Wrapper wrapper2 = node.Value;
                        Geom    geom2    = wrapper2.geom;
                        if (wrapper1.min <= wrapper2.max && //tests the other axis
                            wrapper2.min <= wrapper1.max)
                        {
                            OnCollision(geom1, geom2);
                        }
                    }
                    if (wrapper1.shouldAddNode)
                    {
                        currentBodies.AddLast(wrapper1.node);
                    }
                }
                else
                {
                    if (wrapper1.shouldAddNode)
                    {
                        currentBodies.Remove(wrapper1.node);
                    }
                }
            }
        }
示例#4
0
        /// <summary>
        /// Computes the grid.
        /// </summary>
        /// <param name="geometry">The geometry.</param>
        /// <param name="data"><see cref="ColliderData"/> that contains the size of the grid cell.</param>
        /// <exception cref="ArgumentNullException"><c>geometry</c> is null.</exception>
        public void Prepare(Geom geometry, ColliderData data)
        {
            float gridCellSize = data.GridCellSize;

            if (geometry == null)
            {
                throw new ArgumentNullException("geometry", "Geometry can't be null");
            }

            if (gridCellSize <= 0)
            {
                throw new ArgumentNullException("data", "The grid cell size must be larger than 0");
            }

            //Prepare the geometry.
            Matrix old = geometry.Matrix;

            //Note: Changed in 2.1
            //Matrix identity = Matrix.Identity;
            //geometry.Matrix = identity;
            //to:

            geometry.Matrix = Matrix.Identity;

            //Copy the AABB to the grid field
            _aabb            = new AABB(geometry.AABB);
            _gridCellSize    = gridCellSize;
            _gridCellSizeInv = 1 / gridCellSize;

            //Note: Physics2d have +2
            int xSize = (int)Math.Ceiling((double)(_aabb.Max.X - _aabb.Min.X) * _gridCellSizeInv) + 1;
            int ySize = (int)Math.Ceiling((double)(_aabb.Max.Y - _aabb.Min.Y) * _gridCellSizeInv) + 1;

            _nodes = new float[xSize, ySize];
            Vector2 vector = _aabb.Min;

            for (int x = 0; x < xSize; ++x, vector.X += gridCellSize)
            {
                vector.Y = _aabb.Min.Y;
                for (int y = 0; y < ySize; ++y, vector.Y += gridCellSize)
                {
                    _nodes[x, y] = geometry.GetNearestDistance(vector); // shape.GetDistance(vector);
                }
            }
            //restore the geometry
            geometry.Matrix = old;
        }
示例#5
0
            public void MoveUnderConsiderationToOverlaps()
            {
                for (int i = 0; i < Count; i++)
                {
                    if (this[i].UnderConsideration.Count == 0)
                    {
                        continue;
                    }

                    Geom g1 = this[i].Geometry;

                    // First transfer those under consideration to overlaps,
                    // for, they have been considered...
                    int startIndex = this[i].Overlaps.Count;
                    this[i].Overlaps.AddRange(this[i].UnderConsideration);
                    this[i].UnderConsideration.Clear();

                    for (int j = startIndex; j < this[i].Overlaps.Count; j++)
                    {
                        Geom g2 = this[i].Overlaps[j];

                        // It is possible that we may test the same pair of geometries
                        // for both extents (x and y), however, I'm banking on that
                        // one of the extents has probably already been cached and
                        // therefore, won't be checked.
                        if (DoCollision(g1, g2) == false)
                        {
                            continue;
                        }

                        //Call the OnBroadPhaseCollision event first. If the user aborts the collision
                        //it will not create an arbiter
                        if (Owner.OnBroadPhaseCollision != null)
                        {
                            if (Owner.OnBroadPhaseCollision(g1, g2))
                            {
                                Owner.CollisionPairs.AddPair(g1, g2);
                            }
                        }
                        else
                        {
                            Owner.CollisionPairs.AddPair(g1, g2);
                        }
                    }
                }
            }
示例#6
0
        private void FillHash()
        {
            //Average used to optimize cell size if AutoAdjustCellSize = true.
            float average = 0;

            for (int i = 0; i < _physicsSimulator.GeomList.Count; i++)
            {
                Geom geom = _physicsSimulator.GeomList[i];

                //Note: Could do some checking here for geometries that should not be included in the hashmap

                AABB aabb = geom.AABB;

                if (AutoAdjustCellSize)
                {
                    average += Math.Max(aabb.Max.X - aabb.Min.X, aabb.Max.Y - aabb.Min.Y);
                }

                int minX = (int)(aabb.Min.X * _cellSizeInv);
                int maxX = (int)(aabb.Max.X * _cellSizeInv) + 1;
                int minY = (int)(aabb.Min.Y * _cellSizeInv);
                int maxY = (int)(aabb.Max.Y * _cellSizeInv) + 1;

                for (int x = minX; x < maxX; x++)
                {
                    for (int y = minY; y < maxY; y++)
                    {
                        long        key = PairID.GetHash(x, y);
                        List <Geom> list;
                        if (!_hash.TryGetValue(key, out list))
                        {
                            list = new List <Geom>();
                            _hash.Add(key, list);
                        }
                        list.Add(geom);
                    }
                }
            }

            if (AutoAdjustCellSize)
            {
                CellSize = 2 * average / (_physicsSimulator.GeomList.Count);
            }
        }
        private void OnCollision(Geom geom1, Geom geom2)
        {
            if (!geom1.body.enabled || !geom2.body.enabled)
            {
                return;
            }

            if ((geom1.collisionGroup == geom2.collisionGroup) &&
                geom1.collisionGroup != 0 &&
                geom2.collisionGroup != 0)
            {
                return;
            }

            if (!geom1.collisionEnabled || !geom2.collisionEnabled)
            {
                return;
            }

            if (geom1.body.isStatic && geom2.body.isStatic)
            {
                //don't collide two static bodies
                return;
            }

            if (((geom1.collisionCategories & geom2.collidesWith) == CollisionCategories.None) &
                ((geom2.collisionCategories & geom1.collidesWith) == CollisionCategories.None))
            {
                return;
            }

            Arbiter arbiter = _physicsSimulator.arbiterPool.Fetch();

            arbiter.ConstructArbiter(geom1, geom2, _physicsSimulator);

            if (!_physicsSimulator.arbiterList.Contains(arbiter))
            {
                _physicsSimulator.arbiterList.Add(arbiter);
            }
            else
            {
                _physicsSimulator.arbiterPool.Release(arbiter);
            }
        }
示例#8
0
        /// <summary>
        /// Detects all collision points between a line and a Geom. If intersections exist a LineIntersectionInfo
        /// object is created and added to an existing list of such objects.
        /// </summary>
        /// <param name="p1">The first point of the line segment to test</param>
        /// <param name="p2">The second point of the line segment to test</param>
        /// <param name="geom">The geometry to test.</param>
        /// <param name="detectUsingAABB">If true, intersection will be tested using the Geoms AABB. If false, the Geoms vertices will be used.</param>
        /// <param name="lineIntersectInfoList">An existing intersect info list to add to</param>
        public static void LineSegmentGeomIntersect(ref Vector2 p1, ref Vector2 p2, Geom geom, bool detectUsingAABB,
                                                    ref List <LineIntersectInfo> lineIntersectInfoList)
        {
            List <Vector2> points = new List <Vector2>();

            if (detectUsingAABB)
            {
                LineSegmentAABBIntersect(ref p1, ref p2, geom.AABB, ref points);
                if (points.Count > 0)
                {
                    lineIntersectInfoList.Add(new LineIntersectInfo(geom, points));
                }
            }
            else
            {
                LineSegmentVerticesIntersect(ref p1, ref p2, geom.WorldVertices, ref points);
                if (points.Count > 0)
                {
                    lineIntersectInfoList.Add(new LineIntersectInfo(geom, points));
                }
            }
        }
示例#9
0
        /// <summary>
        /// Computes the grid.
        /// </summary>
        /// <param name="geometry">The geometry.</param>
        /// <param name="gridCellSize">Size of the grid cell.</param>
        public void ComputeGrid(Geom geometry, float gridCellSize)
        {
            //Prepare the geometry.
            Matrix old = geometry.Matrix;

            //TODO: Assign geometry.Matrix to Matrix.Identity directly
            Matrix identity = Matrix.Identity;

            geometry.Matrix = identity;

            //Copy the AABB to the grid field
            _aabb            = new AABB(geometry.AABB);
            _gridCellSize    = gridCellSize;
            _gridCellSizeInv = 1 / gridCellSize;

            //NOTE: Using double cast instead of converting.
            int xSize = (int)Math.Ceiling((double)(_aabb.Max.X - _aabb.Min.X) * _gridCellSizeInv) + 1;
            int ySize = (int)Math.Ceiling((double)(_aabb.Max.Y - _aabb.Min.Y) * _gridCellSizeInv) + 1;

            //TODO: Possible optimization (normal)! If the shape is symmetric in X and Y axis, don't calculate the points, replicate them.
            _nodes  = new float[xSize, ySize];
            _points = new Vector2[xSize * ySize];
            int     i      = 0;
            Vector2 vector = _aabb.Min;

            for (int x = 0; x < xSize; ++x, vector.X += gridCellSize)
            {
                vector.Y = _aabb.Min.Y;
                for (int y = 0; y < ySize; ++y, vector.Y += gridCellSize)
                {
                    _nodes[x, y] = geometry.GetNearestDistance(vector); // shape.GetDistance(vector);
                    _points[i]   = vector;
                    i           += 1;
                }
            }
            //restore the geometry
            geometry.Matrix = old;
        }
示例#10
0
        public void ComputeGrid(Geom geometry, float gridCellSize)
        {
            //prepare the geometry.
            Matrix old      = geometry.Matrix;
            Matrix identity = Matrix.Identity;

            geometry.Matrix = identity;

            _aabb            = new AABB(geometry.AABB);
            _gridCellSize    = gridCellSize;
            _gridCellSizeInv = 1 / gridCellSize;

            //TODO: Possible optimization (minor)! use casting, use _aabb.Width and Height and check if Height==Width instead of calculating twice.
            int xSize = (int)Math.Ceiling(Convert.ToDouble((_aabb.Max.X - _aabb.Min.X) * _gridCellSizeInv)) + 1;
            int ySize = (int)Math.Ceiling(Convert.ToDouble((_aabb.Max.Y - _aabb.Min.Y) * _gridCellSizeInv)) + 1;

            _nodes  = new float[xSize, ySize];
            _points = new Vector2[xSize * ySize];
            int     i      = 0;
            Vector2 vector = _aabb.Min;

            //TODO: Possible optimization (normal)! Cache the grids for later use. (don't recreate a grid of 64x64 if it's already made)

            //TODO: Possible optimization (normal)! If the shape is symmetric in X and Y axis, don't calculate the points, replicate them.
            for (int x = 0; x < xSize; ++x, vector.X += gridCellSize)
            {
                vector.Y = _aabb.Min.Y;
                for (int y = 0; y < ySize; ++y, vector.Y += gridCellSize)
                {
                    _nodes[x, y] = geometry.GetNearestDistance(vector); // shape.GetDistance(vector);
                    _points[i]   = vector;
                    i           += 1;
                }
            }
            //restore the geometry
            geometry.Matrix = old;
        }
示例#11
0
 /// <summary>
 /// Removes a distance grid from the cache.
 /// </summary>
 /// <param name="geom">The geom.</param>
 public void RemoveDistanceGrid(Geom geom)
 {
     _distanceGrids.Remove(geom.id);
 }
示例#12
0
        /// <summary>
        /// Finds the contactpoints between the two geometries.
        /// </summary>
        /// <param name="geomA">The first geom.</param>
        /// <param name="geomB">The second geom.</param>
        /// <param name="contactList">The contact list.</param>
        public void Collide(Geom geomA, Geom geomB, ContactList contactList)
        {
            int vertexIndex = -1;

            //Lookup distancegrid A data from list
            DistanceGridData geomAGridData = _distanceGrids[geomA.id];

            //Iterate the second geometry vertices
            for (int i = 0; i < geomB.worldVertices.Count; i++)
            {
                if (contactList.Count == PhysicsSimulator.MaxContactsToDetect)
                {
                    break;
                }

                vertexIndex += 1;
                _vertRef     = geomB.WorldVertices[i];
                geomA.TransformToLocalCoordinates(ref _vertRef, out _localVertex);

                //The geometry intersects when distance <= 0
                //Continue in the list if the current vector does not intersect
                if (!geomAGridData.Intersect(ref _localVertex, out _feature))
                {
                    continue;
                }

                //If the geometries collide, create a new contact and add it to the contact list.
                if (_feature.Distance < 0f)
                {
                    geomA.TransformNormalToWorld(ref _feature.Normal, out _feature.Normal);

                    Contact contact = new Contact(geomB.WorldVertices[i], _feature.Normal, _feature.Distance, new ContactId(geomB.id, vertexIndex, geomA.id));
                    contactList.Add(contact);
                }
            }

            //Lookup distancegrid B data from list
            DistanceGridData geomBGridData = _distanceGrids[geomB.id];

            //Iterate the first geometry vertices
            for (int i = 0; i < geomA.WorldVertices.Count; i++)
            {
                if (contactList.Count == PhysicsSimulator.MaxContactsToDetect)
                {
                    break;
                }

                vertexIndex += 1;
                _vertRef     = geomA.WorldVertices[i];
                geomB.TransformToLocalCoordinates(ref _vertRef, out _localVertex);

                if (!geomBGridData.Intersect(ref _localVertex, out _feature))
                {
                    continue;
                }

                if (_feature.Distance < 0f)
                {
                    geomB.TransformNormalToWorld(ref _feature.Normal, out _feature.Normal);
                    _feature.Normal = -_feature.Normal;

                    Contact contact = new Contact(geomA.WorldVertices[i], _feature.Normal, _feature.Distance, new ContactId(geomA.id, vertexIndex, geomB.id));
                    contactList.Add(contact);
                }
            }
        }
示例#13
0
 public LineIntersectInfo(Geom geom, List <Vector2> points)
 {
     _geom   = geom;
     _points = points;
 }
            /// <summary>
            /// Incrementally inserts the min/max extents into the ExtentList. As it
            /// does so, the method ensures that overlap records, the collisionpair
            /// map, and all other book-keeping is up todate.
            /// </summary>
            /// <param name="ourInfo">The extent info for a give axis</param>
            public void IncrementalInsertExtent(ExtentInfo ourInfo)
            {
                Extent min = ourInfo.min;
                Extent max = ourInfo.max;

                Debug.Assert(min.value < max.value);

                int iMin = InsertIntoSortedList(min);
                int iMax = InsertIntoSortedList(max);

                Geom ourGeom = ourInfo.geometry;

                // As this is a newly inserted extent, we need to update the overlap
                // information.

                // RULE 1: Traverse from min to max. Look for other "min" Extents
                // and when found, add our wrapper/geometry to their list.
                int iCurr = iMin + 1;

                while (iCurr != iMax)
                {
                    if (this[iCurr].isMin)
                    {
                        this[iCurr].info.underConsideration.Add(ourGeom);
                    }
                    iCurr++;
                }

                // RULE 2: From min, traverse to the left until we encounter
                // another "min" extent. If we find one, we add its geometry
                // to our underConsideration list and go to RULE 3, otherwise
                // there is no more work to do and we can exit.
                iCurr = iMin - 1;
                while (iCurr >= 0 && this[iCurr].isMin == false)
                {
                    iCurr--;
                }

                if (iCurr < 0)
                {
                    return;
                }

                List <Geom> ourUnderConsideration = ourInfo.underConsideration;
                Extent      currExtent            = this[iCurr];

                ourUnderConsideration.Add(currExtent.info.geometry);

                // RULE 3: Now that we have found a "min" extent, we take
                // its existing overlap list and copy it into our underConsideration
                // list. All except for ourselves.
                ourUnderConsideration.AddRange(currExtent.info.underConsideration);
                ourUnderConsideration.Remove(ourGeom); // just in case

                /*LinkedListNode<Geom> currGeomNode =
                 *  currExtent.info.underConsideration.First;
                 *
                 * while (currGeomNode != null)
                 * {
                 *  if (currGeomNode.Value != ourGeom)
                 *  {
                 *      ourUnderConsideration.AddLast(new LinkedListNode<Geom>(
                 *          currGeomNode.Value));
                 *  }
                 *  currGeomNode = currGeomNode.Next;
                 * }*/

                // RULE 4: Move from the found extent back toward our "min" extent.
                // Whenever and "max" extent is found, we remove its reference
                // from our extents list.
                while (iCurr != iMin)
                {
                    if (currExtent.isMin == false)
                    {
                        ourUnderConsideration.Remove(currExtent.info.geometry);

                        if (ourInfo.overlaps.Remove(currExtent.info.geometry))
                        {
                            owner.collisionPairs.RemovePair(ourGeom,
                                                            currExtent.info.geometry);
                        }
                    }
                    currExtent = this[++iCurr];
                }
            }
        /// <summary>
        /// This function can be used for times when frame-coherence is temporarily lost
        /// or when it is simply more convenient to completely rebuild all the cached
        /// data instead of incrementally updating it. Currently it is used after
        /// removing disposed/removed geometries. If your application had an object
        /// that teleported across the universe or some other situation where
        /// frame-coherence was lost, you might consider this function.
        /// </summary>
        public void ForceNonIncrementalUpdate()
        {
            UpdateExtentValues();

            // First, wipe out the collision records
            collisionPairs.Clear();

            // And clear out all the overlap records
            Debug.Assert(_xInfoList.Count == _yInfoList.Count);
            for (int i = 0; i < _xInfoList.Count; i++)
            {
                _xInfoList[i].overlaps.Clear();
                _xInfoList[i].underConsideration.Clear();
                _yInfoList[i].overlaps.Clear();
                _yInfoList[i].underConsideration.Clear();
            }

            // Force sort
            _xExtentList.Sort((l, r) => l.value.CompareTo(r.value));
            _yExtentList.Sort((l, r) => l.value.CompareTo(r.value));

            // Rebuild overlap information
            List <Geom> overlaps = new List <Geom>();

            for (int i = 0; i < 2; i++)
            {
                overlaps.Clear();

                ExtentList extentList = i == 0 ? _xExtentList : _yExtentList;

                foreach (Extent extent in extentList)
                {
                    if (extent.isMin)
                    {
                        // Add whatever is currently in overlaps to this
                        extent.info.overlaps.InsertRange(0, overlaps);

                        // Now add, this geom to overlaps
                        overlaps.Add(extent.info.geometry);
                    }
                    else
                    {
                        // remove this geom from overlaps
                        overlaps.Remove(extent.info.geometry);

                        // Test this geom against its overlaps for collisionpairs
                        Geom thisGeom = extent.info.geometry;
                        foreach (Geom g in extent.info.overlaps)
                        {
                            if (DoCollision(thisGeom, g) == false)
                            {
                                continue;
                            }

                            collisionPairs.AddPair(thisGeom, g);
                        }
                    }
                }
            }
            HandleCollisions();
        }
        /// <summary>
        /// Updates this instance.
        /// </summary>
        public void Update()
        {
            //Iterate all the geoms and check against the next
            for (int i = 0; i < _physicsSimulator.GeomList.Count - 1; i++)
            {
                for (int j = i + 1; j < _physicsSimulator.GeomList.Count; j++)
                {
                    _geometryA = _physicsSimulator.GeomList[i];
                    _geometryB = _physicsSimulator.GeomList[j];

                    if (!_geometryA.body.Enabled || !_geometryB.body.Enabled)
                    {
                        continue;
                    }

                    if ((_geometryA.CollisionGroup == _geometryB.CollisionGroup) &&
                        _geometryA.CollisionGroup != 0 && _geometryB.CollisionGroup != 0)
                    {
                        continue;
                    }

                    if (!_geometryA.CollisionEnabled || !_geometryB.CollisionEnabled)
                    {
                        continue;
                    }

                    if (_geometryA.body.isStatic && _geometryB.body.isStatic)
                    {
                        continue;
                    }

                    if (_geometryA.body == _geometryB.body)
                    {
                        continue;
                    }

                    if (((_geometryA.CollisionCategories & _geometryB.CollidesWith) == CollisionCategory.None) &
                        ((_geometryB.CollisionCategories & _geometryA.CollidesWith) == CollisionCategory.None))
                    {
                        continue;
                    }

                    if (_geometryA.IsGeometryIgnored(_geometryB) || _geometryB.IsGeometryIgnored(_geometryA))
                    {
                        continue;
                    }

                    //Assume intersection
                    bool intersection = true;

                    //Check if there is no intersection
                    if (_geometryA.AABB.min.X > _geometryB.AABB.max.X || _geometryB.AABB.min.X > _geometryA.AABB.max.X)
                    {
                        intersection = false;
                    }
                    else if (_geometryA.AABB.min.Y > _geometryB.AABB.Max.Y || _geometryB.AABB.min.Y > _geometryA.AABB.Max.Y)
                    {
                        intersection = false;
                    }

                    //Call the OnBroadPhaseCollision event first. If the user aborts the collision
                    //it will not create an arbiter
                    if (OnBroadPhaseCollision != null)
                    {
                        intersection = OnBroadPhaseCollision(_geometryA, _geometryB);
                    }

                    //If the user aborted the intersection, continue to the next geometry.
                    if (!intersection)
                    {
                        continue;
                    }

                    Arbiter arbiter = _physicsSimulator.arbiterPool.Fetch();
                    arbiter.ConstructArbiter(_geometryA, _geometryB, _physicsSimulator);

                    if (!_physicsSimulator.ArbiterList.Contains(arbiter))
                    {
                        _physicsSimulator.ArbiterList.Add(arbiter);
                    }
                    else
                    {
                        _physicsSimulator.arbiterPool.Insert(arbiter);
                    }
                }
            }
        }
示例#17
0
 /// <summary>
 /// Detects all collision points between a line and a Geom. If intersections exist a LineIntersectionInfo
 /// object is created and added to an existing list of such objects.
 /// </summary>
 /// <param name="point1">The first point of the line segment to test</param>
 /// <param name="point2">The second point of the line segment to test</param>
 /// <param name="geom">The geometry to test.</param>
 /// <param name="detectUsingAABB">If true, intersection will be tested using the Geoms AABB. If false, the Geoms vertices will be used.</param>
 /// <param name="intersectionPoints">An existing point list to add to</param>
 public static void LineSegmentGeomIntersect(ref Vector2 point1, ref Vector2 point2, Geom geom, bool detectUsingAABB,
                                             ref List <Vector2> intersectionPoints)
 {
     if (detectUsingAABB)
     {
         LineSegmentAABBIntersect(ref point1, ref point2, geom.AABB, ref intersectionPoints);
     }
     else
     {
         LineSegmentVerticesIntersect(ref point1, ref point2, geom.WorldVertices, ref intersectionPoints);
     }
 }
        /// <summary>
        /// Test AABB collisions between two geometries. Tests include checking if the
        /// geometries are enabled, static, in the right collision categories, etc.
        /// </summary>
        /// <returns>Returns true if there is a collision, false otherwise</returns>
        public static bool DoCollision(Geom g1, Geom g2)
        {
            if (!g1.body.enabled || !g2.body.enabled)
            {
                return(false);
            }

            if ((g1.collisionGroup == g2.collisionGroup) &&
                g1.collisionGroup != 0 && g2.collisionGroup != 0)
            {
                return(false);
            }

            if (!g1.collisionEnabled || !g2.collisionEnabled)
            {
                return(false);
            }

            if (g1.body.isStatic && g2.body.isStatic)
            {
                return(false);
            }

            if (g1.body == g2.body)
            {
                return(false);
            }

            if (((g1.collisionCategories & g2.collidesWith) ==
                 CollisionCategories.None) & ((g2.collisionCategories &
                                               g1.collidesWith) == CollisionCategories.None))
            {
                return(false);
            }

            //TMP
            AABB aabb1 = new AABB();
            AABB aabb2 = new AABB();

            aabb1.min    = g1.aabb.min;
            aabb1.max    = g1.aabb.max;
            aabb2.min    = g2.aabb.min;
            aabb2.max    = g2.aabb.max;
            aabb1.min.X -= fTol;
            aabb1.min.Y -= fTol;
            aabb1.max.X += fTol;
            aabb1.max.Y += fTol;
            aabb2.min.X -= fTol;
            aabb2.min.Y -= fTol;
            aabb2.max.X += fTol;
            aabb2.max.Y += fTol;
            if (AABB.Intersect(aabb1, aabb2) == false)
            {
                return(false);
            }

            //            if (AABB.Intersect(g1.aabb, g2.aabb) == false)
            //                return false;

            return(true);
        }
示例#19
0
        private void DoCollision()
        {
            for (int i = 0; i < _physicsSimulator.geomList.Count - 1; i++)
            {
                for (int j = i + 1; j < _physicsSimulator.geomList.Count; j++)
                {
                    _geometryA = _physicsSimulator.geomList[i];
                    _geometryB = _physicsSimulator.geomList[j];
                    //possible early exits
                    if (!_geometryA.Body.enabled || !_geometryB.Body.enabled)
                    {
                        continue;
                    }

                    if ((_geometryA.CollisionGroup == _geometryB.CollisionGroup) && _geometryA.CollisionGroup != 0 &&
                        _geometryB.CollisionGroup != 0)
                    {
                        continue;
                    }

                    if (!_geometryA.CollisionEnabled || !_geometryB.CollisionEnabled)
                    {
                        continue;
                    }

                    if (_geometryA.Body.isStatic && _geometryB.Body.isStatic)
                    {
                        //don't collide two static bodies
                        continue;
                    }

                    if (_geometryA.Body == _geometryB.Body)
                    {
                        //don't collide two geometries connected to the same body
                        continue;
                    }

                    if (((_geometryA.CollisionCategories & _geometryB.CollidesWith) == CollisionCategories.None) &
                        ((_geometryB.CollisionCategories & _geometryA.CollidesWith) == CollisionCategories.None))
                    {
                        continue;
                    }

                    bool intersection = true;

                    #region INLINE: if (AABB.Intersect(_geometryA.aabb, _geometryB.aabb)) ....

                    if (_geometryA.AABB.min.X > _geometryB.AABB.max.X || _geometryB.AABB.min.X > _geometryA.AABB.max.X)
                    {
                        intersection = false;
                    }
                    else if (_geometryA.AABB.min.Y > _geometryB.AABB.Max.Y ||
                             _geometryB.AABB.min.Y > _geometryA.AABB.Max.Y)
                    {
                        intersection = false;
                    }

                    #endregion

                    if (intersection)
                    {
                        _arbiter = _physicsSimulator.arbiterPool.Fetch();
                        _arbiter.ConstructArbiter(_geometryA, _geometryB, _physicsSimulator);

                        if (!_physicsSimulator.arbiterList.Contains(_arbiter))
                        {
                            _physicsSimulator.arbiterList.Add(_arbiter);
                        }
                        else
                        {
                            _physicsSimulator.arbiterPool.Release(_arbiter);
                        }
                    }
                }
            }
        }
示例#20
0
 /// <summary>
 /// Detects all collision points between a line and a Geom. If intersections exist
 /// a LineIntersectionInfo  object is created and added to an existing list of such
 /// objects. </summary>
 /// <param name="point1">The first point of the line segment to test</param>
 /// <param name="point2">The second point of the line segment to test</param>
 /// <param name="geom">The geometry to test.</param>
 /// <param name="detectUsingAABB">If true, intersection will be tested using the
 /// Geoms AABB. If false, the Geoms vertices will be used.</param>
 /// <param name="intersectionPoints">An existing points info list to add to
 /// </param>
 public static void LineSegmentGeomIntersect(Vector2 point1, Vector2 point2, Geom geom, bool detectUsingAABB,
                                             ref List <Vector2> intersectionPoints)
 {
     LineSegmentGeomIntersect(ref point1, ref point2, geom, detectUsingAABB, ref intersectionPoints);
 }
示例#21
0
 /// <summary>
 /// Detects all collision points between a line and a Geom. If intersections exist
 /// a LineIntersectionInfo  object is created and added to an existing list of such
 /// objects. </summary>
 /// <param name="p1">The first point of the line segment to test</param>
 /// <param name="p2">The second point of the line segment to test</param>
 /// <param name="geom">The geometry to test.</param>
 /// <param name="detectUsingAABB">If true, intersection will be tested using the
 /// Geoms AABB. If false, the Geoms vertices will be used.</param>
 /// <param name="lineIntersectInfoList">An existing intersect info list to add to
 /// </param>
 public static void LineSegmentGeomIntersect(Vector2 p1, Vector2 p2, Geom geom, bool detectUsingAABB,
                                             ref List <LineIntersectInfo> lineIntersectInfoList)
 {
     LineSegmentGeomIntersect(ref p1, ref p2, geom, detectUsingAABB, ref lineIntersectInfoList);
 }
示例#22
0
 public bool Intersect(Geom geom, ref Vector2 position)
 {
     return(InsidePolygon(geom.LocalVertices, position));
 }
        private void DetectInternal(bool doX)
        {
            List <Stub> stubs = (doX) ? (_xStubs) : (_yStubs);

            _currentBodies.Clear();
            for (int index = 0; index < stubs.Count; index++)
            {
                Stub    stub     = stubs[index];
                Wrapper wrapper1 = stub.Wrapper;
                if (stub.Begin)
                {
                    //set the min and max values
                    if (doX)
                    {
                        wrapper1.SetY();
                    }
                    else
                    {
                        wrapper1.SetX();
                    }

                    Geom geometryA = wrapper1.Geom;

                    for (LinkedListNode <Wrapper> node = _currentBodies.First; node != null; node = node.Next)
                    {
                        Wrapper wrapper2  = node.Value;
                        Geom    geometryB = wrapper2.Geom;

                        if (wrapper1.Min <= wrapper2.Max && wrapper2.Min <= wrapper1.Max)
                        {
                            if (!geometryA.body.Enabled || !geometryB.body.Enabled)
                            {
                                continue;
                            }

                            if ((geometryA.CollisionGroup == geometryB.CollisionGroup) &&
                                geometryA.CollisionGroup != 0 && geometryB.CollisionGroup != 0)
                            {
                                continue;
                            }

                            if (!geometryA.CollisionEnabled || !geometryB.CollisionEnabled)
                            {
                                continue;
                            }

                            if (geometryA.body.isStatic && geometryB.body.isStatic)
                            {
                                continue;
                            }

                            if (geometryA.body == geometryB.body)
                            {
                                continue;
                            }

                            if (((geometryA.CollisionCategories & geometryB.CollidesWith) == CollisionCategory.None) &
                                ((geometryB.CollisionCategories & geometryA.CollidesWith) == CollisionCategory.None))
                            {
                                continue;
                            }

                            if (geometryA.IsGeometryIgnored(geometryB) || geometryB.IsGeometryIgnored(geometryA))
                            {
                                continue;
                            }

                            bool intersection = true;

                            //Call the OnBroadPhaseCollision event first. If the user aborts the collision
                            //it will not create an arbiter
                            if (OnBroadPhaseCollision != null)
                            {
                                intersection = OnBroadPhaseCollision(geometryA, geometryB);
                            }

                            if (!intersection)
                            {
                                continue;
                            }

                            _physicsSimulator.ArbiterList.AddArbiterForGeomPair(_physicsSimulator, geometryA, geometryB);
                        }
                    }
                    if (wrapper1.ShouldAddNode)
                    {
                        _currentBodies.AddLast(wrapper1.Node);
                    }
                }
                else
                {
                    if (wrapper1.ShouldAddNode)
                    {
                        _currentBodies.Remove(wrapper1.Node);
                    }
                }
            }
        }
示例#24
0
        private void RunHash()
        {
            _keysToRemove.Clear();
            foreach (KeyValuePair <long, List <Geom> > pair in _hash)
            {
                // If there are no geometries in the list. Remove it.
                // If there are any geometries in the list, process them.
                List <Geom> list = pair.Value;
                if (list.Count == 0)
                {
                    _keysToRemove.Add(pair.Key);
                }
                else
                {
                    for (int i = 0; i < list.Count - 1; i++)
                    {
                        Geom geometryA = list[i];
                        for (int j = i + 1; j < list.Count; j++)
                        {
                            Geom geometryB = list[j];

                            if (!geometryA.body.Enabled || !geometryB.body.Enabled)
                            {
                                continue;
                            }

                            if ((geometryA.CollisionGroup == geometryB.CollisionGroup) &&
                                geometryA.CollisionGroup != 0 && geometryB.CollisionGroup != 0)
                            {
                                continue;
                            }

                            if (!geometryA.CollisionEnabled || !geometryB.CollisionEnabled)
                            {
                                continue;
                            }

                            if (geometryA.body.isStatic && geometryB.body.isStatic)
                            {
                                continue;
                            }

                            if (geometryA.body == geometryB.body)
                            {
                                continue;
                            }

                            if (((geometryA.CollisionCategories & geometryB.CollidesWith) == CollisionCategory.None) &
                                ((geometryB.CollisionCategories & geometryA.CollidesWith) == CollisionCategory.None))
                            {
                                continue;
                            }

                            if (geometryA.IsGeometryIgnored(geometryB) || geometryB.IsGeometryIgnored(geometryA))
                            {
                                continue;
                            }

                            long key = PairID.GetId(geometryA.id, geometryB.id);
                            if (!_filter.ContainsKey(key))
                            {
                                _filter.Add(key, null);

                                //Check if there is intersection
                                bool intersection = AABB.Intersect(ref geometryA.AABB, ref geometryB.AABB);

                                //User can cancel collision
                                if (OnBroadPhaseCollision != null)
                                {
                                    intersection = OnBroadPhaseCollision(geometryA, geometryB);
                                }

                                if (!intersection)
                                {
                                    continue;
                                }

                                _physicsSimulator.ArbiterList.AddArbiterForGeomPair(_physicsSimulator, geometryA, geometryB);
                            }
                        }
                    }
                    list.Clear();
                }
            }
            _filter.Clear();

            //Remove all the empty lists from the hash
            for (int index = 0; index < _keysToRemove.Count; ++index)
            {
                _hash.Remove(_keysToRemove[index]);
            }
        }
示例#25
0
            public void MoveUnderConsiderationToOverlaps()
            {
                for (int i = 0; i < Count; i++)
                {
                    if (this[i].UnderConsideration.Count == 0)
                    {
                        continue;
                    }

                    Geom geometryA = this[i].Geometry;

                    // First transfer those under consideration to overlaps,
                    // for, they have been considered...
                    int startIndex = this[i].Overlaps.Count;
                    this[i].Overlaps.AddRange(this[i].UnderConsideration);
                    this[i].UnderConsideration.Clear();

                    for (int j = startIndex; j < this[i].Overlaps.Count; j++)
                    {
                        Geom geometryB = this[i].Overlaps[j];

                        // It is possible that we may test the same pair of geometries
                        // for both extents (x and y), however, I'm banking on that
                        // one of the extents has probably already been cached and
                        // therefore, won't be checked.

                        if (!geometryA.body.Enabled || !geometryB.body.Enabled)
                        {
                            continue;
                        }

                        if ((geometryA.CollisionGroup == geometryB.CollisionGroup) &&
                            geometryA.CollisionGroup != 0 && geometryB.CollisionGroup != 0)
                        {
                            continue;
                        }

                        if (!geometryA.CollisionEnabled || !geometryB.CollisionEnabled)
                        {
                            continue;
                        }

                        if (geometryA.body.isStatic && geometryB.body.isStatic)
                        {
                            continue;
                        }

                        if (geometryA.body == geometryB.body)
                        {
                            continue;
                        }

                        if (((geometryA.CollisionCategories & geometryB.CollidesWith) == CollisionCategory.None) &
                            ((geometryB.CollisionCategories & geometryA.CollidesWith) == CollisionCategory.None))
                        {
                            continue;
                        }

                        if (geometryA.IsGeometryIgnored(geometryB) || geometryB.IsGeometryIgnored(geometryA))
                        {
                            continue;
                        }

                        //TMP
                        AABB aabb1 = new AABB();
                        AABB aabb2 = new AABB();
                        aabb1.min    = geometryA.AABB.min;
                        aabb1.max    = geometryA.AABB.max;
                        aabb2.min    = geometryB.AABB.min;
                        aabb2.max    = geometryB.AABB.max;
                        aabb1.min.X -= _floatTolerance;
                        aabb1.min.Y -= _floatTolerance;
                        aabb1.max.X += _floatTolerance;
                        aabb1.max.Y += _floatTolerance;
                        aabb2.min.X -= _floatTolerance;
                        aabb2.min.Y -= _floatTolerance;
                        aabb2.max.X += _floatTolerance;
                        aabb2.max.Y += _floatTolerance;

                        if (!AABB.Intersect(ref aabb1, ref aabb2))
                        {
                            continue;
                        }

                        //Call the OnBroadPhaseCollision event first. If the user aborts the collision
                        //it will not create an arbiter
                        if (Owner.OnBroadPhaseCollision != null)
                        {
                            if (Owner.OnBroadPhaseCollision(geometryA, geometryB))
                            {
                                Owner.CollisionPairs.AddPair(geometryA, geometryB);
                            }
                        }
                        else
                        {
                            Owner.CollisionPairs.AddPair(geometryA, geometryB);
                        }
                    }
                }
            }
示例#26
0
        /// <summary>
        /// Returns the contact list from two possibly intersecting Geom's.
        /// This is the stationary version of this function. It doesn't
        /// account for linear or angular motion.
        /// </summary>
        /// <param name="geomA">The first Geom.</param>
        /// <param name="geomB">The second Geom.</param>
        /// <param name="contactList">Set of Contacts between the two Geoms.
        /// NOTE- this will be empty if no contacts are present.</param>
        public void Collide(Geom geomA, Geom geomB, ContactList contactList)
        {
            PolygonCollisionResult result = PolygonCollision(geomA.WorldVertices, geomB.WorldVertices);
            float   distance         = result.MinimumTranslationVector.Length();
            int     contactsDetected = 0;
            Vector2 normal           = Vector2.Normalize(-result.MinimumTranslationVector);
            int     contactsHandled  = 0;

            if (result.Intersect && distance > 0.001f)
            {
                for (int i = 0; i < geomA.WorldVertices.Count; i++)
                {
                    if (contactsDetected <= PhysicsSimulator.MaxContactsToDetect)
                    {
                        if (InsidePolygon(geomB.WorldVertices, geomA.WorldVertices[i]))
                        {
                            Contact c = new Contact(geomA.WorldVertices[i], normal, -distance, new ContactId(geomA.id, i, geomB.id));
                            contactList.Add(c);
                            contactsDetected++;
                            contactsHandled++;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                contactsDetected = 0;

                for (int i = 0; i < geomB.WorldVertices.Count; i++)
                {
                    if (contactsDetected <= PhysicsSimulator.MaxContactsToDetect)
                    {
                        if (InsidePolygon(geomA.WorldVertices, geomB.WorldVertices[i]))
                        {
                            Contact c = new Contact(geomB.WorldVertices[i], normal, -distance, new ContactId(geomB.id, i, geomA.id));
                            contactList.Add(c);
                            contactsDetected++;
                            contactsHandled++;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                // No vertices of either polygon are inside the other, despite their intersection.
                // (Think of an X made of two rectangles of four vertices each.)
                // So select the vertex that is furthest past the edge forming the
                // separating axis as the contact point.
                //   - Andrew Russell
                if (contactsHandled == 0)
                {
                    int  edgeIndex        = result.bestEdgeIndex;
                    Geom separatingEdgeOn = geomA;
                    Geom otherPolygon     = geomB;
                    if (result.bestEdgeIndex >= geomA.WorldVertices.Count)
                    {
                        edgeIndex       -= geomA.WorldVertices.Count;
                        separatingEdgeOn = geomB;
                        otherPolygon     = geomA;
                    }

                    Vector2 edge = separatingEdgeOn.WorldVertices.GetEdge(edgeIndex);
                    Vector2 axis = new Vector2(-edge.Y, edge.X);
                    axis.Normalize();

                    int   mostPenetrationIndex = 0;
                    float mostPenetration      = Vector2.Dot(axis, otherPolygon.WorldVertices[0]);
                    for (int i = 1; i < otherPolygon.WorldVertices.Count; i++)
                    {
                        float penetration = Vector2.Dot(axis, otherPolygon.WorldVertices[i]);
                        if (penetration < mostPenetration)
                        {
                            mostPenetration      = penetration;
                            mostPenetrationIndex = i;
                        }
                    }

                    Contact c = new Contact(otherPolygon.WorldVertices[mostPenetrationIndex], normal, -distance,
                                            new ContactId(otherPolygon.id, mostPenetrationIndex, separatingEdgeOn.id));
                    contactList.Add(c);
                }
            }
        }
示例#27
0
 ///<summary>
 /// Not required by brute force collider
 ///</summary>
 public void Add(Geom geom)
 {
 }
示例#28
0
        private void DoCollision()
        {
            //Iterate all the geoms and check against the next
            for (int i = 0; i < _physicsSimulator.geomList.Count - 1; i++)
            {
                for (int j = i + 1; j < _physicsSimulator.geomList.Count; j++)
                {
                    _geometryA = _physicsSimulator.geomList[i];
                    _geometryB = _physicsSimulator.geomList[j];

                    if (!_geometryA.body.Enabled || !_geometryB.body.Enabled)
                    {
                        continue;
                    }

                    if ((_geometryA.collisionGroup == _geometryB.collisionGroup) &&
                        _geometryA.collisionGroup != 0 && _geometryB.collisionGroup != 0)
                    {
                        continue;
                    }

                    if (!_geometryA.collisionEnabled || !_geometryB.collisionEnabled)
                    {
                        continue;
                    }

                    if (_geometryA.body.isStatic && _geometryB.body.isStatic)
                    {
                        continue;
                    }

                    if (_geometryA.body == _geometryB.body)
                    {
                        continue;
                    }

                    if (((_geometryA.CollisionCategories & _geometryB.CollidesWith) == CollisionCategory.None) &
                        ((_geometryB.CollisionCategories & _geometryA.CollidesWith) == CollisionCategory.None))
                    {
                        continue;
                    }

                    //Assume intersection
                    bool intersection = true;

                    #region INLINE: if (AABB.Intersect(_geometryA.aabb, _geometryB.aabb)) ....

                    //Check if there is no intersection
                    if (_geometryA.AABB.min.X > _geometryB.AABB.max.X || _geometryB.AABB.min.X > _geometryA.AABB.max.X)
                    {
                        intersection = false;
                    }
                    else if (_geometryA.AABB.min.Y > _geometryB.AABB.Max.Y ||
                             _geometryB.AABB.min.Y > _geometryA.AABB.Max.Y)
                    {
                        intersection = false;
                    }

                    #endregion

                    //Call the OnBroadPhaseCollision event first. If the user aborts the collision
                    //it will not create an arbiter

                    if (OnBroadPhaseCollision != null)
                    {
                        intersection = OnBroadPhaseCollision(_geometryA, _geometryB);
                    }

                    //If the user aborted the intersection, continue to the next geometry.
                    if (!intersection)
                    {
                        continue;
                    }

                    //Note: Commented this out and copy-paste into from other colliders
                    //_arbiter = _physicsSimulator.arbiterPool.Fetch();
                    //_arbiter.ConstructArbiter(_geometryA, _geometryB, _physicsSimulator);

                    //if (_physicsSimulator.arbiterList.Contains(_arbiter))
                    //{
                    //    _physicsSimulator.arbiterPool.Insert(_arbiter);
                    //}
                    //else
                    //{
                    //    _physicsSimulator.arbiterList.Add(_arbiter);
                    //}

                    Arbiter arbiter = _physicsSimulator.arbiterPool.Fetch();
                    arbiter.ConstructArbiter(_geometryA, _geometryB, _physicsSimulator);

                    if (!_physicsSimulator.arbiterList.Contains(arbiter))
                    {
                        _physicsSimulator.arbiterList.Add(arbiter);
                    }
                    else
                    {
                        _physicsSimulator.arbiterPool.Insert(arbiter);
                    }
                }
            }
        }
示例#29
0
 public void Add(Geom geom)
 {
     //not
 }