예제 #1
0
        private bool CheckPolygonGrid(IShape A, Vector2 APos, IShape B, Vector2 BPos, out Contact[] contacts)
        {
            PolygonShape polygonShapeA = A as PolygonShape;
            GridShape    gridB         = B as GridShape;

            Rectangle polygonBoundingBox = polygonShapeA.BoundingBox + APos,
                      gridBoundingBox    = gridB.BoundingBox + BPos;

            // test grid bounds
            if (!gridBoundingBox.Intersects(polygonBoundingBox))
            {
                contacts = null;
                return(false);
            }

            Polygon polygonA = new Polygon(polygonShapeA.Shape);

            polygonA.Translate(APos);

            List <Contact> gridContacts = TestGrid(gridB, BPos, polygonBoundingBox,
                                                   (Polygon tilePolygon) => {
                SAT.Test(polygonA, tilePolygon, out Contact? tileContact);
                return(tileContact);
            }
                                                   );

            if (gridContacts.Count > 0)
            {
                contacts = gridContacts.ToArray();
                return(true);
            }

            contacts = null;
            return(false);
        }
예제 #2
0
        private List <Contact> TestGrid(GridShape grid, Vector2 gridPos, Rectangle otherBoundingBox, System.Func <Polygon, Contact?> SAT)
        {
            List <Contact> contacts       = new List <Contact>();
            Polygon        boxTilePolygon = new Polygon(grid.BoxTilePolygon);

            boxTilePolygon.Translate(gridPos);

            (int column, int row)start = grid.ConvertPosition(gridPos, otherBoundingBox.TopLeft - Vector2.One),
            end = grid.ConvertPosition(gridPos, otherBoundingBox.BottomRight + Vector2.One);

            List <Polygon> tilePolygons = new List <Polygon>();

            foreach ((int Column, int Row, GridShape.TileShape Shape)tile in grid.Tiles(start, end))
            {
                tilePolygons.Clear();

                if (tile.Shape != null)
                {
                    if (tile.Shape is GridShape.BoxTileShape boxShape)
                    {
                        tilePolygons.Add(boxShape.CreateCollisionPolygon(grid, gridPos, tile.Column, tile.Row));
                    }
                    else if (tile.Shape is GridShape.PolygonTileShape polygonShape)
                    {
                        tilePolygons.AddRange(polygonShape.CreateCollisionPolygons(grid, gridPos, tile.Column, tile.Row));
                    }
                    else
                    {
                        throw new System.InvalidOperationException($"Unable to find shape '{tile.Shape.GetType().Name}'.");
                    }
                }

                Location cell = new Location(tile.Column, tile.Row);
                foreach (Polygon tilePolygon in tilePolygons)
                {
                    Contact?contact = SAT(tilePolygon);
                    if (contact == null)
                    {
                        continue;
                    }

                    contacts.Add(new Contact(contact.Value.Position, contact.Value.Normal, contact.Value.PenetrationDepth, cell));
                }
            }

            return(contacts);
        }
예제 #3
0
        private bool CheckCircleGrid(IShape A, Vector2 APos, IShape B, Vector2 BPos, out Contact[] contacts)
        {
            CircleShape circleA = A as CircleShape;
            GridShape   gridB   = B as GridShape;

            // test grid bounds
            Vector2 closestPoint = new Rectangle(BPos, gridB.Size).ClosestPoint(APos);
            Vector2 diff         = closestPoint - APos;

            if (Vector2.Dot(diff, diff) > circleA.Radius * circleA.Radius)
            {
                contacts = null;
                return(false);
            }

            List <Contact> gridContacts = TestGrid(gridB, BPos, new Rectangle(APos - circleA.Radius, APos + circleA.Radius),
                                                   (Polygon tilePolygon) => {
                SAT.Test(circleA, APos, tilePolygon, out Contact? tileContact);

                if (tileContact == null)
                {
                    return(null);
                }

                return(new Contact(closestPoint, tileContact.Value.Normal, tileContact.Value.PenetrationDepth, null));
            }
                                                   );

            if (gridContacts.Count > 0)
            {
                contacts = gridContacts.ToArray();
                return(true);
            }

            contacts = null;
            return(false);
        }